0
\$\begingroup\$

This is the output of ISim simulation:

ISim

I want to decrease tx_data_ctr by 1 when flags_from_clk_div turns to 4'b0000 so sda_flag_from_transmit_byte take initial bit from tx_data[7:0]. However, I could not find a way to do it. What I actually ask is if there is a way to set flag or do something else synchronously with the certain change of a register?

It is like @(reg_x == 4'b0001) - do_stuff but of course I know there is no such command.

Also, is one able to do stuff with posedge like when register change immediately execute something?

I use configurations like:

always @(posedge start) begin
  // stuff stuff
end

but can we apply something like this to a register has more than one byte? I hope I could explain.

edit: I added codes below:

scl_counter.v:

module scl_counter(
    input rst,
    input start,
    output reg [3:0] flags,
    input clk
);

parameter clk_divider = 0;

reg [15:0] scl_counter;

always @(posedge start) begin
    flags = 4'b0;
    scl_counter = 16'b0;
end  

always @(posedge clk) begin
    if (rst) begin
        flags = 4'b0;
        scl_counter = 16'b0;
    end
    else if (!rst) begin
        if (clk_divider != 1) begin
            if (scl_counter != (clk_divider*2)) begin
                scl_counter = scl_counter + 1;
                if (scl_counter == (clk_divider/2)) begin
                    flags[0] = 1'b1;
                end
                else if (scl_counter == (clk_divider*3/2)) begin
                    flags[1] = 1'b1;
                end
            end
            else if (scl_counter == (clk_divider*2)) begin
                scl_counter = 16'b0;
                flags = 4'b0;
            end
        end
        else if (clk_divider == 1) begin

        end
    end
end

endmodule

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

EDIT: Based on Dave Tweed's answer, I added the following code block and it works now. Is it right way to do it?

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
\$\endgroup\$
3
\$\begingroup\$

You can always create a new signal that represents the condition you want to test, such as:

wire x_is_one = (x == 1);

Then you can look for events on that signal.

However, basing a design on a lot of asynchronous events is a risky approach, very prone to error. Try to find a synchronous solution — one in which all of the logic is clocked by a common clock. This is especially true when working with FPGAs, for which both the hardware architecture and the software tools are strongly oriented toward synchronous designs.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer. 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 I added this code block and it works now. Is it right way to do it? \$\endgroup\$ – Alper91 Jan 3 '16 at 11:05
  • 2
    \$\begingroup\$ I took the liberty of adding the new code to your question as an edit so that I can read it. Yes, it's the right idea, but you have many other problems in your code. Specifically, you can't have assignments to the same signal in multiple always blocks -- it may work in simulation, but you will not be able to synthesize real logic based on it. \$\endgroup\$ – Dave Tweed Jan 3 '16 at 12:37
  • \$\begingroup\$ You mean like in different always blocks like: @(posedge clk) and @(negedge clk) or same always blocks (two @(posedge clk) )but coded seperately in the debugger? \$\endgroup\$ – Alper91 Jan 3 '16 at 13:20
  • 1
    \$\begingroup\$ @Alperözel a register can only be driven by exactly one always block, using exactly one clock edge. \$\endgroup\$ – Tom Carpenter Jan 3 '16 at 14:19
  • 1
    \$\begingroup\$ @Alperözel, IDE's don't want about about registers driven from two always blocks because it is legal non-synthesizable behavioral modeling; for example a model of a analog block. If you enable SystemVerilog and change always to always_ff for synchronous blocks (and always @* to always_comb` for combinational blocks) then the compiler will throw errors when two always blocks drive the same register. \$\endgroup\$ – Greg Jan 3 '16 at 15:58
1
\$\begingroup\$

Based on the updated code that you have posted I wanted to add some changes.

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

When you are @posedge of clock it is a good practice to use the non blocking operator(<=)

The else I have added after each if is to avoid creating a latch

Also try to replace the outer if else if logic I have used above with a case statement as it may end up producing better logic during synthesis

Finally try using a asynchronous reset in the clocking block to initialize all the variables.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.