vak: (Default)
В качестве теста возьмём упомянутый наибольший делитель.
module gcd (
input activate,
input [7:0] a,
input [7:0] b,
output [7:0] c
);
reg [7:0] x, y;

always while (activate) begin
fork
x <= a;
y <= b;
join

while select
x > y:
x = x - y;
y > x:
y = y - x;
endselect

c <= x;
end
endmodule
Парсер преобразует исходный текст в следующее синтаксическое дерево:Осталось научиться генерить из этого дерева асинхронную схему.
vak: (Default)
Закончил парсер для языка Verilog. Удалось приспособить Yacc-овскую грамматику от проекта Yosys, переписав её на Go. Лексический сканер позаимствовал от самого компилятора Go.

Узнал много забавного про константы в Верилоге. Обычный десятичный литерал типа 123 имеет знаковый тип. Если добавить к нему десятичный префикс ('d123), он становится беззнаковым. Чтобы снова превратить его в знаковый, надо добавить буковку s: 'sd123. Разницу можно заметить на примерах:
5 - 10 = -5
'd5 - 10 = 4294967291
'sd5 - 10 = -5
vak: (Default)
Обнаружил в языке Verilog неожиданную фичу, не описанную ни в одной книжке. Оказывается, диапазоны можно задавать в виде X+:Y или X-:Y, что эквивалентно X+Y-1:X и X:X-Y+1 соответственно. К примеру, эти три присваивания эквивалентны:
    value[10:8] = 0;
    value[10-:3] = 0;
    value[8+:3] = 0;
vak: (Default)
В продолжение темы 1, 2: слушайте радиопередачу про предстоящий на следующей неделе в Киеве семинар по микроэлектронике для школьников.

Аудиофайл (на украинском языке): https://hromadskeradio.org/sites/default/files/media/zvuk/hr_hh_2017-04-22_hutka.mp3

Частичная расшифровка: "Українські школярі вчитимуться проектувати мікросхеми, які застосовують Аpple та Tesla"
vak: (Default)
В конце апреля в Киеве пройдёт экспериментальный семинар для старших и младших школьников по обучению современной цифровой электронике. Программа семинара и форма для регистрации доступны на сайте: http://electronics-ukraine.com/


vak: (Default)
С какой максимальной скоростью может работать асинхронный процессор на FPGA? Многие считают, что это в принципе невозможно, а я тем временем решил измерить реальную цифру. Возьмём пустой цикл следующего вида:
    forever
        continue;
Еслибы существовал транслятор с SystemVerilog в асинхронные компоненты, он бы породил такую схему:
                 ,---. out ,---.
    activate ---o| # |----o|run|
                 `---'     `---'
                 Loop     Continue
Примитив Continue я уже упоминал недавно. Loop это компонент, реализующий бесконечный цикл. У него два синхропорта: по ведомому порту он получает сигнал активации, после чего начинает генерить последовательность импульсов на ведущем порту. Реализуется он следующим образом:
    module Loop (sync.slave activate, sync.master out);

        wire req = activate.req & !out.ack;

        BUFR b (.O(out.req), .I(req));

        assign activate.ack = '0;
    endmodule
Работает схема так:



С точки зрения формальной логики буфер BUFR здесь не требуется. Однако без него схема не работает. У семейства Xilinx Artix7 есть три типа подходящых буферов на выбор: BUFG, BUGH и BUFR. Я загрузил прошивку в плату Digilent Basys3 и измерил результат для всех трёх вариантов. Самая высокая частота получается с BUFR, а именно 309 МГц. Это будет верхний предел для скорости асинхронного процессора на данном типе FPGA.
vak: (Default)
Продолжаю постигать азы асинхронной логики. Про сигналы и базовый протокол взаимодействия я уже писал. Но то были теоретические рассуждения, а теперь пора заняться реальным кодом. Для описания асинхронных каналов задействуем конструкцию interface языка SystemVerilog. Будет использовать кодирование dual-rail. Адаптировать для quad-rail или 1-of-N будет нетрудно.

Существует три типа асинхронных каналов: push, pull и nonput. В первом случае активная сторона (мастер) выдаёт данные, а пассивная (slave) отвечает подтверждением:
_______           ______
       |  data   |
Master | ======> | Slave
output |         | input
       |  req    |
_______| <------ |______
Второй вариант - канал типа pull. Здесь мастер выдаёт запрос, а в ответ приходят данные:
_______           ______
       |  req    |
Master | ------> | Slave
input  |         | output
       |  data   |
_______| <====== |______
Каналы push и pull с кодированием dual rail ширины N бит можно описать следующим образом:
vak: (Улыбка)
Измерил скорость работы трёх разных Verilog-симуляторов на комплексном тесте системы команд микро-БЭСМ.

Synopsys VCS предсказуемо лидирует с большим отрывом. На втором месте Xilinx Vivado Simulator (бывший Cadence NCSIM). Altera Modelsim (заимствованный у Mentor Graphics) слегка отстаёт.

Сохранилась фотография из газеты "Дубна" от 13 июня 1990 года, где команда разработчиков демонстрирует работу ровно этого же теста отцам-основателям Мельникову и Томилину (автору аналогичного теста системы команд для БЭСМ-6).



На фотографии слева направо: В.М.Кадыков, И.Н.Силин, Т.Ф.Сапожникова, В.А.Мельников, А.П.Сапожников (1 ряд), И.А.Емелин, Ф.В.Левчановский, А.Н.Томилин (2 ряд, что выше).

Упомянутая статья на 4-5 страницах газеты: http://www.besm6.org/wiki/1990-dubna-retro86
 
vak: (Улыбка)
Измерил скорость трёх коммерческих симуляторов Verilog на тесте микро-БЭСМ.

Mentor Modelsim: 2428 микроинструкций в секунду.
Cadence NCsim: 2362 микроинструкций в секунду.
Synopsys VCS: 7759 микроинструкций в секунду.

Первые два - на самом деле бесплатные версии от Altera и Xilinx. Но синопсис по любому в разы быстрее получается.
vak: (Улыбка)
Сделал ассемблер для трансляции микрокода ЭВМ МКБ-8601.
Так выглядит результат: https://github.com/besm6/micro-besm/blob/master/microcode/microcode.v
vak: (Улыбка)
Воспроизвести чип Am2904 на Верилоге нетрудно. Насколько он соотвествует реальности, это другой вопрос. Надо каким-то образом сравнить его с реальныи чипом. Для этого я собрал вот такой стенд на базе Ардуино Мега.



vak: (Улыбка)
Сделал чип Am2904 на СистемВерилоге.
Теперь задача протестировать.
vak: (Улыбка)
Почему-то считается, что асинхронную логику нельзя засунуть в традиционную FPGA. Я решил поисследовать этот вопрос. Чем дольше разбираюсь, тем яснее становится, что это просто предубеждение. Я взял популярную плату Digilent Basys3 на основе чипа Xilinx Virtex-7, и стал смотреть, что тут можно сделать.

Основа асинхронной логики - несколько базовых примитивов: C-элемент, арбитр, S-элемент, T-элемент. Все их удалось реализовать на имеющейся FPGA. Вот, к примеру, как выглядит двухвходовый С-элемент Мюллера:


Дальше про трёхвходовый С-элемент, асинхронный арбитр, S-элемент и Т-элемент... )
vak: (Улыбка)
В поисках неортодоксальных подходов к разработке хардвера, в частности в области асинхронной логики, я неожиданно для себя открыл интересный язык Balsa, и стоящую за ним методику, называемую 'Handshake Circuits'. Взгляните, вот программа вычисления наибольшего общего делителя на Бальсе:
procedure GCD (
    input x: byte;
    input y: byte;
    output z: byte
) is
local 
    variable a, b: byte
