#verilog
Вопрос:
Я пытаюсь создать 32-разрядный ALU в Verilog. Я реализовал 1-битный ALU в самом начале. ALU должен иметь только 4 функции, не все из них: добавить, добавить, и, или. Это мой код:
module ALU( input wire [3:0] OPCode, input wire Operand1, input wire Operand2, input wire cin, output reg Result, output reg Cout ); always@(*) begin case(OPCode) 4'b0000: Result = Operand1amp;Operand2; 4'b0001: Result = Operand1|Operand2; 4'b0010: begin Result = cin ^(Operand1 ^ (Operand2 ^ cin)); Cout = ((Operand2 ^ cin) amp; Operand1) | ((Operand1 ^ (Operand2 ^ cin)) amp; cin); end 4'b0110: begin Result = cin ^(Operand1 ^ (Operand2 ^ cin)); Cout = ((Operand2 ^ cin) amp; Operand1) | ((Operand1 ^ (Operand2 ^ cin)) amp; cin); end endcase end endmodule
Проблема здесь в том, что это создает ненужные ЗАЩЕЛКИВАЮЩИЕСЯ ворота. Я уже знаю, что это потому, что я не освещаю все случаи в своем case
заявлении; однако это единственные случаи, которые у меня есть. Что я должен сделать, чтобы исправить свое case
заявление?
Ответ №1:
В верхней части always
блока, но перед case
оператором, установите начальные значения для всех сигналов, назначаемых в always
блоке. В вашем коде это означает:
Result = 0; Cout = 0;
Поскольку комбинационная логика использует блокирующие назначения, начальные значения будут правильно перезаписаны при выборе одного из ваших 4 кодов операций. Вот полный always
блок:
always@(*) begin Result = 0; Cout = 0; case(OPCode) 4'b0000: Result = Operand1amp;Operand2; 4'b0001: Result = Operand1|Operand2; 4'b0010: begin Result = cin ^(Operand1 ^ (Operand2 ^ cin)); Cout = ((Operand2 ^ cin) amp; Operand1) | ((Operand1 ^ (Operand2 ^ cin)) amp; cin); end 4'b0110: begin Result = cin ^(Operand1 ^ (Operand2 ^ cin)); Cout = ((Operand2 ^ cin) amp; Operand1) | ((Operand1 ^ (Operand2 ^ cin)) amp; cin); end endcase end
Есть и другие способы сделать это, но это общий подход.
Ответ №2:
Проблема в том, что вы закодировали защелку в своей логике. Учесть следующее:
aways @* if(en) a lt;= b;
В приведенной выше схеме, если en
она высока, то a
меняется, как только b
меняется. Но, если en
он низкий, a
сохранит свое прежнее значение, даже если b
изменится. Это поведение защелки, и инструменты синтеза распознают определенный шаблон для создания защелок.
Алгоритмически защелка выводится из не полностью заданного условного оператора, подобного приведенному выше if
без else
, где a
в некоторых случаях не приводится в действие.
Чтобы выразить комбинаторную логику, вам нужно убедиться, что a
она управляется во всех случаях. Ниже показан простой комбинаторный двусторонний мультиплексор
always @* if (en) a = b; else a = c;
В приведенном выше a
приводится во всех ветвях оператора if. Кстати, использование =
или lt;=
не определяет тип или кодированное устройство. Однако lt;=
рекомендуется для последовательной логики, такой как защелки, и =
ее следует использовать для комбинаторных устройств.
Другой способ убедиться, что a
это всегда выполняется, — это присвоить ему определенное значение перед условным оператором, как здесь:
always @* begin a = c; if (en) a = b; end
Это хорошо известный шаблон проектирования, который работает со всеми инструментами синтеза.
Итак, ваш код аналогичен приведенному выше, и вы не приводите результат и подсчет во всех ветвях оператора case. Другими словами, вы упускаете default:
. Вы можете добавить его как
always @* case ... default: begin Result = 0; Cout = 0; end endcase ...
Или вы можете использовать вторую схему с предварительной инициализацией и назначить их перед оператором case, как в ответе toolic.