Почему не была реализована инструкция DIV для установки CF вместо вызова исключений

Я знаю, что нужно быть очень осторожным при делении в сборке, т.е. делать это:

          mov ah, 10h
          mov al, 00h ; dividend = 1000h
          mov bl, 10h ; divisor = 10h
          div bl      ; Integer overflow exception, /result 100h cannot fit into al

Я написал некоторую логику, которая, вероятно, не является надежной, чтобы создать более дружелюбную среду для разделения:

          mov ah, 10h
          mov al, 00h
          mov bl, 10h 
TryDivide:
          cmp bl,ah
          jna CatchClause
          div bl
          clc
          jmp TryEnd
CatchClause:
          stc
TryEnd:
     

Есть ли у кого-нибудь ключ к техническим причинам, по которым что-то подобное не было реализовано, и у нас есть исключения вместо установленных флагов / усеченных регистров?


person tinmanjk    schedule 09.04.2021    source источник
comment
Этот вопрос, вероятно, лучше подходит для Retrocomputing Stackexchange. Здесь это кажется не по теме, поскольку оно ищет обоснование решения по проектированию оборудования.   -  person njuffa    schedule 10.04.2021
comment
Кто-то недавно успешно дизассемблировал микрокод 8086, но пока их сообщение в блоге с описанием этого усилия упоминает инструкцию IDIV, в ней нет никакой информации, которая пролила бы свет на решение о флаге и исключении (например, нехватка места в ПЗУ микрокода).   -  person njuffa    schedule 10.04.2021
comment
Я думаю, что эта проверка на самом деле защищена от ошибок. high_half < divisor - это точное условие для того, чтобы частное подходило для беззнакового деления, включая исключение деления на ноль. (Знаковое деление также имеет угловой случай переполнения INT_MIN / -1, а проверка старшей половины может потребоваться для абсолютных значений.)   -  person Peter Cordes    schedule 10.04.2021
comment
Обратите внимание, что другие ISA сделали другой выбор; например, ARM усекает вместо того, чтобы вызывать исключения. (И я предполагаю устанавливает флаги). Почему целочисленное деление на -1 (отрицательное) приводит к FPE?   -  person Peter Cordes    schedule 10.04.2021
comment
так что деление на ноль в каком-то смысле частный случай?   -  person tinmanjk    schedule 10.04.2021
comment
@PeterCordes: подразделение на ARM (как 32, так и 64) никогда не устанавливает флаги. Там нет сужающегося разделения, поэтому единственный способ, которым он может переполниться, - это подписанный INT_MIN / - 1, который действительно молча обернут в INT_MIN.   -  person Nate Eldredge    schedule 10.04.2021
comment
@tinmanjk: Да, деление на ноль является частным случаем этого особого случая: нет математически правильного результата для усечения, если вы хотите усеченное деление, и любой итеративный алгоритм может застрять в бесконечном цикле (поэтому аппаратное обеспечение не может просто сделайте это и отбросьте или обнаружите переполнение в частном, чтобы поймать плохие операнды). Но та же самая проверка high_half < divisor поймает и его. беззнаковый x < 0 для любого x.   -  person Peter Cordes    schedule 10.04.2021
comment
Исключение имеет определенный смысл для деления на ноль: оно всегда ошибочно, поэтому таким образом вы его обнаружите, не тратя драгоценную память на дополнительную проверку кода. Тот факт, что переполнение делает то же самое, вполне может быть сделано для упрощения реализации.   -  person Nate Eldredge    schedule 10.04.2021
comment
Это похоже на то, должен ли я вернуть код ошибки или вызвать дебаты об исключении в языках более высокого уровня.   -  person 1201ProgramAlarm    schedule 10.04.2021
comment
@PeterCordes: ну, моя математика не такая свежая, но есть ли набор стандартов, когда усечение допустимо? IMUL обрежет все. Поэтому я думаю, что дело DIV должно быть не столько в правильности, сколько в чем-то другом.   -  person tinmanjk    schedule 10.04.2021
comment
@tinmanjk: 8086 не включает imul reg, reg, только расширение одного операнда mul/imul, которые не усекаются, поэтому каждая вторая инструкция 8086 дает полный результат. (в DX:AX для mul/imul или в CF:reg для add/sub). За исключением shift-by-cl, который может сдвигать несколько битов, но это скорее логическая инструкция, чем арифметическая. DIV/IDIV могут быть единственными математическими инструкциями, где может быть более широкий результат и некуда его поместить. Тем не менее, они могли просто решить урезать и установить ФЛАГИ, особенно для ненулевых делителей.   -  person Peter Cordes    schedule 10.04.2021
comment
@PeterCordes, поэтому в то время, когда были добавлены MUL и DIV, MUL гарантировалось, что он не переполнится, и вопрос для DIV заключался в том, чтобы обрезать или вызвать исключение. Когда было включено больше операндов MUL/IMUL, было решено усечь их и не создавать исключения для них.   -  person tinmanjk    schedule 10.04.2021


Ответы (1)


Чтобы получить точный ответ, вы должны спросить Стивен Морс, дизайнера 8086 набор инструкций.

