Уже писал: я говорю только про архитектуру Wintel/x86, точно так же, как автор исходной статьи, в его утверждении про эту частоту. Вот в ней (Wintel) эта частота используется только для RTC. Что там в настольных часах, напольных весах, в каком-нибудь контроллере на ARM, в Маке, в Амиге, PlayStation, вообще где угодно – за пределами этого. Дальше в этом же комментарии это подчёркнуто было ещё раз.
Схему по вашей ссылке я копать не буду. Чисто теоретически, конечно, интересно, зачем им такая частота – тоже RTC? Но не настолько, чтобы разбираться, как вытащить эту схему во внятное разрешение и раскопать её.
Во-первых, на подавляющем большинстве материнских плат есть до 4 кварцев:
32768Гц – как тут уже сказано.
25МГц – базовый для всех PLL для процессоров, тактирования шин, и так далее.
14.318182МГц – для старых таймеров (8254, ACPI/PIIX).
24.576МГц – для аудио, как минимум. (Смотрел по состоянию около 2015г., тогда он был почти на всех.)
Во-вторых, нет разницы между тем, что вы (только не надо КРИЧАТЬ капсом) обозначили как “резонатор” и “генератор”. В обоих случаях есть сам кварц как относительно прецизионный физический объект, и некоторая схема вокруг него, которая собственно и генерирует колебания в электрическом виде.
И нет критической разницы в обработке обоих. 25МГц напрямую (без PLL) подаётся на южный мост, где основное управление действиями типа включить-выключить всё остальное, и где есть свой небольшой и очень экономный процессор. 32768Гц подаётся на современный аналог MC146818 (RTC clock), но её функциональность давно переработана как спецификации внутрь южного моста, и та частота делится для хода часов, но не для остальной работы (как CMOS-память). Теоретически, можно и без него, дополнительный делитель из других частот это сейчас очень дёшево.
Размер Резонатора не завист от его частоты.
В-третьих, частота кварцевого генератора как раз зависит от его толщины (у большинства), обратной пропорциональностью. У некоторых видов дизайна – от длины. Всё это тривиально гуглится, вы могли легко сами найти.
Таймер 8254 – физически не пропал, угу. Но поскольку блок с ним это меньше чем копейки для современного железа, несколько тысяч вентилей (сравните с современными миллиардами на кэши), никто его и не будет удалять просто так. Особенно с учётом того, что на аналогичной легаси построено достаточно много чего. В ACPI управление типа “выключить питание” делается, по стандарту, записью заданного значения в заданный байтовый порт (причём в большинстве современных материнок эта запись перехватывается в SMM handler, который уже делает реальные действия). Значит, в принципе вообще блок работы с портами 0÷0xff должен быть, и с него нет смысла удалять тот древний таймер;) как и некоторые другие элементы.
(Ранее писал 8259 вместо 8254, глюк биологической памяти. Исправляюсь.)
Ну а легаси попытались снести всё целиком в разработке так называемого X86S. У процессора только 64-битный режим для ядра и 32 или 64 для юзерленда, нет сдохших по факту “ring 1” и “ring 2”, страничная адресация не выключается, и так далее. BIOS, соответственно, совсем другой. Но после пары лет анонсов и даже спецификаций идею почему-то отменили (декабрь 2024). Видимо, тяжесть того легаси на уровне около BIOS оказалась неподъёмной, и это меня удивляет – что именно там такого, что нельзя было перевести на современные подходы?
А вот использование 8254 в современных ОС реально свелось к нулю: Точность и цена доступа к порту старого диапазона (может быть и сотни тактов). Тут даже два аспекта: 1) Тяжёлый путь через шины. 2) Каждое обращение к пространству ввода-вывода на x86, по спеке, это полный барьер памяти. Системный вызов, и ещё сотни тактов на конкретную команду – тысячи тактов наберутся на ровном месте. А теперь сравните с такими вариантами: 1) TSC: просто вызов команды процессора. Да, надо вычесть базовое смещение, разделить на частоту процессора в данный момент и всё такое, но делается без перехода в ядро, если процессу подставлены 2-3 странички кода и данных. 2) HPET, ACPI timer: могут быть замаплены в каждый процесс в R/O режиме, с теми же последствиями, что для TSC.
Ну вот и получается, что как только ядро запустилось и нашло что-то посовременнее, оно этот 8254 просто деактивирует.
Практики – возможно (не все), но при чём тут практики, когда практически каждая тема, описанная у Кнута, кем-то позже переописана с новыми данными, подходами, алгоритмами? Например, по алгоритмам в целом и структурам данных есть Кормен, Скиена, Дасгупта. В темах появились чёрно-красные деревья, LSM tree, skiplists. По плавающей точке есть талмуды вроде Handbook of… от Мюллера с компанией. Огромная новая тема – параллельное и конкурентное программирование, вплоть до хитрых задач типа “византийских генералов”. И это только то, что из памяти за пять минут берётся. То же самое, например, с Ахо-Ульманом и “Книгой дракона”: даже издание 2008 года у них не включило PEG, на котором сейчас очень много чего делается, зато сохраняет множество рассуждений, которые имели смысл в лучшем случае для 1970-х. Прогресс тут идёт, и, отдавая свою дань старому, надо не забывать, насколько всё меняется… (да, комментарий через полгода, ну так получается)
Про поддержку железом как раз упомянуто в статье – вариант использования PTP протокола (не единственный, оно может работать и без такой поддержки, но хуже).
Синхронизация до микросекунд и точнее может быть важна много где, но одно из самых важных это HAC и HPC кластеры – причины разные, но запрос одинаковый. В некоторых кластерах прокладывают отдельную сеть сигналов в стиле PPS от GPS приёмника.
То есть, нам всё равно потребуется от сервера-поставщика точного времени передавать высокочастотный сигнал с его атомного генератора на генераторы остальных компьютеров.
Локальные генераторы никто не трогает, их только измеряют. Давно есть методы софтовой коррекции на основании измеренного расхождения темпа, надёжные и аккуратные. Искать ссылки на внутренние механизмы ядра не буду, но можете почитать ман по adjtimex() с управлением этим всем.
Только подключать его придётся несколько кустарно - одним USB не обойтись, в генератор BIOS‑часов в любом случае придётся вмешиваться.
Да, для PPS применяют, крайне желательно, отдельный порт непосредственно на материнке, обычно это нога компорта или параллельного порта (оба можно настроить на немедленное прерывание).
Вы с прямым углом перепутали;) Если залить в настройки канала в 8259 константу делителя 65536 (это максимум, что он позволял), то собственно прерывание от канала генерировалось с частотой 1193182/65536 ≈ 18.2Гц, а обратное к этому значению было 55 мс. Вот эту цифру 55 вы и вспомнили;)
Подобный режим использовался в MS-DOS по умолчанию. Но: 1) Отдельные программы могли менять этот делитель и тем самым вызывать прерывания на другой частоте, главное, что надо было вызывать основное прерывание только с прежним темпом. 2) Читать счётчик можно было независимо от прерываний и получать время с точностью чуть лучше микросекунды.
Ну а в современной ОС такой тик это слишком долго для нормального шедулинга, делают другие значения - 100Гц, 1000Гц и так далее… и считывание таймера делают современными подходами и максимально его удешевляют.
Я, было очевидно, ограничился контекстом компьютеров, причём достаточно серьёзного уровня (минимум лаптопа), согласно тому, о чём статья в целом. Разнообразные энергонезависимые (на батарейке, имеется в виду?) и нет часы – совсем другой домен. А в RTC в Wintel/x86 с этой частотой ещё сложнее: читать по каждому такому чиху или просить прерывания с такой частотой – сильно дорого. BSD системы использовали 128Гц как профилирующее таймерное прерывание, и это был максимум, что можно было себе позволить при создании этого механизма без явного ущерба для самих измерений. Сейчас, наверно, 1024 и даже 2048 вытянет любое современное железо, но 32768 – ещё нет.
Даже на IBM PC XT системные часы работали от генератора на 1.193182 MHz
Кварц там 14.318182МГц, и его можно и сейчас увидеть на большинстве материнок. Изначально он вообще из телевизора, где задавал частоту для цветовой поднесущей NTSC.
Та частота, что вы написали, и которая подавалась на 8259 – уже результат деления на 12.
1/3 от той частоты подавалась на процессор – потому 8088, 8086 вначале работали на странной 4.77МГц (округлённо). 1/4 – 3.579545МГц – на таймер ACPI/PIIX. Ну и неделённой, на половине или чуть больше материнок, на HPET.
Для большинства компьютерных часов стандартом выбрана частота 32768 Гц, потому что она является степенью двойки и упрощает подсчёт с точностью до одной секунды.
Это точно неправда. 32768Гц используется в одном-единственном месте – RTC часы архитектуры Wintel/x86. И вообще в этом случае не могло быть локального времени с точностью выше 32 мс, автор статьи об этом вообще задумался? Кажется, нет :(
Реально тут представлен следующий зоопарк:
1. X86 имеет почти всегда кварц 14_318_182Гц, из которого порождаются другие частоты: без деления может подаваться в HPET, с делением на 4 в ACPI/PIIX таймер, с делением на 12 в 8259.
2. Там же есть уже всегда кварц 25МГц, на котором напрямую работает Intel ME, или его предшественник из южного моста, и из которого через PLL clock строятся другие частоты (например, для процессора на 1667Мгц те 25МГц умножаются на 200 и затем делятся на 3). В некоторых материнках HPET работает на 25МГц.
3. TSC в процессоре считает с частотой процессора. Она может меняться при всяких TurboBoost, но с учётом этого она самая точная (например, если 5ГГц, то точность до 200пс).
4. Упомянутый RTC, который единственный работает, когда всё обесточено – и поэтому при буте после этого часы могут уйти до 32мс.
На других архитектурах свои особенности. ARM, например, требует, чтобы таймеры считались в частоте 1GHz (начиная с 8.6), но шаг зависит от изготовителя процессора.
В целом статья достаточно неплоха, как обзор, но вот эта грубейшая плюха как-то смущает.
В CSS пример не расчётов в десятичке (тут ничто им не мешает перевести в 0.7 уже в двоичной и так дальше и считать, все основные движки так и делают), а импорта данных из десятичной от человека. Точно так же в JSON почему-то внешний формат – десятичный (в редких случаях катастрофически дорогая конверсия), тем не менее в основном им обмениваются компьютеры. Другие ваши примеры в ту же сторону. Если бы оптимизировали для компьютеров, пусть даже в тексте, было бы 0x1.921fb54442d18p+1 вместо 3.141592653589793.
По умолчанию – угу, а если попросить сокет с тем самым AF_ALG, должна произойти автоподгрузка, рута на это не требуется. Потому и предложенная затычка до лечения кода – запретить загрузку.
Я добавлю, что троичная логика SQL заведомо дефектна, потому что чуть менее чем все чуть менее чем всегда смешивают NULL как “неизвестно” и NULL как “точно нет значения”, и это даже в базе (логика операций с TRUE-FALSE-NULL соответствует “неизвестно”, а подстановка NULL при JOINʼах – “точно нет значения”). Исправления этого пока не придумали, кроме как расширять домен на спец. значения, уходя по максимуму от NULL в собственных данных. Поэтому логика SQL тут скорее антипример.
В статье ссылаются на Фомина, а остальной мир ссылается с той же теоремой на Клода Шеннона. “Середина XX века” это слишком абстрактно. Кто всё-таки был первым?
Действительно, если троичный триггер реально будет состоять из двух двоичных (на плюс и на минус), как получается в реальной логике, то всё преимущество пропадает. Точно так же как если пытаться передавать десятичные цифры как один триггер на 10 состояний, или как 4 на 2 (пусть и с неиспользуемыми состояниями), разница не в пользу того, что на 10 состояний. Поэтому мир и остановился на двоичной логике: она проще, надёжнее и таки дешевле.
Но интересная попытка, безусловно, зачтена: Брусенцов вписал своё имя в историю.
Если сдвиг сделан на бочке (barrel shifter), то подать на неё только младшие 5-6 бит это тривиально, а выяснять, ещё и установлены ли более старшие биты -- дополнительные схемы, на которых таки сэкономили.
К тому же это не единственные проблемы сдвига. Какие флаги важнее в результате сдвига? На x86 в CF оказывается последний выдвинутый за пределы целевого значения бит. При сдвиге на более чем 1 бит смысл этого есть чуть более чем для никого. А вот ещё в S/360 флаги условий ставились в соответствии с логикой -- если для знакового или беззнакового, в зависимости от варианта команды, сдвиг, понятый как умножение на степень 2, даёт переполнение (а сдвиг вправо -- ненулевой остаток). Вот это сейчас важнее, но менять уже никто не будет.
И у BSF/BSR, кроме особого поведения на входе 0, ещё и странная логика, что по входу 0 ставится ZF, который должен ставиться по результату 0, а не входному значению.
Всё это последствия многолетних решений в условиях, когда не думают далее чем на полшага вперёд.
Уже писал: я говорю только про архитектуру Wintel/x86, точно так же, как автор исходной статьи, в его утверждении про эту частоту. Вот в ней (Wintel) эта частота используется только для RTC. Что там в настольных часах, напольных весах, в каком-нибудь контроллере на ARM, в Маке, в Амиге, PlayStation, вообще где угодно – за пределами этого. Дальше в этом же комментарии это подчёркнуто было ещё раз.
Схему по вашей ссылке я копать не буду. Чисто теоретически, конечно, интересно, зачем им такая частота – тоже RTC? Но не настолько, чтобы разбираться, как вытащить эту схему во внятное разрешение и раскопать её.
Во-первых, на подавляющем большинстве материнских плат есть до 4 кварцев:
32768Гц – как тут уже сказано.
25МГц – базовый для всех PLL для процессоров, тактирования шин, и так далее.
14.318182МГц – для старых таймеров (8254, ACPI/PIIX).
24.576МГц – для аудио, как минимум. (Смотрел по состоянию около 2015г., тогда он был почти на всех.)
Во-вторых, нет разницы между тем, что вы (только не надо КРИЧАТЬ капсом) обозначили как “резонатор” и “генератор”. В обоих случаях есть сам кварц как относительно прецизионный физический объект, и некоторая схема вокруг него, которая собственно и генерирует колебания в электрическом виде.
И нет критической разницы в обработке обоих. 25МГц напрямую (без PLL) подаётся на южный мост, где основное управление действиями типа включить-выключить всё остальное, и где есть свой небольшой и очень экономный процессор. 32768Гц подаётся на современный аналог MC146818 (RTC clock), но её функциональность давно переработана как спецификации внутрь южного моста, и та частота делится для хода часов, но не для остальной работы (как CMOS-память). Теоретически, можно и без него, дополнительный делитель из других частот это сейчас очень дёшево.
В-третьих, частота кварцевого генератора как раз зависит от его толщины (у большинства), обратной пропорциональностью. У некоторых видов дизайна – от длины. Всё это тривиально гуглится, вы могли легко сами найти.
Извините за некоторое занудство.
Таймер 8254 – физически не пропал, угу. Но поскольку блок с ним это меньше чем копейки для современного железа, несколько тысяч вентилей (сравните с современными миллиардами на кэши), никто его и не будет удалять просто так. Особенно с учётом того, что на аналогичной легаси построено достаточно много чего. В ACPI управление типа “выключить питание” делается, по стандарту, записью заданного значения в заданный байтовый порт (причём в большинстве современных материнок эта запись перехватывается в SMM handler, который уже делает реальные действия). Значит, в принципе вообще блок работы с портами 0÷0xff должен быть, и с него нет смысла удалять тот древний таймер;) как и некоторые другие элементы.
(Ранее писал 8259 вместо 8254, глюк биологической памяти. Исправляюсь.)
Ну а легаси попытались снести всё целиком в разработке так называемого X86S. У процессора только 64-битный режим для ядра и 32 или 64 для юзерленда, нет сдохших по факту “ring 1” и “ring 2”, страничная адресация не выключается, и так далее. BIOS, соответственно, совсем другой. Но после пары лет анонсов и даже спецификаций идею почему-то отменили (декабрь 2024). Видимо, тяжесть того легаси на уровне около BIOS оказалась неподъёмной, и это меня удивляет – что именно там такого, что нельзя было перевести на современные подходы?
А вот использование 8254 в современных ОС реально свелось к нулю: Точность и цена доступа к порту старого диапазона (может быть и сотни тактов). Тут даже два аспекта: 1) Тяжёлый путь через шины. 2) Каждое обращение к пространству ввода-вывода на x86, по спеке, это полный барьер памяти. Системный вызов, и ещё сотни тактов на конкретную команду – тысячи тактов наберутся на ровном месте. А теперь сравните с такими вариантами: 1) TSC: просто вызов команды процессора. Да, надо вычесть базовое смещение, разделить на частоту процессора в данный момент и всё такое, но делается без перехода в ядро, если процессу подставлены 2-3 странички кода и данных. 2) HPET, ACPI timer: могут быть замаплены в каждый процесс в R/O режиме, с теми же последствиями, что для TSC.
Ну вот и получается, что как только ядро запустилось и нашло что-то посовременнее, оно этот 8254 просто деактивирует.
text.replace(“8259”, “8254”), память заглючила.
text.replace(“8259”, “8254”), память заглючила.
Практики – возможно (не все), но при чём тут практики, когда практически каждая тема, описанная у Кнута, кем-то позже переописана с новыми данными, подходами, алгоритмами? Например, по алгоритмам в целом и структурам данных есть Кормен, Скиена, Дасгупта. В темах появились чёрно-красные деревья, LSM tree, skiplists. По плавающей точке есть талмуды вроде Handbook of… от Мюллера с компанией. Огромная новая тема – параллельное и конкурентное программирование, вплоть до хитрых задач типа “византийских генералов”. И это только то, что из памяти за пять минут берётся. То же самое, например, с Ахо-Ульманом и “Книгой дракона”: даже издание 2008 года у них не включило PEG, на котором сейчас очень много чего делается, зато сохраняет множество рассуждений, которые имели смысл в лучшем случае для 1970-х. Прогресс тут идёт, и, отдавая свою дань старому, надо не забывать, насколько всё меняется… (да, комментарий через полгода, ну так получается)
Про поддержку железом как раз упомянуто в статье – вариант использования PTP протокола (не единственный, оно может работать и без такой поддержки, но хуже).
Синхронизация до микросекунд и точнее может быть важна много где, но одно из самых важных это HAC и HPC кластеры – причины разные, но запрос одинаковый. В некоторых кластерах прокладывают отдельную сеть сигналов в стиле PPS от GPS приёмника.
Локальные генераторы никто не трогает, их только измеряют. Давно есть методы софтовой коррекции на основании измеренного расхождения темпа, надёжные и аккуратные. Искать ссылки на внутренние механизмы ядра не буду, но можете почитать ман по adjtimex() с управлением этим всем.
Да, для PPS применяют, крайне желательно, отдельный порт непосредственно на материнке, обычно это нога компорта или параллельного порта (оба можно настроить на немедленное прерывание).
Вы с прямым углом перепутали;) Если залить в настройки канала в 8259 константу делителя 65536 (это максимум, что он позволял), то собственно прерывание от канала генерировалось с частотой 1193182/65536 ≈ 18.2Гц, а обратное к этому значению было 55 мс. Вот эту цифру 55 вы и вспомнили;)
Подобный режим использовался в MS-DOS по умолчанию. Но: 1) Отдельные программы могли менять этот делитель и тем самым вызывать прерывания на другой частоте, главное, что надо было вызывать основное прерывание только с прежним темпом. 2) Читать счётчик можно было независимо от прерываний и получать время с точностью чуть лучше микросекунды.
Ну а в современной ОС такой тик это слишком долго для нормального шедулинга, делают другие значения - 100Гц, 1000Гц и так далее… и считывание таймера делают современными подходами и максимально его удешевляют.
Я, было очевидно, ограничился контекстом компьютеров, причём достаточно серьёзного уровня (минимум лаптопа), согласно тому, о чём статья в целом. Разнообразные энергонезависимые (на батарейке, имеется в виду?) и нет часы – совсем другой домен. А в RTC в Wintel/x86 с этой частотой ещё сложнее: читать по каждому такому чиху или просить прерывания с такой частотой – сильно дорого. BSD системы использовали 128Гц как профилирующее таймерное прерывание, и это был максимум, что можно было себе позволить при создании этого механизма без явного ущерба для самих измерений. Сейчас, наверно, 1024 и даже 2048 вытянет любое современное железо, но 32768 – ещё нет.
Кварц там 14.318182МГц, и его можно и сейчас увидеть на большинстве материнок. Изначально он вообще из телевизора, где задавал частоту для цветовой поднесущей NTSC.
Та частота, что вы написали, и которая подавалась на 8259 – уже результат деления на 12.
1/3 от той частоты подавалась на процессор – потому 8088, 8086 вначале работали на странной 4.77МГц (округлённо). 1/4 – 3.579545МГц – на таймер ACPI/PIIX. Ну и неделённой, на половине или чуть больше материнок, на HPET.
Это точно неправда. 32768Гц используется в одном-единственном месте – RTC часы архитектуры Wintel/x86. И вообще в этом случае не могло быть локального времени с точностью выше 32 мс, автор статьи об этом вообще задумался? Кажется, нет :(
Реально тут представлен следующий зоопарк:
1. X86 имеет почти всегда кварц 14_318_182Гц, из которого порождаются другие частоты: без деления может подаваться в HPET, с делением на 4 в ACPI/PIIX таймер, с делением на 12 в 8259.
2. Там же есть уже всегда кварц 25МГц, на котором напрямую работает Intel ME, или его предшественник из южного моста, и из которого через PLL clock строятся другие частоты (например, для процессора на 1667Мгц те 25МГц умножаются на 200 и затем делятся на 3). В некоторых материнках HPET работает на 25МГц.
3. TSC в процессоре считает с частотой процессора. Она может меняться при всяких TurboBoost, но с учётом этого она самая точная (например, если 5ГГц, то точность до 200пс).
4. Упомянутый RTC, который единственный работает, когда всё обесточено – и поэтому при буте после этого часы могут уйти до 32мс.
На других архитектурах свои особенности. ARM, например, требует, чтобы таймеры считались в частоте 1GHz (начиная с 8.6), но шаг зависит от изготовителя процессора.
В целом статья достаточно неплоха, как обзор, но вот эта грубейшая плюха как-то смущает.
В CSS пример не расчётов в десятичке (тут ничто им не мешает перевести в 0.7 уже в двоичной и так дальше и считать, все основные движки так и делают), а импорта данных из десятичной от человека. Точно так же в JSON почему-то внешний формат – десятичный (в редких случаях катастрофически дорогая конверсия), тем не менее в основном им обмениваются компьютеры. Другие ваши примеры в ту же сторону. Если бы оптимизировали для компьютеров, пусть даже в тексте, было бы 0x1.921fb54442d18p+1 вместо 3.141592653589793.
По умолчанию – угу, а если попросить сокет с тем самым AF_ALG, должна произойти автоподгрузка, рута на это не требуется. Потому и предложенная затычка до лечения кода – запретить загрузку.
Я добавлю, что троичная логика SQL заведомо дефектна, потому что чуть менее чем все чуть менее чем всегда смешивают NULL как “неизвестно” и NULL как “точно нет значения”, и это даже в базе (логика операций с TRUE-FALSE-NULL соответствует “неизвестно”, а подстановка NULL при JOINʼах – “точно нет значения”). Исправления этого пока не придумали, кроме как расширять домен на спец. значения, уходя по максимуму от NULL в собственных данных. Поэтому логика SQL тут скорее антипример.
И они ничем не выделяются на фоне ситуаций, которые надо представлять четверичной логикой, пятеричной, и так далее.
С тем дизайном, как делали “Сетунь”, двоичная была бы не дороже. Возможно, и дешевле. Ну очень простая была машинка.
Есть он в 6.17 HWE. Или вы что-то не то называете HWE. Или смотрели не по всем дистрибутивам (одного достаточно, чтобы считать, что есть).
В статье ссылаются на Фомина, а остальной мир ссылается с той же теоремой на Клода Шеннона. “Середина XX века” это слишком абстрактно. Кто всё-таки был первым?
Действительно, если троичный триггер реально будет состоять из двух двоичных (на плюс и на минус), как получается в реальной логике, то всё преимущество пропадает. Точно так же как если пытаться передавать десятичные цифры как один триггер на 10 состояний, или как 4 на 2 (пусть и с неиспользуемыми состояниями), разница не в пользу того, что на 10 состояний. Поэтому мир и остановился на двоичной логике: она проще, надёжнее и таки дешевле.
Но интересная попытка, безусловно, зачтена: Брусенцов вписал своё имя в историю.
Но во времена C89 не было такого агрессивного выкачивания очередных 2% производительности из каждого пункта UB.
Если сдвиг сделан на бочке (barrel shifter), то подать на неё только младшие 5-6 бит это тривиально, а выяснять, ещё и установлены ли более старшие биты -- дополнительные схемы, на которых таки сэкономили.
К тому же это не единственные проблемы сдвига. Какие флаги важнее в результате сдвига? На x86 в CF оказывается последний выдвинутый за пределы целевого значения бит. При сдвиге на более чем 1 бит смысл этого есть чуть более чем для никого. А вот ещё в S/360 флаги условий ставились в соответствии с логикой -- если для знакового или беззнакового, в зависимости от варианта команды, сдвиг, понятый как умножение на степень 2, даёт переполнение (а сдвиг вправо -- ненулевой остаток). Вот это сейчас важнее, но менять уже никто не будет.
И у BSF/BSR, кроме особого поведения на входе 0, ещё и странная логика, что по входу 0 ставится ZF, который должен ставиться по результату 0, а не входному значению.
Всё это последствия многолетних решений в условиях, когда не думают далее чем на полшага вперёд.