Оглавление
§ Базовые функции
Итак, поскольку получилось реализовать не только декодер, но даже (частично) довольно важную группу инструкции, то пришло время поговорить и о них, так как именно модуль АЛУ (арифметическо-логического устройство), а также модуль сдвигов являются очень важными, и даже центральными компонентами всей этой сложной системы.
Всего существует 8 базовых функции АЛУ.
| # | КОД | ОПИСАНИЕ |
| 0 | ADD | Сложить A + B |
| 1 | OR | Логическая "ИЛИ" |
| 2 | ADC | Сложить A + B + CF (флаг переноса) |
| 3 | SBB | Вычесть A – B – CF |
| 4 | AND | Логическая "И" |
| 5 | SUB | Вычесть A – B |
| 6 | XOR | Логическое "Исключающее ИЛИ" |
| 7 | CMP | Вычесть A – B, писать только флаги |
|---|
Эти функции сами по себе реализуются достаточно просто:
- Вычисляется значение функции по отдельности
- Выбирается результат работы через мультиплексор
- Вычисляются флаги в соответствии с ответом и входящими операндами
Есть много разных способов сделать АЛУ, и это – лишь один из способов, который легко реализуется в верилоге, и поскольку матрицы ПЛИС как раз очень хорошо "заточены" под мультиплексирование, то такие схемы там достаточно распространены, если не сказать, что повсеместно.
§ Вычисление результата
wire [16:0] ar =
alu == ADD ? op1 + op2 :
alu == ADC ? op1 + op2 + flags[CF] :
alu == SBB ? op1 - op2 - flags[CF] :
alu == AND ? op1 & op2 :
alu == XOR ? op1 ^ op2 :
alu == OR ? op1 | op2 : op1 - op2;
Создадим мультиплексор, но операции CMP и SUB объединяются в одну из-за того что они выполняются совершенно одинаково. Разница заключается лишь только в том, что CMP записывает результат только во флаги, а SUB – обратно в регистр или память, в том числе и во флаги тоже.
Интересная особенность в том, что вычисления всегда производятся с 16-битными операндами. В этом нет ошибки. Главное только в том, чтобы при работе с 8-битными значениями в старших 8 битах операндов op1 и op2 были именно строгие нули (0), иначе тогда ничего не будет работать корректно.
В зависимости от размера операндов выбирается бит, который будет находится в самой вершине (номер старшего бита):
wire [3:0] top = size ? 15 : 7;
Номер бита будет либо 7, если работаем с 8-битными значениями (от 0 до 7), либо же 15 с 16-битными операндами (от 0 до 15).
wire isa = alu == ADD || alu == ADC;
wire isl = alu != AND && alu != OR && alu != XOR;
В данных двух условиях происходит следующий анализ:
- Если
alu имеет значение ADD или ADC, по в isa=1, и знание об этом необходимо для того, чтобы вычислять флаг OF
- Если
alu не равен AND, OR, XOR, то есть, это не логическая операция, то тогда isl=1, и это нужно для обнуления или оставлении значений некоторых результирующих флагов АЛУ. Когда исполняются логические функции, например, XOR, то флаги OF, AF и CF обнуляются, потому нужен провод isl для этой цели.
Рассмотрим же теперь сами вычисления флагов. Флаги расположил по порядку от старшего бита к младшему.
wire new_o = (op1[top] ^ op2[top] ^ isa) & (op1[top] ^ ar[top]);
wire new_s = ar[top];
wire new_z = 0 == (size ? ar[15:0] : ar[7:0]);
wire new_a = op1[4] ^ op2[4] ^ ar[4];
wire new_p = ~^ar[7:0];
wire new_c = ar[top + 1];
Самый, пожалуй, сложный тут будет флаг OF. Возможны две ситуации:
OF = (op1[top] ^ op2[top] ^ 1) & (op1[top] ^ ar[top]): ADD, ADC
OF = (op1[top] ^ op2[top] ^ 0) & (op1[top] ^ ar[top]): SUB, SBB, CMP
Здесь top это либо 7, либо 15, то есть, это старший бит операндов и результата, и, как можно отметить, вместо 1 или 0 установлено значение isa, который равно 1, если ADD или ADC, и 0 в других случаях.
Что делают остальные флаги:
SF (new_s) копирует старший бит результата
ZF (new_z) вычисляет, нулевой ли результат 8 или 16 битного результата
AF (new_a) вычисляет флаг полупереноса по общей формуле, разобранной в одной из глав ранее
PF (new_p) определяет четность единичных бит младших 8 бит результата
CF (new_c) вычисляет перенос, который находится либо в 8-м, либо в 16-м бите результата ar
А теперь последнее – вычисление флагов.
wire [11:0] af = {
new_o & isl,
flags[10:8],
new_s,
new_z,
1'b0,
new_a & isl,
1'b0,
new_p,
1'b1,
new_c & isl
};
Всё это кажется сложным, но это не так. Для логических функции там где & isl флаги OF, AF, CF просто обнуляются. В некоторых битах (5,3,1) значения битов строго заданы и никогда не изменяются. Для битов 8..10 значения просто копируются из предыдущих флагов, так как эти биты никак не меняются для АЛУ-операции.
В этой статье я рассмотрел только эти базовые функции, не переходя к вычислению сдвигов, поскольку для них будет написана отдельная статья.