begin
    loop
        x -> a || y -> b;
        loop
            while a /= b then
            begin
                if a > b
                then a := (a - b as byte)
                else b := (b - a as byte)
                end
            end
        end;
        z <- b
    end
end
При компиляции она превращается в такую асинхронную схему:

Дальше она преобразуется в Verilog и синтезируется в собственно микросхему. Разве не прелесть? Не одним верилогом жив человек! :)

Бальса разрабатывалась в 1998-2010 годах в университете Манчестера. Её исходные тексты доступны на сайте университета на условиях лицензии GPL. Подход подробно описан в диссертации Andrew Barsley "Balsa: An Asynchronous Circuit Synthesis System".
vak: (Улыбка)
"Compiling from Haste to CDFG: a front end for an asynchronous circuit synthesis system" (PDF).

Вычисление факториала на языке Haste выглядит следующим образом:
int = type [0..2^32-1] &

fact : main proc (in?chan int & out!chan int).
  begin x,y :var int ff
  |
    forever do
      in ? x
    ; y := 1
    ; do x > 1 then
        y := y * x
      ; x := x - 1
      od
    ; out ! y
  od
end

Эта функция превращается в такую асинхронную схему:


Дальнейшее преобразование в Верилог и синтез делаются элементарно.
vak: (Улыбка)
Обычно считается, что FPGA не годятся для асинхронной логики. Родной софт от Xilinx способствует этому предубеждению: при попытке создать latch традиционными средствами языка Verilog, к примеру:
    always @(*)
        if (set)
            z <= 1;
        else if (clr)
            z <= 0;
