FPGA. Динамическая мета-логика (Dynamic meta-logics)
Как программиста меня всегда привлекала возможность производить вычисления со скоростью работы аппаратной логики. Но для этого потребовалось бы перестраивать логическую схему компьютера программным способом. Когда я узнал в середине 1990-х, что есть такие микросхемы -- программируемой логики ПЛИС (FPGA), то я сразу понял, что пройдёт некоторое время и у меня появится такая возможность.
И вот, начав изучать язык описания аппаратной логики Verilog, я сразу же вспомнил об этой своей мечте, так что оставалось только изобрести, как это воплотить. В данной статье рассказывается, как это делается.
Универсальный функциональный модуль
Логическая схема, которую можно перестраивать, представляет собой конструктор, состоящий из логических модулей, либо разнотипных, либо универсальных. Вполне понятно, что использовать в качестве строительных блоков универсальные модули было бы предпочтительнее, и хотя они занимают несколько больше логических вентилей, в данном случае на мой взгляд скорее важно проиллюстрировать сам принцип устройства подобного универсального функционального модуля.
В чём-то универсальный функциональный модуль напоминает арифметическо-логическое устройство АЛУ (MCU), хотя я сравнил бы его с микросхемой стандартной логики, функциональную начинку которой можно переключать, подавая на её контрольные выводы значения "включить AND, включить XOR и т.п.".
Вот как выглядит универсальный функциональный модуль unifunc (скачать), имеющий 2 входа, 2 выхода и умеющий выполнять 8 различных функций:
module unifunc(
input [1:0] IN,
input [2:0] ctrlIN,
output reg [1:0] OUT
);
always @ (IN)
case (ctrlIN)
3'b000: // Hi-Z
OUT <= 2'bzz;
3'b001: // Pass Through
begin
OUT[0] <= IN[0];
OUT[1] <= IN[1];
end
3'b010: // 2 NOT
begin
OUT[0] <= ~IN[0];
OUT[1] <= ~IN[1];
end
3'b011: // AND and AND-NOT
begin
OUT[0] <= IN[0] & IN[1];
OUT[1] <= ~ (IN[0] & IN[1]);
end
3'b100: // OR and OR-NOT
begin
OUT[0] <= IN[0] | IN[1];
OUT[1] <= ~ (IN[0] | IN[1]);
end
3'b101: // XOR and XOR-NOT
begin
OUT[0] <= IN[0] | IN[1];
OUT[1] <= ~ (IN[0] | IN[1]);
end
3'b110: // Sum
begin
OUT[0] <= IN[0] + IN[1];
OUT[1] <= IN[0] & IN[1];
end
3'b111: // Difference
begin
OUT[0] <= IN[1] - IN[0];
OUT[1] <= IN[1] < IN[0];
end
endcase
endmodule
Динамически конфигурируемый коммутатор сигналов
Чтобы соединять между собой входы и выходы логических модулей, требуется коммутатор сигналов, причём конфигурируемый, чтобы схему коммутации можно было менять динамически. Следующая диаграмма иллюстрирует логику устройства данного модуля:
Как можно увидеть на диаграмме, все входы и выходы логических модулей с точки зрения логического коммутатора представляют собой два набора - входов и выходов, при этом контрольный сигнал для выхода задаёт номер входа, сигнал с которого на данный выход поступает.
Вот как выглядит код модуля на 16 входов и 16 выходов comm16to16 (скачать) на языке Verilog:
module comm16to16(
input wire [15:0] IN,
input wire [3:0] ctrlIN0,
input wire [3:0] ctrlIN1,
input wire [3:0] ctrlIN2,
input wire [3:0] ctrlIN3,
input wire [3:0] ctrlIN4,
input wire [3:0] ctrlIN5,
input wire [3:0] ctrlIN6,
input wire [3:0] ctrlIN7,
input wire [3:0] ctrlIN8,
input wire [3:0] ctrlIN9,
input wire [3:0] ctrlINA,
input wire [3:0] ctrlINB,
input wire [3:0] ctrlINC,
input wire [3:0] ctrlIND,
input wire [3:0] ctrlINE,
input wire [3:0] ctrlINF,
output reg [15:0] OUT
);
always @ (IN or ctrlIN0 or ctrlIN1 or ctrlIN2 or ctrlIN3
or ctrlIN4 or ctrlIN5 or ctrlIN6 or ctrlIN7
or ctrlIN8 or ctrlIN9 or ctrlINA or ctrlINB
or ctrlINC or ctrlIND or ctrlINE or ctrlINF)
begin
OUT[0] <= IN[ctrlIN0];
OUT[1] <= IN[ctrlIN1];
OUT[2] <= IN[ctrlIN2];
OUT[3] <= IN[ctrlIN3];
OUT[4] <= IN[ctrlIN4];
OUT[5] <= IN[ctrlIN5];
OUT[6] <= IN[ctrlIN6];
OUT[7] <= IN[ctrlIN7];
OUT[8] <= IN[ctrlIN8];
OUT[9] <= IN[ctrlIN9];
OUT[10] <= IN[ctrlINA];
OUT[11] <= IN[ctrlINB];
OUT[12] <= IN[ctrlINC];
OUT[13] <= IN[ctrlIND];
OUT[14] <= IN[ctrlINE];
OUT[15] <= IN[ctrlINF];
end
endmodule
Обработка данных
Следующая диаграмма иллюстрируют общую схему обработки данных в процессоре динамической мета-логики:
Как следует из диаграммы, вся схема состоит из двух частей: коммутируемой логики с модулями ввода и вывода данных, а также управляющего модуля, который предварительно конфигурируется по последовательному интерфейсу на ряд заданных конфигураций обработки данных, переключение между которыми в процессе обработки данных происходит с требуемой скоростью (то есть очень быстро).
Данная схема позволяет использовать вместо распараллеливания вычислений их аппаратное ускорение с квантованием по времени.
Автор: Андрей Шаройко <vanyamboe@gmail.com>