Как удалить защелки в коде 1-битного ALU?

#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.