Если вы проектируете процессор, реализующий различные операции в гигантском операторе case, то на самом деле вы описываете ряд параллельных функциональных блоков, питающих выходной мультиплексор. У вас может быть выход, который управляется, в зависимости от режима операции, выводом либо умножения, сложения, вычитания, некоторой логической операции, сдвига и т. д.
Вы можете легко спроектировать это модульным способом, реализовав каждый функциональный блок в своем собственном объекте, некоторые из которых могут быть довольно простыми. В первом случае эти блоки будут работать безоговорочно, а их выходы будут подаваться на выходной мультиплексор. Позже вы можете добавить сигналы включения, управляемые вашей логикой декодирования инструкций, которые включают только блоки, которые будут использоваться в конкретной операции, для экономии энергии. Может показаться, что при таком подходе вы получите много управляющих сигналов, но если вы поместите их все в запись, это сделает код довольно компактным, в то же время обеспечивая многословие и читабельность в точке, где управляющий элемент используется сигнал, например:
AddSub : entity work.AdderSubtractor
port map (
clk => clk,
enable => decoded_instruction.addsub_enable,
a => a,
b => b,
mode => decoded_instruction.addsub_mode, -- This might be an enumerated type
output => addsub_output
);
Были бы другие сигналы _output
, и в конце у вас было бы что-то вроде
OutputMux : process (all)
begin
case decoded_instruction.output_mux_select is
when ADD_SUB => output <= addsub_output;
when MULT => output <= mult_output;
when LOGIC => output <= logic_output;
end case;
end process;
Одним из преимуществ этого способа является то, что вы можете найти эффективным несколько функций, реализованных в блоке DSP в FPGA; вы можете легко создать функциональный блок для сложения, вычитания, умножения, написанный для целевого блока DSP на вашем устройстве. Выход этого будет просто еще одним входом для вашего «выходного» мультиплексора. По моему опыту, вы должны быть в состоянии эффективно реализовать многие из ваших функций обработки, используя один блок DSP (или один объект, который описывает несколько каскадных блоков DSP, в зависимости от ширины пути данных).
Лично я предпочитаю такой подход, заключающийся в том, чтобы сделать дизайн очень модульным. В недавнем многоядерном проекте DSP у меня есть только пара файлов, содержащих около 500 строк, а в большинстве из них 200 или меньше. Это означает, что когда я возвращаюсь к части дизайна, она обычно умещается на одной странице, и ее можно легко подобрать и понять за очень короткий промежуток времени. Я также обнаружил, что при реализации тяжелой конвейерной обработки для повышения производительности проекта слишком много операций в одном процессе или объекте может на порядок усложнить эту работу.
Наконец, если функциональные элементы содержатся в небольших объектах, вам будет проще смоделировать, протестировать и проверить только этот фрагмент кода в изоляции, что, по моему опыту, позволяет быстрее подписывать блок, в то же время давая больше уверенности в коде. Если все находится в одном процессе, сложнее быть уверенным, что изменение, которое исправляет или улучшает что-то одно, не сломает что-то другое. Опять же, в сильно конвейеризированном дизайне я обнаружил, что может быть довольно легко изменить что-то, что непреднамеренно приведет к сбою проекта из-за жестких временных ограничений, поэтому чем проще объекты, тем меньше шансов, что это произойдет.
person
scary_jeff
schedule
30.08.2016