Другие инженеры Intel работали над фактической реализацией, но #comment11346_5128">очевидно, ISA сначала был разработан на бумаге, почти полностью одним человеком. Он также считается главным архитектором 8086. PC World брал у него интервью в 2008 году. к 30-летию 8086 года и, что более важно, он написал книгу The 8086/8088 Primer (1982). Я его не читал, но, видимо, он обсуждает некоторые дизайнерские решения, а также то, как его запрограммировать. Если вам повезет, возможно, он написал что-то о выборе ловушки div/idiv.


Нет причин, по которым это должно было быть именно так; установка CF и/или OF и усечение были бы допустимыми конструкциями. Но вам все равно нужно выбрать какое-то значение, чтобы поместить его в выходные регистры частного/остатка в случае деления на ноль1. (Я думаю, что для ISA с разделением HW довольно часто встречается исключение деления по ошибке, по крайней мере, для деления на ноль, но На каких платформах целочисленное деление на ноль вызывает исключение с плавающей запятой? к сожалению, упоминается только x86 как ISA с ловушками. Если деление делает ловушку, и ОС POSIX вообще доставляет сигнал, это должно быть SIGFPE для арифметического исключения.)

Обратите внимание, что другие ISA делают другой выбор. Например, подразделение ARM никогда не дает сбоев и не устанавливает флаги. (Хотя он не обеспечивает дивиденд двойной ширины, поэтому только in-fpe">переполнение INT_MIN / -1 со знаком и случаи деления на 0 являются особыми для него.)

IDK, если создание аппаратного модуля деления (или микрокода), который мог бы получить правильно усеченное частное для случаев переполнения (когда точное частное шире 16-бит), будет сложнее, чем простое обнаружение переполнения и аварийное отключение. Если так, то это будет довольно уважительной причиной.

(Оставить мусор в выходных регистрах и установить ФЛАГИ было бы возможно, но не очень хорошо; каждое деление должно было бы впоследствии проверять результат, если оно хочет избежать возможности использования мусора.)

Примечание 1: деление на 0 в некотором смысле является частным случаем этого: high_half < divisor ложно для divisor=0 для любого делимого. Но нет четко определенного математического результата, который можно было бы обрезать. Разделение IEEE FP разрешает это, рассматривая как предел, когда делитель приближается к 0, то есть к +- бесконечности. Но целое число 0 следует считать именно 0, а не каким-то крошечным числом, и в любом случае нет внутриполосного значения NaN или Inf, только конечное 0xFFFF...


Никакие другие математические инструкции 8086 не нужно усекать, если вы считаете ФЛАГИ

Обратите внимание, что 8086 только включает формы с одним операндом mul и imul, которые умножают расширение: DX:AX = AX * src. (CF и OF устанавливаются, если старшая половина не равна нулю (для mul) или если старшая половина не является расширением знака младшей половины (для imul)). Только более поздние процессоры представили усеченные формы, такие как imul r, r/m, imm (186) и imul r, r/m (386), которые не не тратьте время на запись старшей половины в любом месте, хотя все еще устанавливайте ФЛАГИ, чтобы вы могли обнаружить подписанную упаковку, если хотите. (Большинство пользователей этого не делают, поэтому более поздние ЦП предоставляли только imul, версии mul, которые были бы такими же, за исключением FLAGS.)

add/sub может переносить/заимствовать, но полный результат добавления доступен как CF : reg с дополнительным битом во флаге переноса.

Если вы рассматриваете sar / shr / shl reg, cl как побитовую логическую операцию, а не математическую, то она не считается, даже если она может сдвигать несколько битов, не оставляя их нигде. (Последний бит остается в CF, поэтому сдвиг на 1 можно отменить с помощью переноса с чередованием.)

Это оставляет DIV/IDIV, поскольку я думаю, что это единственные арифметические инструкции, где может быть более широкий результат и некуда его поместить. Это могло быть частью мотивации для выбора есть их вина.


high_half < divisor является защитой от беззнакового деления

Это точное условие для подгонки частного по размеру операнда. 1:0 (например, 0x0100 для 8-битного размера операнда) — это наименьшее частное, которое не подходит, поэтому 0x0100 * divisor — это наименьшее делимое, которое дает частное, которое не помещается в 8 бит.

Это делимое равно divisor:0, когда оно разделено на половины hi:lo той же ширины, что и делимое.

Любое число, меньшее, чем это, должно было бы заимствоваться из старшей половины, оставляя его строго меньшим, чем divisor.

(Знаковое деление также имеет угловой случай переполнения INT_MIN / -1, и проверка верхней половины, возможно, должна быть на абсолютных значениях.)

person Peter Cordes    schedule 10.04.2021
comment
Как насчет IDIV: 9100h/92h --› исключение, 9200h/91h --› тоже исключение? - person tinmanjk; 10.04.2021
comment
@tinmanjk: я не делал никаких определенных заявлений о переполнении idiv; моя математика только доказывает что-либо о div. По-видимому, это не так просто, как абсолютное значение. - person Peter Cordes; 10.04.2021
comment
да, я думаю, что нашел аналогичный вопрос link, который на самом деле не является окончательным тоже, но хорошая отправная точка - person tinmanjk; 11.04.2021