{–}

{ Generate Code to Multiply Primary by Stack }

function PopMul(T1, T2: char): char;

var T: char;

begin

Pop(T1);

T := SameType(T1, T2);

Convert(T, 'W', 'D7');

Convert(T, 'W', 'D0');

if T = 'L' then

GenLongMult

else

GenMult;

if T = 'B' then

PopMul := 'W'

else

PopMul:= 'L';

end;

{–}

Как вы можете видеть, подпрограмма начинается совсем как PopAdd. Два аргумента приводятся к тому же самому типу. Два вызова Convert заботятся о случаях, когда оба операнда – байты. Сами данные переводятся до слова, но подпрограмма помнит тип чтобы назначать корректный тип результату. В заключение мы вызываем одну из двух подпрограмм генерации кода и затем назначаем тип результата. Не слишком сложно, действительно.

Я полагаю, что сейчас вы уже тестируете программу. Попробуйте все комбинации размеров операндов.

ДЕЛЕНИЕ

Случай с делением совсем не так симметричен. У меня также есть для вас некоторые плохие новости:

Все современные 16-разрядные процессоры поддерживают целочисленное деление. Спецификации изготовителей описывают эту операцию как 32 x 16 бит деление, означающее, что вы можете разделить 32 -разрядное делимое на 16-разрядный делитель. Вот плохая новость:

Они вам лгут!!!

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

Проблема состоит в том, что эта команда в действительности требует, чтобы получаемое частное вписывалось в 16-разрядный результат. Этого не случится, если делитель достаточно большой. Когда любое число делится на единицу, частное будет конечно тем же самым, что и делимое.

С начала времен (ну во всяком случае компьютерных) архитекторы ЦПУ предусматривали этот маленький подводный камень в схеме деления. Это обеспечивает некоторую симметрию, так как это своего рода инверсия способа каким работает умножение. Но так как единица – это совершенно допустимое (и довольно частое) число для использования в качестве делителя, делению, реализованному аппаратно, требуется некоторая помощь от программистов.

Подразумевает следующее:

Тип частного всегда должен быть того же самого типа, что и делимое. Он независим от делителя.

Несмотря на то, что ЦПУ поддерживает деление длинного слова, аппаратно предоставленной инструкции можно доверить только делимые байт и слово. Для делимых типа длинное слово нам необходима другая библиотечная подпрограмма, которая может возвращать длинный результат.

Это похоже на работу для другой таблицы, для суммирования требуемых действий:

T1

T2 B W L

B Преобразовать D0 в W

Преобразовать D7 в L

DIVS

Result = B Преобразовать D0 в W

Преобразовать D7 в L

DIVS

Result = W Преобразовать D0 в L

JSR DIV32

Result = L

W Преобразовать D7 в L

DIVS

Result = B Преобразовать D7 в L

DIVS

Result = W Преобразовать D0 в L

JSR DIV32

Result = L

L Преобразовать D7 в L

JSR DIV32

Result = B Преобразовать D7 в L

JSR DIV32

Result = W JSR DIV32

Result = L

(Вы можете задаться вопросом, почему необходимо выполнять 32-разрядное деление, когда делимое, скажем, всего лишь байт. Так как число битов в результате может быть только столько, сколько и в делимом, зачем беспокоиться? Причина в том, что если делитель – длинное слово и в нем есть какие-либо установленные старшие разряды, результат деления должен быть равен нулю. Мы не смогли бы получить его, если мы используем только младшее слово делителя)

Следующий код предоставляет корректную функцию для PopDiv:

{–}

{ Generate Code to Divide Stack by the Primary }

function PopDiv(T1, T2: char): char;

begin

Pop(T1);

Convert(T1, 'L', 'D7');

if (T1 = 'L') or (T2 = 'L') then begin

Convert(T2, 'L', 'D0');

GenLongDiv;

PopDiv := 'L';

end

else begin

Convert(T2, 'W', 'D0');

GenDiv;

PopDiv := T1;

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату