Чтобы получить точный ответ, вы должны спросить Стивен Морс, дизайнера 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
IDIV
, в ней нет никакой информации, которая пролила бы свет на решение о флаге и исключении (например, нехватка места в ПЗУ микрокода). - person njuffa   schedule 10.04.2021high_half < divisor
- это точное условие для того, чтобы частное подходило для беззнакового деления, включая исключение деления на ноль. (Знаковое деление также имеет угловой случай переполненияINT_MIN / -1
, а проверка старшей половины может потребоваться для абсолютных значений.) - person Peter Cordes   schedule 10.04.2021INT_MIN / - 1
, который действительно молча обернут вINT_MIN
. - person Nate Eldredge   schedule 10.04.2021high_half < divisor
поймает и его. беззнаковыйx < 0
для любого x. - person Peter Cordes   schedule 10.04.2021imul 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