Verilog: ¿cómo asignar sincrónicamente el cable con el registro?

0

Esta es la salida de la simulación ISim:

Quierodisminuirtx_data_ctren1cuandoflags_from_clk_divcambiea4'b0000,porloquesda_flag_from_transmit_bytetomaelbitinicialdetx_data[7:0].Sinembargo,nopudeencontrarunamaneradehacerlo.Loquerealmentepreguntoessihayunamaneradeestablecerunamarcaohaceralgomásdemanerasincrónicaconelcambiosegurodeunregistro?

Escomo@(reg_x==4'b0001)-do_stuffpero,porsupuesto,séquenoexistetalcomando.

También,¿alguienpuedehacercosasconposedgecomocuandouncambioderegistroejecutaalgodeinmediato?

Usoconfiguracionescomo:

always@(posedgestart)begin//stuffstuffend

pero,¿podemosaplicaralgocomoestoaunregistroquetengamásdeunbyte?Esperopoderexplicarlo.

editar:heañadidoloscódigosacontinuación:

scl_counter.v:

modulescl_counter(inputrst,inputstart,outputreg[3:0]flags,inputclk);parameterclk_divider=0;reg[15:0]scl_counter;always@(posedgestart)beginflags=4'b0;scl_counter=16'b0;endalways@(posedgeclk)beginif(rst)beginflags=4'b0;scl_counter=16'b0;endelseif(!rst)beginif(clk_divider!=1)beginif(scl_counter!=(clk_divider*2))beginscl_counter=scl_counter+1;if(scl_counter==(clk_divider/2))beginflags[0]=1'b1;endelseif(scl_counter==(clk_divider*3/2))beginflags[1]=1'b1;endendelseif(scl_counter==(clk_divider*2))beginscl_counter=16'b0;flags=4'b0;endendelseif(clk_divider==1)beginendendendendmodule

transmit_byte.v:

'include"scl_counter.v"
module transmit_byte(
        output reg [0:0] sda_flag_from_transmit_byte,
        input [7:0] tx_data,
        output reg [7:0] rx_data,
        input clk,
        output reg [0:0] scl_flag_from_transmit_byte,
        input start_scl_div,
        output reg [0:0] reset_to_clk_div,
        input [3:0] flags_from_clk_div,
        output reg [2:0] tx_data_ctr

);

reg [2:0] rx_data_ctr;
reg [0:0] ready_to_start_flag;
reg [0:0] resetter_flag_clk_div;

always @(posedge start_scl_div) begin
    scl_flag_from_transmit_byte = 1'b0;
    ready_to_start_flag = 1'b0;
    resetter_flag_clk_div = 1'b0;
    tx_data_ctr = 3'b111;
    rx_data_ctr = 3'b0;
    ready_to_start_flag = #1 1'b1;

end

always @(negedge clk) 

begin: RESETTER_TO_CLK_DIV

    if (ready_to_start_flag) begin
        if (start_scl_div) begin
            if (resetter_flag_clk_div == 1'b1) begin
                reset_to_clk_div = 1'b0;
            end
            else if (resetter_flag_clk_div == 1'b0) begin
                reset_to_clk_div = 1'b1;
                resetter_flag_clk_div = 1'b1;
            end
        end
    end

end



always @(posedge clk) begin
    if (start_scl_div) begin
        if (ready_to_start_flag) begin
            if (flags_from_clk_div == 4'b0) begin
                sda_flag_from_transmit_byte = tx_data[tx_data_ctr];
            end
            else if (flags_from_clk_div == 4'b0001) begin
                scl_flag_from_transmit_byte = 1'b1;
            end
            else if (flags_from_clk_div != 4'b0001) begin
                scl_flag_from_transmit_byte = 1'b0;
            end
        end
    end
end

always @(negedge start_scl_div) begin
    ready_to_start_flag = 1'b0;
    resetter_flag_clk_div = 1'b0;
end
//b01100100
scl_counter #(16'b00001000) c_1(
    .rst    (reset_to_clk_div),
    .start  (start_scl_div),
    .flags  (flags_from_clk_div),
    .clk    (clk)
);

endmodule

timer_A.v:

module timer_A(
    input clk,   // which clock?
    input rst,   // sets to 0 or up counter
    //output [7:0] flags_timer_A,   // sets flag when counts to the value
    input mode,   // if mode 0, counts up to A only flags A, if 1 counts to
                        // A and B, C, D ... flags if they are not 0.
    input [15:0] count_to_A,  // counts to first value
    input [15:0] count_to_B,  // counts to second value
    input count_to_C,
    input count_to_D,
    input count_to_E,
    input count_to_F,
    input count_to_G,
    input count_to_H,
    output reg [7:0] flags_timer_A
);

reg [15:0] timer_A_Reg;

//reg [7:0] flags_timer_A;

/*
timer_A_flag_A  = flags_timer_A[0]

timer_A_flag_B  = flags_timer_A[1]

timer_A_flag_C  = flags_timer_A[2]

timer_A_flag_D  = flags_timer_A[3] ...
*/


always @(posedge rst) begin
    flags_timer_A = 8'b0;
    timer_A_Reg = 16'b0;
end

always @(posedge clk) begin
    if (rst) begin
        flags_timer_A = 8'b0;
        timer_A_Reg = 16'b0;
    end
    else if (!rst) begin
        if (mode == 1'b0) begin
            if (timer_A_Reg != count_to_A) begin
                timer_A_Reg <= timer_A_Reg + 1;
            end
            else begin
                flags_timer_A[0] <= 1'b1;
            end
        end
        else begin
            if (timer_A_Reg != count_to_A) begin
                timer_A_Reg = timer_A_Reg + 1;
                if (timer_A_Reg == count_to_B) begin
                    flags_timer_A[1] = 1'b1;
                end
                else if (timer_A_Reg == count_to_C) begin
                    flags_timer_A[2] = 1'b1;
                end
                else if (timer_A_Reg == count_to_D) begin
                    flags_timer_A[3] = 1'b1;
                end
                else if (timer_A_Reg == count_to_E) begin
                    flags_timer_A[4] = 1'b1;
                end
                else if (timer_A_Reg == count_to_F) begin
                    flags_timer_A[5] = 1'b1;
                end
                else if (timer_A_Reg == count_to_G) begin
                    flags_timer_A[6] = 1'b1;
                end
                else if (timer_A_Reg == count_to_H) begin
                    flags_timer_A[7] = 1'b1;
                end
            end
            else begin
                flags_timer_A[0] <= 1'b1;
            end
        end
    end
end


endmodule

start_i2c.v:

    'include "timer_A.v"
    module start_i2c(
            input start,
            input [7:0] flags_timer_A,
            input clk,
            output reg [0:0] rst_to_tmr,
            output reg [0:0] start_done,
            output reg [0:0] scl_flag_from_start_i2c,
            output reg [0:0] sda_flag_from_start_i2c
    );

    reg [0:0] resetter_flag;
    reg [0:0] mode_to_tmr;
    /*
    timer_A_flag_A  = flags[0]

    timer_A_flag_B  = flags[1]

    timer_A_flag_C  = flags[2]

    timer_A_flag_D  = flags[3] ...
    */

    always @(posedge start) begin
        resetter_flag <= 1'b0;
        mode_to_tmr <= 1'b1;
        start_done <= 1'b0;
        scl_flag_from_start_i2c <= 1'b1;
        sda_flag_from_start_i2c <= 1'b1;
    end

    parameter min_SDA_on_time = 0;  
    parameter min_SDA_SCL_fall_delay = 0;

    always @(negedge clk)
    begin: RESETTER    // this resets up when start is on immediately
        if (start && !resetter_flag) begin
            rst_to_tmr = 1'b1;
            resetter_flag = 1'b1;
        end
        else if (start && resetter_flag) begin
            rst_to_tmr <= 1'b0;
        end
    end

    always @(posedge clk) begin
        if (start) begin
            if (flags_timer_A[1]) begin
                sda_flag_from_start_i2c <= 1'b0;
            end
            if (flags_timer_A[0]) begin
                scl_flag_from_start_i2c <= 1'b0;
                start_done <= 1'b1;
            end
        end
        else begin

        end
    end

    always @(negedge start) begin
        resetter_flag = 1'b0;
        //start_done <= 1'b0;
    end

    timer_A  start_timer(
        .clk             (clk),   // which clock?
        .rst             (rst_to_tmr),   // sets to 0 or up counter
        .mode     (mode_to_tmr),   // if mode 0, counts up to A only flags A, if 1 counts to
                                            // A and B, C, D ... flags if they are not 0.
        .count_to_A      (min_SDA_on_time + min_SDA_SCL_fall_delay),  // counts to first value
        .count_to_B      (min_SDA_on_time),  // counts to second value
        .count_to_C      (16'b0),
        .count_to_D      (16'b0),
        .count_to_E      (16'b0),
        .count_to_F      (16'b0),
        .count_to_G      (16'b0),
        .count_to_H      (16'b0),
        .flags_timer_A   (flags_timer_A)  // sets flag when counts to the value
    );

    endmodule

**start_i2c_tb.v:**

'include "start_i2c.v"
'include "transmit_byte.v"

module start_i2c_tb(
    );

//defparam start_test.min_SDA_on_time = 16'b11001000;

//defparam start_test.min_SDA_SCL_fall_delay = 16'b01100100; 

reg [0:0] start_start_i2c;

reg [0:0] start_scl_div;

reg [7:0] tx_data;

wire [7:0] flags_timer_A;

reg [0:0] clk;

wire sda_flag_from_transmit_byte;

wire scl_flag_from_transmit_byte;

wire scl_flag_from_start_i2c;

wire sda_flag_from_start_i2c;

wire [3:0] flags_from_clk_div;

wire [2:0] tx_data_ctr;

initial begin

    clk = 1'b0;
    start_scl_div = 1'b0;
    start_start_i2c = 1'b0;
    #5 start_start_i2c = 1'b1;
    tx_data = 8'b10101010;
    #40000 $finish;

end

always begin
    #1 clk = ~ clk;
end

always @(clk) begin
    if (start_done && start_start_i2c) begin
        start_start_i2c = 1'b0;
    end
    else if (start_done && !start_start_i2c) begin
        start_start_i2c = 1'b0;
        start_scl_div = 1'b1;
    end
end

start_i2c #(16'b11001000, 16'b01100100) start_test(
        .start          (start_start_i2c),
        .flags_timer_A  (flags_timer_A),
        .clk            (clk),
        .rst_to_tmr     (rst_to_tmr),
        .start_done     (start_done),
        .scl_flag_from_start_i2c            (scl_flag_from_start_i2c),
        .sda_flag_from_start_i2c            (sda_flag_from_start_i2c)
);

transmit_byte start_transmit(
        .sda_flag_from_transmit_byte       (sda_flag_from_transmit_byte),
        .tx_data   (tx_data),
        .rx_data   (rx_data),
        .clk       (clk),
        .scl_flag_from_transmit_byte       (scl_flag_from_transmit_byte),
        .start_scl_div   (start_scl_div),
        .reset_to_clk_div  (reset_to_clk_div),
        .flags_from_clk_div  (flags_from_clk_div),
        .tx_data_ctr   (tx_data_ctr)

);

endmodule

EDITAR: Basado en la respuesta de Dave Tweed, agregué el siguiente bloque de código y ahora funciona. ¿Es la forma correcta de hacerlo?

always @(posedge clk) begin
    if (flags_from_clk_div == 4'b0) begin
        if (tx_check) begin
            tx_data_ctr = tx_data_ctr + 1;
            tx_check = 1'b0;
        end
    end
    if (flags_from_clk_div == 4'b0011) begin
        tx_check = 1'b1;
    end
end
    
pregunta Alper91

2 respuestas

3

Siempre puede crear una nueva señal que represente la condición que desea probar, como:

wire x_is_one = (x == 1);

Luego puedes buscar eventos en esa señal.

Sin embargo, basar un diseño en muchos eventos asíncronos es un enfoque riesgoso, muy propenso a errores. Intente encontrar una solución síncrona, una en la que toda la lógica esté sincronizada con un reloj común. Esto es especialmente cierto cuando se trabaja con FPGA, para los cuales tanto la arquitectura de hardware como las herramientas de software están fuertemente orientadas hacia diseños sincrónicos.

    
respondido por el Dave Tweed
1

Según el código actualizado que ha publicado, quería agregar algunos cambios.

always @(posedge clk) begin
  if (flags_from_clk_div == 4'b0000) begin
      if (tx_check) begin
          tx_data_ctr <= tx_data_ctr + 1;
          tx_check <= 1'b0;
      end else begin
          // do something here
      end          
  end else if (flags_from_clk_div == 4'b0011) begin
      tx_check <= 1'b1;
  end else begin
      // do something here
  end
end

Cuando tenga una cuenta de reloj, es una buena práctica utilizar el operador sin bloqueo (< =)

La otra cosa que he agregado después de cada uno es evitar crear un pestillo

También intente reemplazar el externo, si no, si la lógica que he usado anteriormente con una declaración de caso, ya que puede terminar produciendo una mejor lógica durante la síntesis

Finalmente, intente usar un reinicio asíncrono en el bloque de sincronización para inicializar todas las variables.

    
respondido por el DBB

Lea otras preguntas en las etiquetas