получаем серию страшных предупреждений типа:
WARNING:Xst:737 - Found 1-bit latch for signal <z>. Latches may
be generated from incomplete case or if statements. We do not
recommend the use of latches in FPGA/CPLD designs, as they may
lead to timing problems.

(*) This 1 clock signal(s) are generated by combinatorial logic,
and XST is not able to identify which are the primary clock signals.
Please use the CLOCK_SIGNAL constraint to specify the clock signal(s)
generated by combinatorial logic.

WARNING:PhysDesignRules:372 - Gated clock. Clock net clr is sourced by a
combinatorial pin. This is not good design practice. Use the CE pin to
control the loading of data into the flip-flop.
Между тем, задача отлично решается посредством компонента FDCPE из библиотеки Xilinx. Немного лёгкого шаманства, и он превращается в асинхронную защёлку:
module th22 (input a, input b, output z);
    assign set = a & b;
    assign clr = !a & !b;

    FDCPE latch (
        .Q   (z),      // Data output
        .D   (0),      // Data input
        .C   (0),      // Clock input
        .CE  (0),      // Clock enable 
        .PRE (set),    // Asynchronous set 
        .CLR (clr)     // Asynchronous clear 
    );
endmodule
vak: (Улыбка)
Регистр в подходе NCL logic выглядит так:



Попробуем изобразить его на Верилоге. Трудность в том, что Верилог не даёт простого способа обозначить Dual Rail encoding, то есть сигналы, представленные в виде пары проводов. Один из вариантов - задействовать состояние X, приписав ему другую семантику. Будем считать, что X - это когда оба провода логического сигнала принимают значения Low (то есть NULL). В этом случае асинхронный регистр может выглядеть так:

module areg #(
    parameter WIDTH = 2             // ширина регистра
)(
    input  wire             reset,  // сброс
    input  wire [WIDTH-1:0] d,      // данные на входе
    input  wire             ki,     // вход подтверждения
    output reg  [WIDTH-1:0] q,      // данные на выходе
    output wire             ko      // выход подтверждения
);
    always @(*) begin
        if (reset)
            q <= {WIDTH{1'bx}};     // при сбросе выдаём NULL
        else if (ki)
            q <= d;                 // защёлкиваем вход (возможно, содержащий NULL-и)
        else for (i=0; i<WIDTH; i=i+1)
            if (d[i] === 1'bx)
                q[i] <= 1'bx;       // сбрасываем выход в NULL

    assign ko = (^q === 1'bx);      // выдаём подтверждение, пока выход не полностью определён
endmodule
Не знаю пока, вылезут ли грабли при симуляции из-за нештатного использования состояния X, или прокатит.
vak: (Улыбка)
Берём Yosys: бесплатный открытый софт для синтеза. Его можно легко собрать из исходников под Линукс, или скачать готовый для RedHat или Windows. В качестве примера создаём файл example.v на языке Verilog:
    module example(input clk, a, b, c, output reg [1:0] y);
        always @(posedge clk)
            if (c)
                y <= a + b;
    endmodule
Скрипт и протокол... )
Откроется окошко с получившейся схемой:



На схеме можно видеть сумматор, мультиплексор и D-триггер.

Подробности можно прочитать в статье "Yosys Application Note 011: Interactive Design Investigation".
vak: (Улыбка)
Основной сайт проекта: http://www.clifford.at/yosys/
Исходники на Гитхабе: https://github.com/cliffordwolf/yosys
Краткое введение: http://www.clifford.at/yosys/files/yosys-austrochip2013.pdf
Полное описание: http://www.clifford.at/yosys/files/yosys_manual.pdf

Характеристики:
• Обрабатывает практически любой синтезируемый дизайн на языке Verilog-2005.
Преобразует Verilog в BLIF / EDIF / BTOR / SMT-LIB / упрощённый RTL Verilog / и т.п.
Встроенные формальные методы проверки свойств и эквивалентности.
Отображение на стандартные библиотеки ASIC (в формате Liberty).
Отображение на Xilinx 7 серии и Lattice iCE40 FPGA.