Сперва некоторое перечисление критериев/мыслей:
- Теорию категорий подключить сразу не удастся, слишком её много. Придётся делать как всегда - ad hoc, используя идеи.
- На первое (и довольно длительное время) можно ограничиться только синхронным дизайном без управления тактирующими линиями (такие случаи очень редки, судя по краткому опросу и исследованию).
- Без Template Haskell не обойтись. В противном случае, не удастся использовать алгебраические типы, чего хотелось бы.
- Судя по всему, количество идиом будет достаточно небольшим из-за необходимости их корректной трансляции. Достаточным ровно для того, чтобы не чувствовать особой скованности, это раз, и чтобы программы не раздувались, это два. Точнее: argument guards, подмножество сравнения с образцом, case, if, всякого рода умножения и сложения со сдвигами.
- Использование TH может позволить упростить создание элементов. Например, можно сравнить типы аргументов и выходных значений, и если типы совпадают на каком-то последовательном участке, считать их состоянием, помещая их в регистры.
Пример:
$(circuit [d|counter n reset enable PosEdge
| reset = (0,0)
| enable = let n1 = n+1 in (n1,n)
| otherwise = (n,n)
|])Как вариант реализации counter. Дублирования (которое (n1,n1)) можно избежать, но это уже детали реализации.
PosEdge (который означает срабатывание по фронту тактирующего сигнала) может отделять состояние.
Что ещё интересно: тип counter получится counter :: (Num a) => a -> Bool -> Bool -> ClockEdges -> (a, a), что означает, что он параметризован типом. Значит, если мы где-то обнаружим counter, то нам придётся выяснить типы его аргументов и создать соответствующий код (counter_Int2 или counter_Int64). С одной стороны, мы не фиксируем типы, с другой стороны, придётся проводить вывод типов (заранее кричу от отчаяния;).
Для сравнения - код counter из документации на HDCaml:
let counter_design width =
(* Initialize the design database. *)
start_circuit "counter_example";
(* Define the top-level inputs. *)
let enable = input "enable" 1 in
(* Start a sub-circuit. *)
circuit "counter";
(* Instantiate the counter. Label the enable inside the sub-circuit to aid in debugging. *)
let count = counter width ("enable" -- enable) in
(* Close the sub-circuit. *)
endcircuit ();
(* Define the top-level outputs. *)
output "count" count;
(* Fetch the circuit database. *)
let circuit = get_circuit () in
(* Generate a Verilog netlist. *)
Verilog.output_netlist circuit;
(* Generate a SystemC model. *)
Systemc.output_model circuit;
(* Open a VCD channel and simulate the counter. *)
let vcd = open_out "counter_example.vcd" in
let sim, inputs, outputs = Simulate.create circuit vcd in
(* Fetch the enable input and set it high. *)
let enable = List.assoc "enable" inputs in
enable.(0) <- 1;
(* Run a few cycles. *)
Simulate.cycle sim;
Simulate.cycle sim;
Simulate.cycle sim;
Simulate.cycle sim;
(* Disable the counter. *)
enable.(0) <- 0;
Simulate.cycle sim;
Simulate.cycle sim;
(* Re-enable the counter. *)
enable.(0) <- 1;
Simulate.cycle sim;
Simulate.cycle sim;
(* Reset the circuit. *)
Simulate.reset sim;
Simulate.cycle sim;
Simulate.cycle sim;
(* Close the VCD channel. *)
close_out vcd
;;
И для справки:
сравнение HDL, включая HDCaml и Confluence.