Увы, я не очень хороший объясняльщик. Кроме того, хотя я также являюсь и программистом, мне тоже приходится по ходу дискуссии обдумывать как это все лучше реализовать программно. Так что польза от обсуждения обоюдная 

Сообщение от
gid
т.е. следуя этой логике, vm1_pli pli_matrix(.rq(rq), .sp(pli)); нужно внутри модуля vm1_qbus развернуть как include и все его assignы выполнять как assignы модуля vm1_qbus и не вызывать его как внешнюю функцию.
Да, по сущности это инклуд/макрос. Включаются внутренние блоки модуля. Но, синтаксически, сами сигналы можно рассматривать не как переменные, а как функции. Типа:
Код:
plm_ena_fc_var = plm_ena_fc(....);
Тогда очень уж сильного разворачивания можно избежать и использовать много готового кода из имеющегося верилога. И часть модулей можно будет представить как функции. Вот vm1_pli и vm1_plm содержат только assign - их можно представить как фукнции. vm1_timer - уже имеет внутри триггеры, его как функцию не представить.

Сообщение от
gid
Поэтому, если с assignами и alwaysами как-то более-менее понятно, то с вызовом модуля из другого модуля, если его рассматривать именно как внешнюю функцию, возникает неясность.
Нет, Вы правильно сказали, модуль надо рассматривать как include или макрос, в том смысле что его внутренние блоки включаются в проект и внутренний текст разворачивается - все внутренние assign и always включаются в текущий уровень вложений. То есть модуль - это НЕ вызов функции/функций в общем случае. Отдельный assign - да, можно рассмотреть как вызов программной функции. Кстати, в Верилоге есть свои таски и функции, хорошо что я их тут не применял 

Сообщение от
gid
С моей точки зрения это наоборот усложнение. Если always сложный и развесистый, то количество используемых переменных может возрасти кратно
always не может быть сложным и развеститым, его суть - указать триггеры которые назначаются по событию клока. То, что там внутри понаписаны какие-то функции - это просто синтаксическое удобство, внос неявного assigna. Я просто предложил сделать их явными. Тогда в always вообще не придется ничего вычислять, просто тупо переписать в триггеры по событию клока результаты из массива вычисленных значений функций. Никаких снапшотов и раздумий что и откуда брать.

Сообщение от
gid
может не получиться выстроить все assignы в порядке, когда не нужно их крутить в цикле.
Получится, абсолютно весь проект сводится к парам функция/триггер. И все функции имеют в качестве аргументов внешние входные значения (для модуля процессора это внешние пины) и триггеры. Если входным значением вдруг является значение другой функции - то эта другая все равно в итоге доходит до внешних параметров и триггеров. То есть любая функция в проекте зависит только от внешних сигналов и состояния триггеров. Все функции-аргменты являются промежуточными и в итоге тоже приходят к зависимости только от внешних сигналов и триггеров.
Эту промежуточную функцию-аргумент можно или вычислить ее значение и "закешировать" для использования в других выражениях (как аргумент других функций) - то есть назначить результат какой-то переменной, или для начала, для простоты, тупо вычислять каждый раз - тогда не нужен цикл, все результаты будут актуальными сразу.

Сообщение от
gid
А выход из цикла - сравнение предыдущего состояния списка переменных с новым, там одно это сравнение будет сколько ресурсов отжирать.
Да, цикл он только для иллюстрации был, как метод вычисления, независящий от порядка операторов. Не лучшая идея, согласен.
---------- Post added at 18:26 ---------- Previous post was at 17:51 ----------
Давайте вместе подумаем на совсем простом примере, я вот набросал 155ИР13, синхронный сдвиговый регистр, с параллельной загрузкой и асинхронным сбросом, чтобы не возиться с описанием взял стандартную микросхему.
Код:
module ir13
(
input rst_n, // async reset, active low
input clk, // sync clock, raising edge
input [2:1] s, // shift mode
input [7:0] d, // parallel load data
input dsr, dsl; // new shifted in data bit
output reg [7:0] q // output data
);
wire [7:0] q_rc;
//
// assign form is used deliberately for illustrative purposes
//
assign q_rc[0] = (s == 2'b00) & q[0] // storage
| (s == 2'b01) & q[1] // shift left
| (s == 2'b10) & dsr // shift right
| (s == 2'b11) & d[0]; // parallel load
assign q_rc[1] = (s == 2'b00) & q[1] // storage
| (s == 2'b01) & q[2] // shift left
| (s == 2'b10) & q[0] // shift right
| (s == 2'b11) & d[1]; // parallel load
assign q_rc[2] = (s == 2'b00) & q[2] // storage
| (s == 2'b01) & q[3] // shift left
| (s == 2'b10) & q[1] // shift right
| (s == 2'b11) & d[2]; // parallel load
assign q_rc[3] = (s == 2'b00) & q[3] // storage
| (s == 2'b01) & q[4] // shift left
| (s == 2'b10) & q[2] // shift right
| (s == 2'b11) & d[3]; // parallel load
assign q_rc[4] = (s == 2'b00) & q[4] // storage
| (s == 2'b01) & q[5] // shift left
| (s == 2'b10) & q[3] // shift right
| (s == 2'b11) & d[4]; // parallel load
assign q_rc[5] = (s == 2'b00) & q[5] // storage
| (s == 2'b01) & q[6] // shift left
| (s == 2'b10) & q[4] // shift right
| (s == 2'b11) & d[5]; // parallel load
assign q_rc[6] = (s == 2'b00) & q[6] // storage
| (s == 2'b01) & q[7] // shift left
| (s == 2'b10) & q[5] // shift right
| (s == 2'b11) & d[6]; // parallel load
assign q_rc[7] = (s == 2'b00) & q[7] // storage
| (s == 2'b01) & dsl // shift left
| (s == 2'b10) & q[6] // shift right
| (s == 2'b11) & d[7]; // parallel load
always @(posedge clk or negedge rst_n)
begin
if (~rst_n)
q <= 8'b00000000;
else
q <= q_rc;
end
endmodule
Теперь надо подумать как это представить на С++, можете шаблон создать? Я в плюсах писатель не очень.