Дожив до седых волос, сделав множество работоспособных и ещё больше неработоспособных электронных штук, понял, что в моих познаниях есть некий пробел, заполненный ненадёжным туманом очень общих слов: я не знаю, как на самом деле работают микропроцессоры. Т.е. я умею ими пользоваться, я понимаю различия между архитектурами и семействами, я знаю, для чего нужно АЛУ, кэш и т.п., но я не имею ни малейшего представления о том, как оно на самом деле всё устроено. Т.е. я понимаю, что на функциональных схемах обозначают эти квадратики, но вот что у них внутри - ?..
И это беспокойное сомнение свербит мне мозг.
Полез читать и разбираться.
Начал с динозавра (стадию релейных рыб и ламповых земноводных решил пропустить) - АЛУ 74181, достославный чип, подливший бензина в пламя компьютерной революции. Почитал даташиты, заказал (ещё не получил) КМОП-версию для экспериментов. Чтобы было что пощупать, пока микросхемы в пути, написал
VHDL-модель, буквально передрав схему из документации:
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity alu74181 is
Port ( m : in STD_LOGIC;
cn : in STD_LOGIC;
s : in STD_LOGIC_VECTOR (3 downto 0);
neg_a : in STD_LOGIC_VECTOR (3 downto 0);
neg_b : in STD_LOGIC_VECTOR (3 downto 0);
neg_g : out STD_LOGIC;
neg_p : out STD_LOGIC;
Cn4 : out STD_LOGIC;
neg_f : out STD_LOGIC_VECTOR (3 downto 0);
pb,gb : out STD_LOGIC_VECTOR (3 downto 0);
a_eq_b : out STD_LOGIC);
end alu74181;
architecture Behavioral of alu74181 is
signal g, -- GENERATE
p, -- PROPAGATE
f : std_logic_vector (3 downto 0);
signal a,b: std_logic_vector (3 downto 0);
signal nm, temp_ng, temp_cn4, temp_p : std_logic;
begin
a <= neg_a;
b <= neg_b;
nm <= not m;
g(3) <= not ( (b(3) and s(3) and a(3)) or (a(3) and s(2) and (not b(3))) ); -- Generate
g(2) <= not ( (b(2) and s(3) and a(2)) or (a(2) and s(2) and (not b(2))) ); -- Generate
g(1) <= not ( (b(1) and s(3) and a(1)) or (a(1) and s(2) and (not b(1))) ); -- Generate
g(0) <= not ( (b(0) and s(3) and a(0)) or (a(0) and s(2) and (not b(0))) ); -- Generate
p(3) <= not ( (not b(3) and s(1) ) or (s(0) and b(3)) or a(3)); -- Propagate
p(2) <= not ( (not b(2) and s(1) ) or (s(0) and b(2)) or a(2)); -- Propagate
p(1) <= not ( (not b(1) and s(1) ) or (s(0) and b(1)) or a(1)); -- Propagate
p(0) <= not ( (not b(0) and s(1) ) or (s(0) and b(0)) or a(0)); -- Propagate
pb <= p;
gb <= g;
temp_p <= (g(3) and g(2) and g(1) and g(0));
neg_p <= not temp_p;
temp_ng <= not (
p(3) or
(g(3) and p(2)) or
(g(3) and g(2) and p(1)) or
(g(3) and g(2) and g(1) and p(0))
);
neg_g <= temp_ng;
temp_cn4 <= not (temp_p and cn);
cn4 <= (not temp_cn4) or (not temp_ng);
f(3) <= (g(3) and (not p(3))) xor
(not (
(g(2) and g(1) and g(0) and cn and nm) or
(g(2) and g(1) and p(0) and nm) or
(g(2) and p(1) and nm) or
(p(2) and nm)
)
);
f(2) <= (g(2) and (not p(2))) xor
(not (
(g(1) and g(0) and cn and nm) or
(g(1) and p(0) and nm) or
(p(1) and nm)
)
);
f(1) <= (g(1) and (not p(1))) xor
(not (
(g(0) and cn and nm) or
(p(0) and nm)
)
);
f(0) <= (g(0) and (not p(0))) xor
(not (cn and nm));
neg_f <= f;
a_eq_b <= (f(3) and f(2) and f(1) and f(0));
end Behavioral;
----------------------------------------------------------------------------------
Написал тестбенч для некоторых функций (всё решил не проверять, ибо не могу придумать никакого практического применения выражениям типа (A + /B) plus AB). И эта штука в самом деле умеет складывать, вычитать, сравнивать... поразительно. Т.е. вроде ничего странного - но всё равно удивляет.
Набросал так же модель 4-битного компаратора 7585 (и сделал из неё 32-битную версию) и каскадного быстрого сумматора вообще на отдельных вентилях. Всё работает: битики сравнения выставляются, сумма-разность вычисляется. Фантастика!
Почитал ещё, как в самом деле устроена кэш-память. Модель ещё не делал, т.к. пока не всё ясно.
Параллельно читаю про RISC-V.
Почитал, что-как народ делает.
Посмотрел картинки самопальных компьютеров, в т.ч. смелую попытку собрать RISC-V на рассыпухе (чувак зашёл очень бодро - но закончил примерно там же, где и начал).
Понял, что все они дураки, а я один умный и весь в белом - думаю, а не попробовать ли и мне? Ведь нет лучшего способа для того, чтобы в чём-то разобраться, чем сделать это самому. Причём не на ПЛИС. Во всяком случае, не на высокоуровневом HDL, прячущем все детали реализации под кодом - это было бы удобно, но всё равно непонятно: к примеру, тот же АЛУ, будучи написанным как блок switch/case, остаётся всё таким же таинственным квадратиком.
Уже понятно, что чудовище будет огромное (сотни микросхем), медленное (вряд ли тактовую частоту получится поднять выше 5 МГц) и дорогое: один лишь только блок регистров (только детальки к нему!) обойдётся рублей эдак тыщи в три-четыре. А это ведь только часть. Хоть и весьма значительная, но не единственная. Потребуется много-много мультиплексоров и дешифраторов, отдельных вентилей и триггеров, компараторов, сумматоров и т.п., и т.д. Плюс всякая экзотика и эзотерика, снятая с производства - и если АЛУ ещё можно легко повторить на отдельных вентилях (и получится даже лучше, чем оригинал), то content-addressable memory повторить хоть и в принципе возможно, но лучше всё-таки найти чипы, оставшиеся от золотой эпохи цифровой электроники.
Собирать на отдельных транзисторах или реле, как поступают некоторые из немногих, я, пожалуй, не буду.