Простой пример Verilog для светодиодного переключателя?

Я пытаюсь создать StateMachine для простой кнопки переключения светодиодов с 1 горячим кодированием.

Особенно я пытаюсь понять блокирующие и неблокирующие назначения на своем примере.

Считаете ли вы, что следующее можно было бы сделать лучше или это совершенно неправильно в любом блоке?

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);


reg on;
reg off;

reg t_on_off;
reg t_off_on;


always @* begin
  t_on_off = on & (push);
end

always @* begin
  t_off_on = off & (push);
end


always @(posedge clk or posedge rst) begin
  if (rst)              on <= 1'b0;
  else if (t_off_on)    on <= 1'b1;
  else if (t_on_off)    on <= 1'b0;
end

always @(posedge clk or posedge rst) begin
  if (rst)              off <= 1'b1;
  else if (t_off_on)    off <= 1'b0;
  else if (t_on_off)    off <= 1'b1;
end


always @* begin
  led_on = on;
end


endmodule

Особенно я хотел бы знать: могу ли я объединить назначения переходов в один блок, например:

always @* begin
  t_on_off = on & (push);
  t_off_on = off & (push);
end

?


person membersound    schedule 30.05.2013    source источник


Ответы (5)


Если он не должен быть одноразовым, то упростите его до:

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);

always @(posedge clk or posedge rst) begin
  if (rst)        led_on  <= 1'b0;
  else if (push)  led_on  <= !led_on;
end

endmodule

Он функционально эквивалентен тому, что у вас есть, и более удобочитаем.

person Greg    schedule 30.05.2013

Особенно хотелось бы узнать: могу ли я объединить назначения переходов в один блок, например...

Да, вы можете сделать это именно так, как вы описали.

Вы также можете комбинировать последовательные блоки, если хотите:

always @(posedge clk or posedge rst) begin
  if (rst) begin
     on  <= 1'b0;
     off <= 1'b1;
  end else if (t_off_on) begin
     on  <= 1'b1;
     off <= 1'b0;
  end 
  (etc....)
end
person Tim    schedule 30.05.2013

Да, вы можете объединить несколько блоков всегда в один.

Вам просто нужно разделить синхронные (синхронизированные) и асинхронные блоки на отдельные блоки always.

Однако хорошим стилем является наличие блока всегда для каждого отдельного вывода. Это проще для чтения и более реалистично, так как каждый блок always параллелен друг с другом.

person sybreon    schedule 30.05.2013

Предложение по рефакторингу:

output reg led_on;

always @* begin
  led_on = on;
end

to:

output led_on; //wire by default (not declared reg)

assign led_on = on;

Вы также можете сделать то же самое со своими t_on_off и t_off_on.

wire t_on_off;
wire t_off_on;

assign t_on_off = on  & (push);
assign t_off_on = off & (push);

Или, если вы предпочитаете свернуть объявление и назначить в одной строке.

wire t_on_off = on  & (push);
wire t_off_on = off & (push);

Но если вы объединяете два всегда синхронизируемых блока в один, нет необходимости в отдельной логике, объединяя ответ @Tim с проверкой t_on_off:

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);

reg on;
reg off;

assign  led_on = on;

always @(posedge clk or posedge rst) begin
  if (rst) begin
    on  <= 1'b0;
    off <= 1'b1;
  end
  else if (off & push) begin
    on  <= 1'b1;
    off <= 1'b0;
  end
  else if (on  & push) begin
    on  <= 1'b0;
    off <= 1'b1;
  end
end

endmodule
person Morgan    schedule 31.05.2013

Это уже было далеко в прошлом, но представленные решения, возможно, не совсем то, что вы ожидали. Из того, что я мог сделать, все решения считают, что светодиод будет продолжать переключаться, пока нажата кнопка (т. Е. Он будет переключаться с тактовой частотой), что делает его визуально незаметным, если тактовая частота высока. Однако я предполагаю, что вам нужно что-то, что переключает светодиод только один раз при каждом нажатии кнопки, при этом состояние светодиода сохраняется в течение этого периода.

В приведенном ниже примере переключаются состояния 3 светодиодов в зависимости от активности 3 кнопок.

  1. led0 активируется всякий раз, когда нажимается pbutton0.
  2. led1 продолжает периодически переключаться (в зависимости от размера clk_div) и сбрасывается при каждом нажатии pbutton1.
  3. led2 переключается всякий раз, когда нажимается pbutton2.

Обратите внимание, что led0 является комбинационным, а два других светодиода — последовательными. Для переключения led2 необходимо сохранить предыдущее состояние pbutton2; всякий раз, когда pbutton2(t-1)==0 и pbutton2(t)==1, это означает, что кнопка только что перешла от низкого уровня к высокому, и, таким образом, состояние из led2 должны измениться.

Наконец, не обращайте внимания на источник тактового сигнала, так как он использовался только для демонстрации кода комплекта разработки Xilinx SP605.

////////////////////////////////////////////////////
// This project uses 3 pushbuttons and 3 LEDs.
//  pbutton0 activates led0
//  pbutton1 serves as reset for led1 periodic toggling
//  pbutton2 toggles led2
//
// The clock source (divider+buffer) was created using the clocking IP wizard.
//

module xilinx_sp605_board_leds
(
    input CLK_IN1_P,
    input CLK_IN1_N,

    input pbutton0,
    input pbutton1,
    input pbutton2,

    output led0,
    output reg led1,
    output reg led2
);

// declarations
wire clk;
wire reset = pbutton1;
reg [19:0] clk_div;
reg pbutton2_reg;

// led0 = state of pbutton0
assign led0 = pbutton0;

// differential clock divider+buffer
clk_source CLK_SOURCE (
    .CLK_IN1_P(CLK_IN1_P),
    .CLK_IN1_N(CLK_IN1_N),
    .CLK_OUT1(clk),
    .RESET(reset));

// led1, led2 toggling
always @(posedge reset or posedge clk)
begin
    if(reset)begin
        clk_div <= 0;
        led1 <= 0;

        pbutton2_reg <= 0;
        led2 <= 0;
    end else begin
        clk_div <= clk_div + 1;
        if(clk_div==0) 
            led1 <= ~led1;

        pbutton2_reg <= pbutton2;
        if(~pbutton2_reg && pbutton2)
            led2 <= ~led2;
    end
end

endmodule
person bupedroni    schedule 06.11.2015