This is the output of ISim simulation:
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
Best Answer
You can always create a new signal that represents the condition you want to test, such as:
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.