From 904c6dc6e0c9100c0970619a05f35f36c34ef09a Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Fri, 28 Jun 2024 19:09:42 +0200 Subject: [PATCH 01/47] saving --- rtl/i2c_master.v | 279 ++++------------------------------------ rtl/i2c_phy.v | 326 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+), 252 deletions(-) create mode 100644 rtl/i2c_phy.v diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 9c69b48..669cff8 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -216,7 +216,7 @@ localparam [4:0] PHY_STATE_STOP_2 = 5'd14, PHY_STATE_STOP_3 = 5'd15; -reg [4:0] phy_state_reg = STATE_IDLE, phy_state_next; +reg [4:0] phy_state_reg = STATE_IDLE; reg phy_start_bit; reg phy_stop_bit; @@ -236,9 +236,6 @@ reg mode_read_reg = 1'b0, mode_read_next; reg mode_write_multiple_reg = 1'b0, mode_write_multiple_next; reg mode_stop_reg = 1'b0, mode_stop_next; -reg [16:0] delay_reg = 16'd0, delay_next; -reg delay_scl_reg = 1'b0, delay_scl_next; -reg delay_sda_reg = 1'b0, delay_sda_next; reg [3:0] bit_count_reg = 4'd0, bit_count_next; @@ -260,8 +257,8 @@ reg last_scl_i_reg = 1'b1; reg last_sda_i_reg = 1'b1; reg busy_reg = 1'b0; -reg bus_active_reg = 1'b0; -reg bus_control_reg = 1'b0, bus_control_next; +//reg bus_active_reg = 1'b0; +//reg bus_control_reg = 1'b0, bus_control_next; reg missed_ack_reg = 1'b0, missed_ack_next; assign s_axis_cmd_ready = s_axis_cmd_ready_reg; @@ -279,7 +276,7 @@ assign sda_t = sda_o_reg; assign busy = busy_reg; assign bus_active = bus_active_reg; -assign bus_control = bus_control_reg; +//assign bus_control = bus_control_reg; assign missed_ack = missed_ack_reg; wire scl_posedge = scl_i_reg & ~last_scl_i_reg; @@ -596,241 +593,32 @@ always @* begin end end -always @* begin - phy_state_next = PHY_STATE_IDLE; - - phy_rx_data_next = phy_rx_data_reg; - - delay_next = delay_reg; - delay_scl_next = delay_scl_reg; - delay_sda_next = delay_sda_reg; - - scl_o_next = scl_o_reg; - sda_o_next = sda_o_reg; - - bus_control_next = bus_control_reg; - - if (phy_release_bus) begin - // release bus and return to idle state - sda_o_next = 1'b1; - scl_o_next = 1'b1; - delay_scl_next = 1'b0; - delay_sda_next = 1'b0; - delay_next = 1'b0; - phy_state_next = PHY_STATE_IDLE; - end else if (delay_scl_reg) begin - // wait for SCL to match command - delay_scl_next = scl_o_reg & ~scl_i_reg; - phy_state_next = phy_state_reg; - end else if (delay_sda_reg) begin - // wait for SDA to match command - delay_sda_next = sda_o_reg & ~sda_i_reg; - phy_state_next = phy_state_reg; - end else if (delay_reg > 0) begin - // time delay - delay_next = delay_reg - 1; - phy_state_next = phy_state_reg; - end else begin - case (phy_state_reg) - PHY_STATE_IDLE: begin - // bus idle - wait for start command - sda_o_next = 1'b1; - scl_o_next = 1'b1; - if (phy_start_bit) begin - sda_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_START_1; - end else begin - phy_state_next = PHY_STATE_IDLE; - end - end - PHY_STATE_ACTIVE: begin - // bus active - if (phy_start_bit) begin - sda_o_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_REPEATED_START_1; - end else if (phy_write_bit) begin - sda_o_next = phy_tx_data; - delay_next = prescale; - phy_state_next = PHY_STATE_WRITE_BIT_1; - end else if (phy_read_bit) begin - sda_o_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_1; - end else if (phy_stop_bit) begin - sda_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_STOP_1; - end else begin - phy_state_next = PHY_STATE_ACTIVE; - end - end - PHY_STATE_REPEATED_START_1: begin - // generate repeated start bit - // ______ - // sda XXX/ \_______ - // _______ - // scl ______/ \___ - // - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_REPEATED_START_2; - end - PHY_STATE_REPEATED_START_2: begin - // generate repeated start bit - // ______ - // sda XXX/ \_______ - // _______ - // scl ______/ \___ - // - - sda_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_START_1; - end - PHY_STATE_START_1: begin - // generate start bit - // ___ - // sda \_______ - // _______ - // scl \___ - // - - scl_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_START_2; - end - PHY_STATE_START_2: begin - // generate start bit - // ___ - // sda \_______ - // _______ - // scl \___ - // - - bus_control_next = 1'b1; - phy_state_next = PHY_STATE_ACTIVE; - end - PHY_STATE_WRITE_BIT_1: begin - // write bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale << 1; - phy_state_next = PHY_STATE_WRITE_BIT_2; - end - PHY_STATE_WRITE_BIT_2: begin - // write bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_WRITE_BIT_3; - end - PHY_STATE_WRITE_BIT_3: begin - // write bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - phy_state_next = PHY_STATE_ACTIVE; - end - PHY_STATE_READ_BIT_1: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_2; - end - PHY_STATE_READ_BIT_2: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - phy_rx_data_next = sda_i_reg; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_3; - end - PHY_STATE_READ_BIT_3: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_4; - end - PHY_STATE_READ_BIT_4: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - phy_state_next = PHY_STATE_ACTIVE; - end - PHY_STATE_STOP_1: begin - // stop bit - // ___ - // sda XXX\_______/ - // _______ - // scl _______/ - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_STOP_2; - end - PHY_STATE_STOP_2: begin - // stop bit - // ___ - // sda XXX\_______/ - // _______ - // scl _______/ - - sda_o_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_STOP_3; - end - PHY_STATE_STOP_3: begin - // stop bit - // ___ - // sda XXX\_______/ - // _______ - // scl _______/ - - bus_control_next = 1'b0; - phy_state_next = PHY_STATE_IDLE; - end - endcase - end -end +i2c_phy phy_instance ( + // Control signals + .phy_start_bit(phy_start_bit), + .phy_stop_bit(phy_stop_bit), + .phy_write_bit(phy_write_bit), + .phy_read_bit(phy_read_bit), + .phy_tx_data(phy_tx_data), + .phy_release_bus(phy_release_bus), + + // I2C interface + .scl_i_reg, + .scl_o_reg, + .sda_i_reg, + .sda_o_reg, + + // Status and data + .phy_busy(phy_busy), + .bus_control_reg, + .phy_rx_data_reg, + + // Configuration + .prescale(prescale) +); always @(posedge clk) begin state_reg <= state_next; - phy_state_reg <= phy_state_next; - - phy_rx_data_reg <= phy_rx_data_next; addr_reg <= addr_next; data_reg <= data_next; @@ -840,9 +628,6 @@ always @(posedge clk) begin mode_write_multiple_reg <= mode_write_multiple_next; mode_stop_reg <= mode_stop_next; - delay_reg <= delay_next; - delay_scl_reg <= delay_scl_next; - delay_sda_reg <= delay_sda_next; bit_count_reg <= bit_count_next; @@ -857,8 +642,6 @@ always @(posedge clk) begin scl_i_reg <= scl_i; sda_i_reg <= sda_i; - scl_o_reg <= scl_o_next; - sda_o_reg <= sda_o_next; last_scl_i_reg <= scl_i_reg; last_sda_i_reg <= sda_i_reg; @@ -873,22 +656,14 @@ always @(posedge clk) begin bus_active_reg <= bus_active_reg; end - bus_control_reg <= bus_control_next; missed_ack_reg <= missed_ack_next; if (rst) begin state_reg <= STATE_IDLE; - phy_state_reg <= PHY_STATE_IDLE; - delay_reg <= 16'd0; - delay_scl_reg <= 1'b0; - delay_sda_reg <= 1'b0; s_axis_cmd_ready_reg <= 1'b0; s_axis_data_tready_reg <= 1'b0; m_axis_data_tvalid_reg <= 1'b0; - scl_o_reg <= 1'b1; - sda_o_reg <= 1'b1; busy_reg <= 1'b0; - bus_active_reg <= 1'b0; bus_control_reg <= 1'b0; missed_ack_reg <= 1'b0; end diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v new file mode 100644 index 0000000..a914f6f --- /dev/null +++ b/rtl/i2c_phy.v @@ -0,0 +1,326 @@ +module i2c_phy ( + input wire clk, + input wire rst, + + // Control signals + input wire phy_start_bit, + input wire phy_stop_bit, + input wire phy_write_bit, + input wire phy_read_bit, + input wire phy_tx_data, + input wire phy_release_bus, + + // I2C interface + input wire scl_i_reg, + output reg scl_o_reg, + input wire sda_i_reg, + output reg sda_o_reg, + + // Status and data + output wire phy_busy, + output reg bus_control_reg, + output reg phy_rx_data_reg, + + // Configuration + input wire [15:0] prescale +); + localparam [4:0] + PHY_STATE_IDLE = 5'd0, + PHY_STATE_ACTIVE = 5'd1, + PHY_STATE_REPEATED_START_1 = 5'd2, + PHY_STATE_REPEATED_START_2 = 5'd3, + PHY_STATE_START_1 = 5'd4, + PHY_STATE_START_2 = 5'd5, + PHY_STATE_WRITE_BIT_1 = 5'd6, + PHY_STATE_WRITE_BIT_2 = 5'd7, + PHY_STATE_WRITE_BIT_3 = 5'd8, + PHY_STATE_READ_BIT_1 = 5'd9, + PHY_STATE_READ_BIT_2 = 5'd10, + PHY_STATE_READ_BIT_3 = 5'd11, + PHY_STATE_READ_BIT_4 = 5'd12, + PHY_STATE_STOP_1 = 5'd13, + PHY_STATE_STOP_2 = 5'd14, + PHY_STATE_STOP_3 = 5'd15; + + + + // Internal registers + + + reg phy_rx_data_reg = 1'b0, phy_rx_data_next; + +reg [4:0] phy_state_reg = STATE_IDLE, phy_state_next; + +reg [16:0] delay_reg = 16'd0, delay_next; + reg delay_scl_reg = 1'b0, delay_scl_next; + reg delay_sda_reg = 1'b0, delay_sda_next; + + reg scl_o_reg = 1'b1, scl_o_next; + reg sda_o_reg = 1'b1, sda_o_next; + + reg bus_control_reg = 1'b0, bus_control_next; + + always @* begin + phy_state_next = PHY_STATE_IDLE; + + phy_rx_data_next = phy_rx_data_reg; + + delay_next = delay_reg; + delay_scl_next = delay_scl_reg; + delay_sda_next = delay_sda_reg; + + scl_o_next = scl_o_reg; + sda_o_next = sda_o_reg; + + bus_control_next = bus_control_reg; + + if (phy_release_bus) begin + // release bus and return to idle state + sda_o_next = 1'b1; + scl_o_next = 1'b1; + delay_scl_next = 1'b0; + delay_sda_next = 1'b0; + delay_next = 1'b0; + phy_state_next = PHY_STATE_IDLE; + end else if (delay_scl_reg) begin + // wait for SCL to match command + delay_scl_next = scl_o_reg & ~scl_i_reg; + phy_state_next = phy_state_reg; + end else if (delay_sda_reg) begin + // wait for SDA to match command + delay_sda_next = sda_o_reg & ~sda_i_reg; + phy_state_next = phy_state_reg; + end else if (delay_reg > 0) begin + // time delay + delay_next = delay_reg - 1; + phy_state_next = phy_state_reg; + end else begin + case (phy_state_reg) + PHY_STATE_IDLE: begin + // bus idle - wait for start command + sda_o_next = 1'b1; + scl_o_next = 1'b1; + if (phy_start_bit) begin + sda_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_START_1; + end else begin + phy_state_next = PHY_STATE_IDLE; + end + end + PHY_STATE_ACTIVE: begin + // bus active + if (phy_start_bit) begin + sda_o_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_REPEATED_START_1; + end else if (phy_write_bit) begin + sda_o_next = phy_tx_data; + delay_next = prescale; + phy_state_next = PHY_STATE_WRITE_BIT_1; + end else if (phy_read_bit) begin + sda_o_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_1; + end else if (phy_stop_bit) begin + sda_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_STOP_1; + end else begin + phy_state_next = PHY_STATE_ACTIVE; + end + end + PHY_STATE_REPEATED_START_1: begin + // generate repeated start bit + // ______ + // sda XXX/ \_______ + // _______ + // scl ______/ \___ + // + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_REPEATED_START_2; + end + PHY_STATE_REPEATED_START_2: begin + // generate repeated start bit + // ______ + // sda XXX/ \_______ + // _______ + // scl ______/ \___ + // + + sda_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_START_1; + end + PHY_STATE_START_1: begin + // generate start bit + // ___ + // sda \_______ + // _______ + // scl \___ + // + + scl_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_START_2; + end + PHY_STATE_START_2: begin + // generate start bit + // ___ + // sda \_______ + // _______ + // scl \___ + // + + bus_control_next = 1'b1; + phy_state_next = PHY_STATE_ACTIVE; + end + PHY_STATE_WRITE_BIT_1: begin + // write bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale << 1; + phy_state_next = PHY_STATE_WRITE_BIT_2; + end + PHY_STATE_WRITE_BIT_2: begin + // write bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_WRITE_BIT_3; + end + PHY_STATE_WRITE_BIT_3: begin + // write bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + phy_state_next = PHY_STATE_ACTIVE; + end + PHY_STATE_READ_BIT_1: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_2; + end + PHY_STATE_READ_BIT_2: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + phy_rx_data_next = sda_i_reg; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_3; + end + PHY_STATE_READ_BIT_3: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_4; + end + PHY_STATE_READ_BIT_4: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + phy_state_next = PHY_STATE_ACTIVE; + end + PHY_STATE_STOP_1: begin + // stop bit + // ___ + // sda XXX\_______/ + // _______ + // scl _______/ + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_STOP_2; + end + PHY_STATE_STOP_2: begin + // stop bit + // ___ + // sda XXX\_______/ + // _______ + // scl _______/ + + sda_o_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_STOP_3; + end + PHY_STATE_STOP_3: begin + // stop bit + // ___ + // sda XXX\_______/ + // _______ + // scl _______/ + + bus_control_next = 1'b0; + phy_state_next = PHY_STATE_IDLE; + end + endcase + end + end + + +always @(posedge clk) begin + phy_state_reg <= phy_state_next; + + phy_rx_data_reg <= phy_rx_data_next; + + + delay_reg <= delay_next; + delay_scl_reg <= delay_scl_next; + delay_sda_reg <= delay_sda_next; + + + scl_i_reg <= scl_i; + sda_i_reg <= sda_i; + + scl_o_reg <= scl_o_next; + sda_o_reg <= sda_o_next; + + bus_control_reg <= bus_control_next; + + if (rst) begin + phy_state_reg <= PHY_STATE_IDLE; + delay_reg <= 16'd0; + delay_scl_reg <= 1'b0; + delay_sda_reg <= 1'b0; + scl_o_reg <= 1'b1; + sda_o_reg <= 1'b1; + bus_control_reg <= 1'b0; + end +end + + + +endmodule From c5722a2bf7eb433ef68e14682855a2a5cc8957cc Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Fri, 28 Jun 2024 20:51:15 +0200 Subject: [PATCH 02/47] Refactored I2C PHY module for improved readability and maintainability. --- rtl/i2c_phy.v | 65 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index a914f6f..f5072e1 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -1,6 +1,8 @@ + +`timescale 1ns / 1ps module i2c_phy ( - input wire clk, - input wire rst, + input wire clk, + input wire rst, // Control signals input wire phy_start_bit, @@ -11,15 +13,18 @@ module i2c_phy ( input wire phy_release_bus, // I2C interface - input wire scl_i_reg, - output reg scl_o_reg, - input wire sda_i_reg, - output reg sda_o_reg, + input wire scl_i, + output wire scl_o, + input wire sda_i, + output wire sda_o, + output wire sda_t, + output wire scl_t, // Status and data output wire phy_busy, - output reg bus_control_reg, - output reg phy_rx_data_reg, + output reg bus_control_reg, + output reg phy_rx_data_reg, + output reg [4:0] phy_state_reg, // Configuration input wire [15:0] prescale @@ -46,19 +51,30 @@ module i2c_phy ( // Internal registers + reg scl_o_reg; + reg scl_i_reg; + reg sda_i_reg; + reg sda_o_reg; + - reg phy_rx_data_reg = 1'b0, phy_rx_data_next; + reg phy_rx_data_next; -reg [4:0] phy_state_reg = STATE_IDLE, phy_state_next; + reg [4:0] phy_state_next; -reg [16:0] delay_reg = 16'd0, delay_next; + reg [16:0] delay_reg = 16'd0, delay_next; reg delay_scl_reg = 1'b0, delay_scl_next; reg delay_sda_reg = 1'b0, delay_sda_next; - reg scl_o_reg = 1'b1, scl_o_next; - reg sda_o_reg = 1'b1, sda_o_next; + reg scl_o_next; + reg sda_o_next; + + reg bus_control_next; + + assign scl_o = scl_o_reg; + assign scl_t = scl_o_reg; + assign sda_o = sda_o_reg; + assign sda_t = sda_o_reg; - reg bus_control_reg = 1'b0, bus_control_next; always @* begin phy_state_next = PHY_STATE_IDLE; @@ -97,10 +113,12 @@ reg [16:0] delay_reg = 16'd0, delay_next; end else begin case (phy_state_reg) PHY_STATE_IDLE: begin + $display("idle, simply wait"); // bus idle - wait for start command sda_o_next = 1'b1; scl_o_next = 1'b1; if (phy_start_bit) begin + $display("idle, "); sda_o_next = 1'b0; delay_next = prescale; phy_state_next = PHY_STATE_START_1; @@ -291,7 +309,7 @@ reg [16:0] delay_reg = 16'd0, delay_next; end -always @(posedge clk) begin + always @(posedge clk) begin phy_state_reg <= phy_state_next; phy_rx_data_reg <= phy_rx_data_next; @@ -311,15 +329,16 @@ always @(posedge clk) begin bus_control_reg <= bus_control_next; if (rst) begin - phy_state_reg <= PHY_STATE_IDLE; - delay_reg <= 16'd0; - delay_scl_reg <= 1'b0; - delay_sda_reg <= 1'b0; - scl_o_reg <= 1'b1; - sda_o_reg <= 1'b1; - bus_control_reg <= 1'b0; + phy_rx_data_reg <= 1'b0; + phy_state_reg <= PHY_STATE_IDLE; + delay_reg <= 16'd0; + delay_scl_reg <= 1'b0; + delay_sda_reg <= 1'b0; + scl_o_reg <= 1'b1; + sda_o_reg <= 1'b1; + bus_control_reg <= 1'b0; end -end + end From da896a270b9e4bbfcad1fbe53f013f5a0c82e56e Mon Sep 17 00:00:00 2001 From: "Kreijstal (aider)" Date: Fri, 28 Jun 2024 20:51:16 +0200 Subject: [PATCH 03/47] Set default value for `phy_busy` and update delay register width to 17 bits. --- rtl/i2c_phy.v | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index f5072e1..f588c9f 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -21,7 +21,7 @@ module i2c_phy ( output wire scl_t, // Status and data - output wire phy_busy, + output wire phy_busy = 1'b0, output reg bus_control_reg, output reg phy_rx_data_reg, output reg [4:0] phy_state_reg, @@ -61,7 +61,7 @@ module i2c_phy ( reg [4:0] phy_state_next; - reg [16:0] delay_reg = 16'd0, delay_next; + reg [16:0] delay_reg = 17'd0, delay_next; reg delay_scl_reg = 1'b0, delay_scl_next; reg delay_sda_reg = 1'b0, delay_sda_next; @@ -96,7 +96,7 @@ module i2c_phy ( scl_o_next = 1'b1; delay_scl_next = 1'b0; delay_sda_next = 1'b0; - delay_next = 1'b0; + delay_next = 17'd0; phy_state_next = PHY_STATE_IDLE; end else if (delay_scl_reg) begin // wait for SCL to match command @@ -120,7 +120,7 @@ module i2c_phy ( if (phy_start_bit) begin $display("idle, "); sda_o_next = 1'b0; - delay_next = prescale; + delay_next = {1'b0, prescale}; phy_state_next = PHY_STATE_START_1; end else begin phy_state_next = PHY_STATE_IDLE; @@ -205,7 +205,7 @@ module i2c_phy ( scl_o_next = 1'b1; delay_scl_next = 1'b1; - delay_next = prescale << 1; + delay_next = {1'b0, prescale} << 1; phy_state_next = PHY_STATE_WRITE_BIT_2; end PHY_STATE_WRITE_BIT_2: begin @@ -304,6 +304,9 @@ module i2c_phy ( bus_control_next = 1'b0; phy_state_next = PHY_STATE_IDLE; end + default: begin + phy_state_next = PHY_STATE_IDLE; + end endcase end end From ba5610bcf43f414713ca8ba4142b1916c6744dbd Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 29 Jun 2024 00:45:22 +0200 Subject: [PATCH 04/47] creating testbench --- .gitignore | 1 + rtl/i2c_phy.v | 17 +++--- rtl/i2c_phy_tb.sv | 144 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 rtl/i2c_phy_tb.sv diff --git a/.gitignore b/.gitignore index 964df4d..4ea44bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.vvp *.kate-swp +.aider* diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index f588c9f..68a8173 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -21,13 +21,13 @@ module i2c_phy ( output wire scl_t, // Status and data - output wire phy_busy = 1'b0, + output reg phy_busy = 1'b0, output reg bus_control_reg, output reg phy_rx_data_reg, output reg [4:0] phy_state_reg, // Configuration - input wire [15:0] prescale + input wire [16:0] prescale ); localparam [4:0] PHY_STATE_IDLE = 5'd0, @@ -113,14 +113,14 @@ module i2c_phy ( end else begin case (phy_state_reg) PHY_STATE_IDLE: begin - $display("idle, simply wait"); + //$display("idle, simply wait"); // bus idle - wait for start command sda_o_next = 1'b1; scl_o_next = 1'b1; if (phy_start_bit) begin - $display("idle, "); + //$display("idle, "); sda_o_next = 1'b0; - delay_next = {1'b0, prescale}; + delay_next = prescale; phy_state_next = PHY_STATE_START_1; end else begin phy_state_next = PHY_STATE_IDLE; @@ -129,6 +129,8 @@ module i2c_phy ( PHY_STATE_ACTIVE: begin // bus active if (phy_start_bit) begin + $display("start bit should have reset"); + sda_o_next = 1'b1; delay_next = prescale; phy_state_next = PHY_STATE_REPEATED_START_1; @@ -145,6 +147,7 @@ module i2c_phy ( delay_next = prescale; phy_state_next = PHY_STATE_STOP_1; end else begin + $display("Do nothing, leave things as is"); phy_state_next = PHY_STATE_ACTIVE; end end @@ -205,7 +208,7 @@ module i2c_phy ( scl_o_next = 1'b1; delay_scl_next = 1'b1; - delay_next = {1'b0, prescale} << 1; + delay_next = prescale << 1; phy_state_next = PHY_STATE_WRITE_BIT_2; end PHY_STATE_WRITE_BIT_2: begin @@ -334,7 +337,7 @@ module i2c_phy ( if (rst) begin phy_rx_data_reg <= 1'b0; phy_state_reg <= PHY_STATE_IDLE; - delay_reg <= 16'd0; + delay_reg <= 17'd0; delay_scl_reg <= 1'b0; delay_sda_reg <= 1'b0; scl_o_reg <= 1'b1; diff --git a/rtl/i2c_phy_tb.sv b/rtl/i2c_phy_tb.sv new file mode 100644 index 0000000..12ccabe --- /dev/null +++ b/rtl/i2c_phy_tb.sv @@ -0,0 +1,144 @@ +`timescale 1ns / 1ps + +module i2c_phy_tb; + + // Parameters + parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) + + // Signals + reg clk = 0; + reg rst = 0; + reg phy_start_bit = 0; + reg phy_stop_bit = 0; + reg phy_write_bit = 0; + reg phy_read_bit = 0; + reg phy_tx_data = 0; + reg phy_release_bus = 0; + wire scl_i = 1; + wire scl_o; + wire sda_i = 1; + wire sda_o; + wire sda_t; + wire scl_t; + wire phy_busy; + wire bus_control_reg; + wire phy_rx_data_reg; + wire [4:0] phy_state_reg; + + // Clock generation + always #(CLK_PERIOD/2) clk <= ~clk; + + // Instantiate the i2c_phy module + i2c_phy uut ( + .clk(clk), + .rst(rst), + .phy_start_bit(phy_start_bit), + .phy_stop_bit(phy_stop_bit), + .phy_write_bit(phy_write_bit), + .phy_read_bit(phy_read_bit), + .phy_tx_data(phy_tx_data), + .phy_release_bus(phy_release_bus), + .scl_i(scl_i), + .scl_o(scl_o), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .scl_t(scl_t), + .phy_busy(phy_busy), + .bus_control_reg(bus_control_reg), + .phy_rx_data_reg(phy_rx_data_reg), + .phy_state_reg(phy_state_reg), + .prescale(17'd3) + ); + + // Simulate I2C bus behavior + //always @(posedge clk) begin + // if (!scl_t) scl_i <= scl_o; + // if (!sda_t) sda_i <= sda_o; + //end + wire sda_pin; + wire scl_pin; + assign sda_pin = sda_o ? 1'bz : 1'b0; + assign scl_pin = scl_o ? 1'bz : 1'b0; + assign sda_i = sda_pin; + assign scl_i = scl_pin; + + // Test procedure + initial begin + // Initialize inputs + //$display("Starting"); + rst = 1; + phy_start_bit = 0; + phy_stop_bit = 0; + phy_write_bit = 0; + phy_read_bit = 0; + phy_tx_data = 0; + phy_release_bus = 0; + + // Wait for a few clock cycles and release reset + //$display("before wait"); + #(CLK_PERIOD * 5); + //$display("before reset"); + rst = 0; + #(CLK_PERIOD * 5); + + //$display("before set"); + // Assert phy_start_bit + phy_start_bit = 1; + #(CLK_PERIOD); + phy_start_bit=0; + + // Wait until phy_state becomes active (PHY_STATE_ACTIVE) + //$display("wiating when phy becomes active"); + wait(phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 + $display("PHY_STATE_ACTIVE reached at time %t", $time); + + phy_write_bit = 1; + phy_tx_data = 0; + $display("Sending a 00000001"); + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 1; + #(CLK_PERIOD* 3*4); + phy_write_bit = 1; + phy_tx_data = 1;//READ =1 + $display("send write value"); + #(CLK_PERIOD* 3*4); + phy_write_bit = 0; + phy_read_bit = 1; + //do not Send acknoledgement + #(CLK_PERIOD* 3*4); + $display("Reading value %d",phy_rx_data_reg); + //rx should be 1 since we have not send anything this is a NACK + // End simulation + $finish; + end + + // Optional: Dump waveforms + initial begin + $dumpfile("i2c_phy_tb.vcd"); + $dumpvars(0, i2c_phy_tb); + end + +endmodule From 606625cc1c670cff6e0b79409152ea4e493f42bb Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 29 Jun 2024 07:39:20 +0200 Subject: [PATCH 05/47] free formatting --- rtl/i2c_phy.v | 10 ++--- rtl/i2c_phy_tb.sv | 110 +++++++++++++++++++++++----------------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index 68a8173..8f5db48 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -14,11 +14,11 @@ module i2c_phy ( // I2C interface input wire scl_i, - output wire scl_o, + output wire scl_o, input wire sda_i, - output wire sda_o, - output wire sda_t, - output wire scl_t, + output wire sda_o, + output wire sda_t, + output wire scl_t, // Status and data output reg phy_busy = 1'b0, @@ -118,7 +118,7 @@ module i2c_phy ( sda_o_next = 1'b1; scl_o_next = 1'b1; if (phy_start_bit) begin - //$display("idle, "); + //$display("idle, "); sda_o_next = 1'b0; delay_next = prescale; phy_state_next = PHY_STATE_START_1; diff --git a/rtl/i2c_phy_tb.sv b/rtl/i2c_phy_tb.sv index 12ccabe..49af927 100644 --- a/rtl/i2c_phy_tb.sv +++ b/rtl/i2c_phy_tb.sv @@ -3,7 +3,7 @@ module i2c_phy_tb; // Parameters - parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) + parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) // Signals reg clk = 0; @@ -26,29 +26,29 @@ module i2c_phy_tb; wire [4:0] phy_state_reg; // Clock generation - always #(CLK_PERIOD/2) clk <= ~clk; + always #(CLK_PERIOD / 2) clk <= ~clk; // Instantiate the i2c_phy module i2c_phy uut ( - .clk(clk), - .rst(rst), - .phy_start_bit(phy_start_bit), - .phy_stop_bit(phy_stop_bit), - .phy_write_bit(phy_write_bit), - .phy_read_bit(phy_read_bit), - .phy_tx_data(phy_tx_data), - .phy_release_bus(phy_release_bus), - .scl_i(scl_i), - .scl_o(scl_o), - .sda_i(sda_i), - .sda_o(sda_o), - .sda_t(sda_t), - .scl_t(scl_t), - .phy_busy(phy_busy), - .bus_control_reg(bus_control_reg), - .phy_rx_data_reg(phy_rx_data_reg), - .phy_state_reg(phy_state_reg), - .prescale(17'd3) + .clk(clk), + .rst(rst), + .phy_start_bit(phy_start_bit), + .phy_stop_bit(phy_stop_bit), + .phy_write_bit(phy_write_bit), + .phy_read_bit(phy_read_bit), + .phy_tx_data(phy_tx_data), + .phy_release_bus(phy_release_bus), + .scl_i(scl_i), + .scl_o(scl_o), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .scl_t(scl_t), + .phy_busy(phy_busy), + .bus_control_reg(bus_control_reg), + .phy_rx_data_reg(phy_rx_data_reg), + .phy_state_reg(phy_state_reg), + .prescale(17'd3) ); // Simulate I2C bus behavior @@ -60,8 +60,8 @@ module i2c_phy_tb; wire scl_pin; assign sda_pin = sda_o ? 1'bz : 1'b0; assign scl_pin = scl_o ? 1'bz : 1'b0; - assign sda_i = sda_pin; - assign scl_i = scl_pin; + assign sda_i = sda_pin; + assign scl_i = scl_pin; // Test procedure initial begin @@ -86,50 +86,50 @@ module i2c_phy_tb; // Assert phy_start_bit phy_start_bit = 1; #(CLK_PERIOD); - phy_start_bit=0; + phy_start_bit = 0; // Wait until phy_state becomes active (PHY_STATE_ACTIVE) //$display("wiating when phy becomes active"); - wait(phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 + wait (phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 $display("PHY_STATE_ACTIVE reached at time %t", $time); phy_write_bit = 1; - phy_tx_data = 0; + phy_tx_data = 0; $display("Sending a 00000001"); - #(CLK_PERIOD* 3*4); + #(CLK_PERIOD * 3 * 4); phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD* 3*4); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD* 3*4); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD* 3*4); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD* 3*4); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD* 3*4); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD* 3*4); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD* 3*4); - phy_write_bit = 1; - phy_tx_data = 1; - #(CLK_PERIOD* 3*4); + phy_tx_data = 0; + #(CLK_PERIOD * 3 * 4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD * 3 * 4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD * 3 * 4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD * 3 * 4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD * 3 * 4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD * 3 * 4); + phy_write_bit = 1; + phy_tx_data = 0; + #(CLK_PERIOD * 3 * 4); + phy_write_bit = 1; + phy_tx_data = 1; + #(CLK_PERIOD * 3 * 4); phy_write_bit = 1; - phy_tx_data = 1;//READ =1 + phy_tx_data = 1; //READ =1 $display("send write value"); - #(CLK_PERIOD* 3*4); + #(CLK_PERIOD * 3 * 4); phy_write_bit = 0; - phy_read_bit = 1; + phy_read_bit = 1; //do not Send acknoledgement - #(CLK_PERIOD* 3*4); - $display("Reading value %d",phy_rx_data_reg); + #(CLK_PERIOD * 3 * 4); + $display("Reading value %d", phy_rx_data_reg); //rx should be 1 since we have not send anything this is a NACK // End simulation $finish; From 7c6feaa01472c05e01ac750960691fcbfaca841a Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 29 Jun 2024 10:55:52 +0200 Subject: [PATCH 06/47] formatting plus testbench works now --- rtl/axis_fifo.v | 316 +++++++++++++++++++++++----------------------- rtl/i2c_phy_tb.sv | 92 +++++++++----- 2 files changed, 220 insertions(+), 188 deletions(-) diff --git a/rtl/axis_fifo.v b/rtl/axis_fifo.v index b8dfb0b..a33c27b 100644 --- a/rtl/axis_fifo.v +++ b/rtl/axis_fifo.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * AXI4-Stream FIFO */ -module axis_fifo # -( +module axis_fifo #( // FIFO depth in words // KEEP_WIDTH words per cycle if KEEP_ENABLE set // Rounded up to nearest power of 2 cycles @@ -39,9 +38,9 @@ module axis_fifo # parameter DATA_WIDTH = 8, // Propagate tkeep signal // If disabled, tkeep assumed to be 1'b1 - parameter KEEP_ENABLE = (DATA_WIDTH>8), + parameter KEEP_ENABLE = (DATA_WIDTH > 8), // tkeep signal width (words per cycle) - parameter KEEP_WIDTH = (DATA_WIDTH/8), + parameter KEEP_WIDTH = (DATA_WIDTH / 8), // Propagate tlast signal parameter LAST_ENABLE = 1, // Propagate tid signal @@ -73,218 +72,221 @@ module axis_fifo # // When set, s_axis_tready is always asserted // Requires FRAME_FIFO set parameter DROP_WHEN_FULL = 0 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * AXI input */ - input wire [DATA_WIDTH-1:0] s_axis_tdata, - input wire [KEEP_WIDTH-1:0] s_axis_tkeep, - input wire s_axis_tvalid, - output wire s_axis_tready, - input wire s_axis_tlast, - input wire [ID_WIDTH-1:0] s_axis_tid, - input wire [DEST_WIDTH-1:0] s_axis_tdest, - input wire [USER_WIDTH-1:0] s_axis_tuser, + input wire [DATA_WIDTH-1:0] s_axis_tdata, + input wire [KEEP_WIDTH-1:0] s_axis_tkeep, + input wire s_axis_tvalid, + output wire s_axis_tready, + input wire s_axis_tlast, + input wire [ ID_WIDTH-1:0] s_axis_tid, + input wire [DEST_WIDTH-1:0] s_axis_tdest, + input wire [USER_WIDTH-1:0] s_axis_tuser, /* * AXI output */ - output wire [DATA_WIDTH-1:0] m_axis_tdata, - output wire [KEEP_WIDTH-1:0] m_axis_tkeep, - output wire m_axis_tvalid, - input wire m_axis_tready, - output wire m_axis_tlast, - output wire [ID_WIDTH-1:0] m_axis_tid, - output wire [DEST_WIDTH-1:0] m_axis_tdest, - output wire [USER_WIDTH-1:0] m_axis_tuser, + output wire [DATA_WIDTH-1:0] m_axis_tdata, + output wire [KEEP_WIDTH-1:0] m_axis_tkeep, + output wire m_axis_tvalid, + input wire m_axis_tready, + output wire m_axis_tlast, + output wire [ ID_WIDTH-1:0] m_axis_tid, + output wire [DEST_WIDTH-1:0] m_axis_tdest, + output wire [USER_WIDTH-1:0] m_axis_tuser, /* * Status */ - output wire status_overflow, - output wire status_bad_frame, - output wire status_good_frame, - output wire status_full, - output wire status_empty + output wire status_overflow, + output wire status_bad_frame, + output wire status_good_frame, + output wire status_full, + output wire status_empty ); -parameter ADDR_WIDTH = (KEEP_ENABLE && KEEP_WIDTH > 1) ? $clog2(DEPTH/KEEP_WIDTH) : $clog2(DEPTH); + parameter ADDR_WIDTH = (KEEP_ENABLE && KEEP_WIDTH > 1) ? $clog2( + DEPTH / KEEP_WIDTH + ) : $clog2( + DEPTH + ); -// check configuration -initial begin + // check configuration + initial begin if (PIPELINE_OUTPUT < 1) begin - $error("Error: PIPELINE_OUTPUT must be at least 1 (instance %m)"); - $finish; + $error("Error: PIPELINE_OUTPUT must be at least 1 (instance %m)"); + $finish; end if (FRAME_FIFO && !LAST_ENABLE) begin - $error("Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)"); - $finish; + $error("Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)"); + $finish; end if (DROP_BAD_FRAME && !FRAME_FIFO) begin - $error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set (instance %m)"); - $finish; + $error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set (instance %m)"); + $finish; end if (DROP_WHEN_FULL && !FRAME_FIFO) begin - $error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set (instance %m)"); - $finish; + $error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set (instance %m)"); + $finish; end if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin - $error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"); - $finish; + $error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"); + $finish; end -end + end -localparam KEEP_OFFSET = DATA_WIDTH; -localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0); -localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0); -localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0); -localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); -localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); + localparam KEEP_OFFSET = DATA_WIDTH; + localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0); + localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0); + localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0); + localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); + localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); -reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}; + reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH + 1{1'b0}}; + reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH + 1{1'b0}}; + reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH + 1{1'b0}}; -reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0]; -reg [WIDTH-1:0] mem_read_data_reg; -reg mem_read_data_valid_reg = 1'b0; + reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0]; + reg [WIDTH-1:0] mem_read_data_reg; + reg mem_read_data_valid_reg = 1'b0; -wire [WIDTH-1:0] s_axis; + wire [WIDTH-1:0] s_axis; -reg [WIDTH-1:0] m_axis_pipe_reg[PIPELINE_OUTPUT-1:0]; -reg [PIPELINE_OUTPUT-1:0] m_axis_tvalid_pipe_reg = 1'b0; + reg [WIDTH-1:0] m_axis_pipe_reg[PIPELINE_OUTPUT-1:0]; + reg [PIPELINE_OUTPUT-1:0] m_axis_tvalid_pipe_reg = 1'b0; -// full when first MSB different but rest same -wire full = wr_ptr_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); -wire full_cur = wr_ptr_cur_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); -// empty when pointers match exactly -wire empty = wr_ptr_reg == rd_ptr_reg; -// overflow within packet -wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); + // full when first MSB different but rest same + wire full = wr_ptr_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); + wire full_cur = wr_ptr_cur_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); + // empty when pointers match exactly + wire empty = wr_ptr_reg == rd_ptr_reg; + // overflow within packet + wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); -reg drop_frame_reg = 1'b0; -reg overflow_reg = 1'b0; -reg bad_frame_reg = 1'b0; -reg good_frame_reg = 1'b0; + reg drop_frame_reg = 1'b0; + reg overflow_reg = 1'b0; + reg bad_frame_reg = 1'b0; + reg good_frame_reg = 1'b0; -assign s_axis_tready = FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full; + assign s_axis_tready = FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full; -generate + generate assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata; - if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep; - if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast; - if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid; - if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest; - if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser; -endgenerate - -assign m_axis_tvalid = m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1]; - -assign m_axis_tdata = m_axis_pipe_reg[PIPELINE_OUTPUT-1][DATA_WIDTH-1:0]; -assign m_axis_tkeep = KEEP_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}}; -assign m_axis_tlast = LAST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][LAST_OFFSET] : 1'b1; -assign m_axis_tid = ID_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}}; -assign m_axis_tdest = DEST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}}; -assign m_axis_tuser = USER_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}}; - -assign status_overflow = overflow_reg; -assign status_bad_frame = bad_frame_reg; -assign status_good_frame = good_frame_reg; -assign status_full = FRAME_FIFO ? full_cur || full_wr : full; -assign status_empty = empty; - -// Write logic -always @(posedge clk) begin - overflow_reg <= 1'b0; - bad_frame_reg <= 1'b0; + if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET+:KEEP_WIDTH] = s_axis_tkeep; + if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast; + if (ID_ENABLE) assign s_axis[ID_OFFSET+:ID_WIDTH] = s_axis_tid; + if (DEST_ENABLE) assign s_axis[DEST_OFFSET+:DEST_WIDTH] = s_axis_tdest; + if (USER_ENABLE) assign s_axis[USER_OFFSET+:USER_WIDTH] = s_axis_tuser; + endgenerate + + assign m_axis_tvalid = m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1]; + + assign m_axis_tdata = m_axis_pipe_reg[PIPELINE_OUTPUT-1][DATA_WIDTH-1:0]; + assign m_axis_tkeep = KEEP_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}}; + assign m_axis_tlast = LAST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][LAST_OFFSET] : 1'b1; + assign m_axis_tid = ID_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}}; + assign m_axis_tdest = DEST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}}; + assign m_axis_tuser = USER_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}}; + + assign status_overflow = overflow_reg; + assign status_bad_frame = bad_frame_reg; + assign status_good_frame = good_frame_reg; + assign status_full = FRAME_FIFO ? full_cur || full_wr : full; + assign status_empty = empty; + + // Write logic + always @(posedge clk) begin + overflow_reg <= 1'b0; + bad_frame_reg <= 1'b0; good_frame_reg <= 1'b0; if (s_axis_tready && s_axis_tvalid) begin - // transfer in - if (!FRAME_FIFO) begin - // normal FIFO mode - mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; - wr_ptr_reg <= wr_ptr_reg + 1; - end else if (full_cur || full_wr || drop_frame_reg) begin - // full, packet overflow, or currently dropping frame - // drop frame - drop_frame_reg <= 1'b1; - if (s_axis_tlast) begin - // end of frame, reset write pointer - wr_ptr_cur_reg <= wr_ptr_reg; - drop_frame_reg <= 1'b0; - overflow_reg <= 1'b1; - end - end else begin - mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis; - wr_ptr_cur_reg <= wr_ptr_cur_reg + 1; - if (s_axis_tlast) begin - // end of frame - if (DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin - // bad packet, reset write pointer - wr_ptr_cur_reg <= wr_ptr_reg; - bad_frame_reg <= 1'b1; - end else begin - // good packet, update write pointer - wr_ptr_reg <= wr_ptr_cur_reg + 1; - good_frame_reg <= 1'b1; - end - end + // transfer in + if (!FRAME_FIFO) begin + // normal FIFO mode + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_reg <= wr_ptr_reg + 1; + end else if (full_cur || full_wr || drop_frame_reg) begin + // full, packet overflow, or currently dropping frame + // drop frame + drop_frame_reg <= 1'b1; + if (s_axis_tlast) begin + // end of frame, reset write pointer + wr_ptr_cur_reg <= wr_ptr_reg; + drop_frame_reg <= 1'b0; + overflow_reg <= 1'b1; end + end else begin + mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_cur_reg <= wr_ptr_cur_reg + 1; + if (s_axis_tlast) begin + // end of frame + if (DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin + // bad packet, reset write pointer + wr_ptr_cur_reg <= wr_ptr_reg; + bad_frame_reg <= 1'b1; + end else begin + // good packet, update write pointer + wr_ptr_reg <= wr_ptr_cur_reg + 1; + good_frame_reg <= 1'b1; + end + end + end end if (rst) begin - wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_reg <= {ADDR_WIDTH + 1{1'b0}}; + wr_ptr_cur_reg <= {ADDR_WIDTH + 1{1'b0}}; - drop_frame_reg <= 1'b0; - overflow_reg <= 1'b0; - bad_frame_reg <= 1'b0; - good_frame_reg <= 1'b0; + drop_frame_reg <= 1'b0; + overflow_reg <= 1'b0; + bad_frame_reg <= 1'b0; + good_frame_reg <= 1'b0; end -end + end -// Read logic -integer j; + // Read logic + integer j; -always @(posedge clk) begin + always @(posedge clk) begin if (m_axis_tready) begin - // output ready; invalidate stage - m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1] <= 1'b0; + // output ready; invalidate stage + m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1] <= 1'b0; end - for (j = PIPELINE_OUTPUT-1; j > 0; j = j - 1) begin - if (m_axis_tready || ((~m_axis_tvalid_pipe_reg) >> j)) begin - // output ready or bubble in pipeline; transfer down pipeline - m_axis_tvalid_pipe_reg[j] <= m_axis_tvalid_pipe_reg[j-1]; - m_axis_pipe_reg[j] <= m_axis_pipe_reg[j-1]; - m_axis_tvalid_pipe_reg[j-1] <= 1'b0; - end + for (j = PIPELINE_OUTPUT - 1; j > 0; j = j - 1) begin + if (m_axis_tready || ((~m_axis_tvalid_pipe_reg) >> j)) begin + // output ready or bubble in pipeline; transfer down pipeline + m_axis_tvalid_pipe_reg[j] <= m_axis_tvalid_pipe_reg[j-1]; + m_axis_pipe_reg[j] <= m_axis_pipe_reg[j-1]; + m_axis_tvalid_pipe_reg[j-1] <= 1'b0; + end end if (m_axis_tready || ~m_axis_tvalid_pipe_reg) begin - // output ready or bubble in pipeline; read new data from FIFO - m_axis_tvalid_pipe_reg[0] <= 1'b0; - m_axis_pipe_reg[0] <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]]; - if (!empty) begin - // not empty, increment pointer - m_axis_tvalid_pipe_reg[0] <= 1'b1; - rd_ptr_reg <= rd_ptr_reg + 1; - end + // output ready or bubble in pipeline; read new data from FIFO + m_axis_tvalid_pipe_reg[0] <= 1'b0; + m_axis_pipe_reg[0] <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]]; + if (!empty) begin + // not empty, increment pointer + m_axis_tvalid_pipe_reg[0] <= 1'b1; + rd_ptr_reg <= rd_ptr_reg + 1; + end end if (rst) begin - rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; - m_axis_tvalid_pipe_reg <= {PIPELINE_OUTPUT{1'b0}}; + rd_ptr_reg <= {ADDR_WIDTH + 1{1'b0}}; + m_axis_tvalid_pipe_reg <= {PIPELINE_OUTPUT{1'b0}}; end -end + end endmodule diff --git a/rtl/i2c_phy_tb.sv b/rtl/i2c_phy_tb.sv index 49af927..cca5a00 100644 --- a/rtl/i2c_phy_tb.sv +++ b/rtl/i2c_phy_tb.sv @@ -14,10 +14,12 @@ module i2c_phy_tb; reg phy_read_bit = 0; reg phy_tx_data = 0; reg phy_release_bus = 0; - wire scl_i = 1; + reg scl_i = 1;//Technically they are not registers but in testbench we need to store them somewhere wire scl_o; - wire sda_i = 1; + reg sda_i = 1; wire sda_o; + reg sda2=1;//dummy registers + reg scl2=1; wire sda_t; wire scl_t; wire phy_busy; @@ -28,6 +30,35 @@ module i2c_phy_tb; // Clock generation always #(CLK_PERIOD / 2) clk <= ~clk; + // Tri-state buffer modeling + wire scl_wire; + wire sda_wire; + + reg scl_i_reg_tb, sda_i_reg_tb; + // Model pull-up resistors with weak pull-ups + pullup(scl_wire); + pullup (sda_wire); + + // Model open-drain outputs + assign scl_wire = (scl_o & scl2) ? 1'bz : 1'b0; + assign sda_wire = (sda_o & sda2) ? 1'bz : 1'b0; + + // Sample the bus with non-blocking assignments to avoid race conditions + always @(posedge clk or posedge rst) begin + if (rst) begin + scl_i_reg_tb <= 1'b1; + sda_i_reg_tb <= 1'b1; + end else begin + scl_i_reg_tb <= scl_wire; + sda_i_reg_tb <= sda_wire; + + // Assert that sda_i_reg is not X + if(sda_i_reg_tb === 1'bx) $fatal(1,"sda_i_reg is X at time %t", $time); + end + end + + + // Instantiate the i2c_phy module i2c_phy uut ( .clk(clk), @@ -38,9 +69,9 @@ module i2c_phy_tb; .phy_read_bit(phy_read_bit), .phy_tx_data(phy_tx_data), .phy_release_bus(phy_release_bus), - .scl_i(scl_i), + .scl_i(scl_i_reg_tb), .scl_o(scl_o), - .sda_i(sda_i), + .sda_i(sda_i_reg_tb), .sda_o(sda_o), .sda_t(sda_t), .scl_t(scl_t), @@ -51,18 +82,7 @@ module i2c_phy_tb; .prescale(17'd3) ); - // Simulate I2C bus behavior - //always @(posedge clk) begin - // if (!scl_t) scl_i <= scl_o; - // if (!sda_t) sda_i <= sda_o; - //end - wire sda_pin; - wire scl_pin; - assign sda_pin = sda_o ? 1'bz : 1'b0; - assign scl_pin = scl_o ? 1'bz : 1'b0; - assign sda_i = sda_pin; - assign scl_i = scl_pin; - +// Input to the module // Test procedure initial begin // Initialize inputs @@ -96,40 +116,50 @@ module i2c_phy_tb; phy_write_bit = 1; phy_tx_data = 0; $display("Sending a 00000001"); - #(CLK_PERIOD * 3 * 4); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 phy_write_bit = 1; phy_tx_data = 0; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 phy_write_bit = 1; phy_tx_data = 0; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); phy_write_bit = 1; phy_tx_data = 0; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); phy_write_bit = 1; phy_tx_data = 0; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); phy_write_bit = 1; phy_tx_data = 0; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); phy_write_bit = 1; phy_tx_data = 0; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); phy_write_bit = 1; phy_tx_data = 1; - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); phy_write_bit = 1; phy_tx_data = 1; //READ =1 $display("send write value"); - #(CLK_PERIOD * 3 * 4); + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); phy_write_bit = 0; phy_read_bit = 1; - //do not Send acknoledgement - #(CLK_PERIOD * 3 * 4); - $display("Reading value %d", phy_rx_data_reg); + sda2=0; + #(CLK_PERIOD*2); + wait (phy_state_reg == 5'd1); + sda2=1; + $display("Reading value %d", phy_rx_data_reg); //since we sent a 0 this is an ACK + #(CLK_PERIOD * 140); + sda2=1; //rx should be 1 since we have not send anything this is a NACK // End simulation $finish; From 6cae407e85e8d786fe892da7fed8ac77e832548d Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 29 Jun 2024 11:25:37 +0200 Subject: [PATCH 07/47] compartementalize the test --- rtl/i2c_master.v | 46 +++++------ rtl/i2c_phy_tb.sv | 197 +++++++++++++++++++++++++++------------------- 2 files changed, 140 insertions(+), 103 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 669cff8..4d4fbec 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -593,29 +593,29 @@ always @* begin end end -i2c_phy phy_instance ( - // Control signals - .phy_start_bit(phy_start_bit), - .phy_stop_bit(phy_stop_bit), - .phy_write_bit(phy_write_bit), - .phy_read_bit(phy_read_bit), - .phy_tx_data(phy_tx_data), - .phy_release_bus(phy_release_bus), - - // I2C interface - .scl_i_reg, - .scl_o_reg, - .sda_i_reg, - .sda_o_reg, - - // Status and data - .phy_busy(phy_busy), - .bus_control_reg, - .phy_rx_data_reg, - - // Configuration - .prescale(prescale) -); +i2c_phy phy_instance +( + .clk(clk), + .rst(rst), + .phy_start_bit(phy_start_bit), + .phy_stop_bit(phy_stop_bit), + .phy_write_bit(phy_write_bit), + .phy_read_bit(phy_read_bit), + .phy_tx_data(phy_tx_data), + .phy_release_bus(phy_release_bus), + .scl_i(scl_i), + .scl_o(scl_o), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .scl_t(scl_t), + .phy_busy(phy_busy), + .bus_control_reg(bus_control_reg), + .phy_rx_data_reg(phy_rx_data_reg), + .phy_state_reg(phy_state_reg), + .prescale(17'd3) + ); + always @(posedge clk) begin state_reg <= state_next; diff --git a/rtl/i2c_phy_tb.sv b/rtl/i2c_phy_tb.sv index cca5a00..dfa4c1b 100644 --- a/rtl/i2c_phy_tb.sv +++ b/rtl/i2c_phy_tb.sv @@ -81,90 +81,127 @@ module i2c_phy_tb; .phy_state_reg(phy_state_reg), .prescale(17'd3) ); +task initialize; + begin + rst = 1; + phy_start_bit = 0; + phy_stop_bit = 0; + phy_write_bit = 0; + phy_read_bit = 0; + phy_tx_data = 0; + phy_release_bus = 0; + end + endtask + + task reset; + begin + rst = 1; + #(CLK_PERIOD * 5); + rst = 0; + #(CLK_PERIOD * 5); + end + endtask + task write_operation(input tx_data); + begin + wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE + phy_write_bit = 1; + phy_tx_data = tx_data; + #(CLK_PERIOD * 2); + end + endtask + task read_operation; + begin + wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE + phy_write_bit = 0; + phy_read_bit = 1; + #(CLK_PERIOD * 2); + end + endtask + + task wait_for_idle; + begin + wait (phy_state_reg == 5'd0); // Assuming PHY_STATE_IDLE is 5'd0 + end + endtask + + // Specific test scenarios + task test_write_byte; + begin + $display("Testing write byte operation"); + phy_start_bit = 1; + #(CLK_PERIOD); + phy_start_bit = 0; + + // Write byte 0x81 (10000001) + write_operation(1); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(1); + + // Read ACK + //Send ACK + sda2=0; + read_operation; + wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE + sda2=1;//pull sda2 back up + if (phy_rx_data_reg!=0) + $finish("Expecting ACK but found NACK: %d ", phy_rx_data_reg); + end + endtask + + task test_read_byte; + begin + $display("Testing read byte operation"); + phy_start_bit = 1; + #(CLK_PERIOD); + phy_start_bit = 0; + + // Send read command (e.g., 0xA1 for read) + write_operation(1); + write_operation(0); + write_operation(1); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(1); + + // Read ACK + read_operation; + + // Read byte + repeat(8) begin + read_operation; + end + + // Send NACK + write_operation(1); + end + endtask -// Input to the module - // Test procedure + // Main test procedure initial begin - // Initialize inputs - //$display("Starting"); - rst = 1; - phy_start_bit = 0; - phy_stop_bit = 0; - phy_write_bit = 0; - phy_read_bit = 0; - phy_tx_data = 0; - phy_release_bus = 0; - - // Wait for a few clock cycles and release reset - //$display("before wait"); - #(CLK_PERIOD * 5); - //$display("before reset"); - rst = 0; - #(CLK_PERIOD * 5); - - //$display("before set"); - // Assert phy_start_bit - phy_start_bit = 1; - #(CLK_PERIOD); - phy_start_bit = 0; - - // Wait until phy_state becomes active (PHY_STATE_ACTIVE) - //$display("wiating when phy becomes active"); - wait (phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 - $display("PHY_STATE_ACTIVE reached at time %t", $time); - - phy_write_bit = 1; - phy_tx_data = 0; - $display("Sending a 00000001"); - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); // Assuming PHY_STATE_ACTIVE is 5'd1 - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - phy_write_bit = 1; - phy_tx_data = 0; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - phy_write_bit = 1; - phy_tx_data = 1; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - phy_write_bit = 1; - phy_tx_data = 1; //READ =1 - $display("send write value"); - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - phy_write_bit = 0; - phy_read_bit = 1; - sda2=0; - #(CLK_PERIOD*2); - wait (phy_state_reg == 5'd1); - sda2=1; - $display("Reading value %d", phy_rx_data_reg); //since we sent a 0 this is an ACK - #(CLK_PERIOD * 140); - sda2=1; - //rx should be 1 since we have not send anything this is a NACK - // End simulation + $display("Starting I2C PHY Test"); + initialize; + $display("Initialized"); + reset; + $display("reseted"); + + $display("Test write"); + test_write_byte; + $display("Test idle?"); + //wait_for_idle; + + //test_read_byte; + //wait_for_idle; + + $display("I2C PHY Test Completed"); $finish; end - // Optional: Dump waveforms initial begin $dumpfile("i2c_phy_tb.vcd"); From 3c0e001696015ac3f4aa2ce3ba593da0bdf2b638 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 29 Jun 2024 19:30:25 +0200 Subject: [PATCH 08/47] save whatever --- rtl/i2c_master.v | 70 +++++++---- rtl/i2c_master_tb.v | 280 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 327 insertions(+), 23 deletions(-) create mode 100644 rtl/i2c_master_tb.v diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 4d4fbec..fbfc570 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -181,20 +181,20 @@ scl_o should not be connected directly to scl_i, only via AND logic or a tristat I/O pin. This would prevent devices from stretching the clock period. */ - localparam [4:0] - STATE_IDLE = 4'd0, - STATE_ACTIVE_WRITE = 4'd1, - STATE_ACTIVE_READ = 4'd2, - STATE_START_WAIT = 4'd3, - STATE_START = 4'd4, - STATE_ADDRESS_1 = 4'd5, - STATE_ADDRESS_2 = 4'd6, - STATE_WRITE_1 = 4'd7, - STATE_WRITE_2 = 4'd8, - STATE_WRITE_3 = 4'd9, - STATE_READ = 4'd10, - STATE_STOP = 4'd11; + STATE_IDLE = 5'd0, + STATE_ACTIVE_WRITE = 5'd1, + STATE_ACTIVE_READ = 5'd2, + STATE_START_WAIT = 5'd3, + STATE_START = 5'd4, + STATE_ADDRESS_1 = 5'd5, + STATE_ADDRESS_2 = 5'd6, + STATE_WRITE_1 = 5'd7, + STATE_WRITE_2 = 5'd8, + STATE_WRITE_3 = 5'd9, + STATE_READ = 5'd10, + STATE_STOP = 5'd11; + reg [4:0] state_reg = STATE_IDLE, state_next; @@ -216,7 +216,7 @@ localparam [4:0] PHY_STATE_STOP_2 = 5'd14, PHY_STATE_STOP_3 = 5'd15; -reg [4:0] phy_state_reg = STATE_IDLE; +wire [4:0] phy_state_reg; reg phy_start_bit; reg phy_stop_bit; @@ -226,7 +226,8 @@ reg phy_release_bus; reg phy_tx_data; -reg phy_rx_data_reg = 1'b0, phy_rx_data_next; +//reg phy_rx_data_reg = 1'b0, phy_rx_data_next; +wire phy_rx_data_reg; reg [6:0] addr_reg = 7'd0, addr_next; reg [7:0] data_reg = 8'd0, data_next; @@ -257,7 +258,9 @@ reg last_scl_i_reg = 1'b1; reg last_sda_i_reg = 1'b1; reg busy_reg = 1'b0; -//reg bus_active_reg = 1'b0; +reg bus_active_reg = 1'b0; +wire bus_control_reg; +wire phy_busy; //reg bus_control_reg = 1'b0, bus_control_next; reg missed_ack_reg = 1'b0, missed_ack_next; @@ -269,14 +272,14 @@ assign m_axis_data_tdata = m_axis_data_tdata_reg; assign m_axis_data_tvalid = m_axis_data_tvalid_reg; assign m_axis_data_tlast = m_axis_data_tlast_reg; -assign scl_o = scl_o_reg; -assign scl_t = scl_o_reg; -assign sda_o = sda_o_reg; -assign sda_t = sda_o_reg; +//assign scl_o = scl_o_reg; +//assign scl_t = scl_o_reg; +//assign sda_o = sda_o_reg; +//assign sda_t = sda_o_reg; assign busy = busy_reg; assign bus_active = bus_active_reg; -//assign bus_control = bus_control_reg; +assign bus_control = bus_control_reg; assign missed_ack = missed_ack_reg; wire scl_posedge = scl_i_reg & ~last_scl_i_reg; @@ -360,6 +363,7 @@ always @* begin s_axis_cmd_ready_next = 1'b1; if (s_axis_cmd_ready & s_axis_cmd_valid) begin + $display("ready and valid"); // command valid if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin // read or write command @@ -394,19 +398,23 @@ always @* begin end end else begin if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin + $display("Not here"); // no waiting command and stop_on_idle selected, issue stop condition phy_stop_bit = 1'b1; state_next = STATE_IDLE; end else begin + $display("From read to write?"); state_next = STATE_ACTIVE_WRITE; end end end STATE_ACTIVE_READ: begin + $display("State active read"); // line active to current address s_axis_cmd_ready_next = ~m_axis_data_tvalid; if (s_axis_cmd_ready & s_axis_cmd_valid) begin + $display("ready and valid ative read"); // command valid if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin // read or write command @@ -421,6 +429,7 @@ always @* begin // address or mode mismatch or forced start - repeated start // write nack for previous read + $display("mode mismatch forced restart, write nack"); phy_write_bit = 1'b1; phy_tx_data = 1'b1; // repeated start bit @@ -428,6 +437,7 @@ always @* begin end else begin // address and mode match + $display("sending ack and continue with next read"); // write ack for previous read phy_write_bit = 1'b1; phy_tx_data = 1'b0; @@ -437,6 +447,7 @@ always @* begin state_next = STATE_READ; end end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin + $display("Not here active read"); // stop command // write nack for previous read phy_write_bit = 1'b1; @@ -444,18 +455,24 @@ always @* begin // send stop bit state_next = STATE_STOP; end else begin + $display("active read: invalid or unspecified - ignore.. ?"); // invalid or unspecified - ignore state_next = STATE_ACTIVE_READ; end end else begin + if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin // no waiting command and stop_on_idle selected, issue stop condition // write ack for previous read phy_write_bit = 1'b1; phy_tx_data = 1'b1; // send stop bit + $display("got last bit and received, so stopping"); + state_next = STATE_STOP; end else begin + $display("Active Read: conditions: %d, %d",s_axis_cmd_ready,~s_axis_cmd_valid); +$display("m_axis_data_tvalid %d ", m_axis_data_tvalid); state_next = STATE_ACTIVE_READ; end end @@ -492,7 +509,9 @@ always @* begin phy_write_bit = 1'b1; phy_tx_data = mode_read_reg; state_next = STATE_ADDRESS_1; + $display("should be %d",mode_read_reg); end else begin + $display("should be 0 %d",sda_o); // read ack bit phy_read_bit = 1'b1; state_next = STATE_ADDRESS_2; @@ -501,11 +520,16 @@ always @* begin STATE_ADDRESS_2: begin // read ack bit missed_ack_next = phy_rx_data_reg; + if (missed_ack_next) begin + $display("got NACK"); + end + else + $display("got ACK"); if (mode_read_reg) begin // start read bit_count_next = 4'd8; - data_next = 1'b0; + data_next = 8'b0; state_next = STATE_READ; end else begin // start write @@ -589,6 +613,7 @@ always @* begin phy_stop_bit = 1'b1; state_next = STATE_IDLE; end + default: $display("I don't think case default should get triggered"); endcase end end @@ -664,7 +689,6 @@ always @(posedge clk) begin s_axis_data_tready_reg <= 1'b0; m_axis_data_tvalid_reg <= 1'b0; busy_reg <= 1'b0; - bus_control_reg <= 1'b0; missed_ack_reg <= 1'b0; end end diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v new file mode 100644 index 0000000..7dec9b6 --- /dev/null +++ b/rtl/i2c_master_tb.v @@ -0,0 +1,280 @@ +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Testbench for i2c_master + */ +module test_i2c_master; + +// Parameters + + parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [6:0] s_axis_cmd_address = 0; +reg s_axis_cmd_start = 0; +reg s_axis_cmd_read = 0; +reg s_axis_cmd_write = 0; +reg s_axis_cmd_write_multiple = 0; +reg s_axis_cmd_stop = 0; +reg s_axis_cmd_valid = 0; +reg [7:0] s_axis_data_tdata = 0; +reg s_axis_data_tvalid = 0; +reg s_axis_data_tlast = 0; +reg m_axis_data_tready = 0; +reg scl_i = 1; +reg sda_i = 1; +reg [15:0] prescale = 0; +reg stop_on_idle = 0; + +// Outputs +wire s_axis_cmd_ready; +wire s_axis_data_tready; +wire [7:0] m_axis_data_tdata; +wire m_axis_data_tvalid; +wire m_axis_data_tlast; +wire scl_o; +wire scl_t; +wire sda_o; +wire sda_t; +wire busy; +wire bus_control; +wire bus_active; +wire missed_ack; + +// Additional wires for modeling pull-up resistors and open-drain outputs +wire scl_wire; +wire sda_wire; + reg sda2=1;//dummy registers + reg scl2=1;//dummy registers + + +// Model pull-up resistors with weak pull-ups +pullup(scl_wire); +pullup(sda_wire); + +// Model open-drain outputs +assign scl_wire = (scl_o & scl2) ? 1'bz : 1'b0; +assign sda_wire = (sda_o & sda2) ? 1'bz : 1'b0; + + always #(CLK_PERIOD / 2) clk <= ~clk; +// Sample the bus with non-blocking assignments to avoid race conditions +always @(posedge clk or posedge rst) begin + if (rst) begin + scl_i <= 1'b1; + sda_i <= 1'b1; + end else begin + scl_i <= scl_wire; + sda_i <= sda_wire; + + // Assert that sda_i_reg_tb is not X + if (sda_i === 1'bx) $fatal(1, "sda_i_reg_tb is X at time %t", $time); + end +end + + +initial begin + // dump file + $dumpfile("i2c_master_tb.vcd"); + $dumpvars(0, test_i2c_master); + +end + +i2c_master +UUT ( + .clk(clk), + .rst(rst), + .s_axis_cmd_address(s_axis_cmd_address), + .s_axis_cmd_start(s_axis_cmd_start), + .s_axis_cmd_read(s_axis_cmd_read), + .s_axis_cmd_write(s_axis_cmd_write), + .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), + .s_axis_cmd_stop(s_axis_cmd_stop), + .s_axis_cmd_valid(s_axis_cmd_valid), + .s_axis_cmd_ready(s_axis_cmd_ready), + .s_axis_data_tdata(s_axis_data_tdata), + .s_axis_data_tvalid(s_axis_data_tvalid), + .s_axis_data_tready(s_axis_data_tready), + .s_axis_data_tlast(s_axis_data_tlast), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .scl_i(scl_i), + .scl_o(scl_o), + .scl_t(scl_t), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .busy(busy), + .bus_control(bus_control), + .bus_active(bus_active), + .missed_ack(missed_ack), + .prescale(prescale), + .stop_on_idle(stop_on_idle) +); + + task initialize_testbench; + begin + clk = 0; + rst = 1; + s_axis_cmd_address = 0; + s_axis_cmd_start = 0; + s_axis_cmd_read = 0; + s_axis_cmd_write = 0; + s_axis_cmd_write_multiple = 0; + s_axis_cmd_stop = 0; + s_axis_cmd_valid = 0; + s_axis_data_tdata = 0; + s_axis_data_tvalid = 0; + s_axis_data_tlast = 0; + m_axis_data_tready = 0; + scl_i = 1; + sda_i = 1; + prescale = 0; + stop_on_idle = 0; + sda2 = 1; + scl2 = 1; + + #10 rst = 0; + end + endtask + + task i2c_start; + input [6:0] address; + input is_read; + begin + s_axis_cmd_address = address; + s_axis_cmd_start = 1; + s_axis_cmd_read = is_read; + s_axis_cmd_write = !is_read; + s_axis_cmd_valid = 1; + + @(negedge sda_wire); + @(negedge scl_wire);//start condition done! + + s_axis_cmd_start = 0; + s_axis_cmd_read = 0; + s_axis_cmd_write = 0; + s_axis_cmd_valid = 0; + end + endtask + +initial begin + $display("Starting I2C Master test"); + initialize_testbench; + + // Set address to 00000001, command to write, and data to 11111111 + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10100101; + s_axis_data_tvalid = 1; + $display("Waiting for ready"); + // Wait for NACK + @(posedge missed_ack); + $display("NACK expected!"); + + @(posedge s_axis_cmd_ready); + #(CLK_PERIOD); // let it cook + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + $display("Waiting for ready round 2"); + + // Hardcoding the acknowledgement + repeat(8) @(negedge scl_o); + // Send ACK + sda2 = 0; + #(CLK_PERIOD); // let it cook + + @(negedge scl_o); + sda2 = 1; + + @(negedge scl_o); + + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + #(CLK_PERIOD); // let it cook + sda2 = 0; + s_axis_cmd_start = 0; + s_axis_cmd_write = 0; + s_axis_cmd_valid = 0; + stop_on_idle=1; + + + @(negedge scl_o); + #(CLK_PERIOD); // let it cook + + sda2 = 1; + + @(posedge s_axis_cmd_ready); + #1000; + s_axis_cmd_address = 7'b0000001; + //start is implied + //s_axis_cmd_start = 0; + s_axis_cmd_read = 1; + s_axis_cmd_valid = 1; + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + $display("Now doing a read."); + + // Hardcoding the acknowledgement + @(negedge sda_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + // Send ACK + sda2 = 0; + $display("Send ACK."); + #(CLK_PERIOD); // let it cook + + s_axis_cmd_valid = 0; + @(negedge scl_o); + $display("test 1"); + + @(negedge scl_o); + sda2 = 1; + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + @(negedge scl_o); + s_axis_cmd_valid = 1; + m_axis_data_tready = 1;//prepare readyness + @(negedge scl_o); + #(CLK_PERIOD); // let it cook + stop_on_idle=1; + //@(negedge scl_o); + @(posedge m_axis_data_tvalid); + $display("received m_axis_data_tdata %d",m_axis_data_tdata); + $display("received readiness %d",s_axis_cmd_ready); + @(posedge scl_o); + if (sda_wire) begin + $fatal(1,"Got NACK from master") ; + end +//pretend we got data + @(posedge s_axis_cmd_ready); + s_axis_cmd_valid = 0;//now stop + @(posedge s_axis_cmd_ready); + // Add a timeout + #1000; + $display("Simulation ended due to timeout"); + $finish; +end + endmodule + From 77303b7c1fa7d7d14e6fafbb360ea07ae98bc2d3 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 29 Jun 2024 20:25:20 +0200 Subject: [PATCH 09/47] looks good --- rtl/i2c_master_tb.v | 153 +++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 81 deletions(-) diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index 7dec9b6..c9d6ec3 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -164,117 +164,108 @@ UUT ( end endtask +task send_byte; + input [7:0] byte_to_send; + integer i; + begin + for (i = 7; i >= 0; i = i - 1) begin + sda2 = byte_to_send[i]; + @(negedge scl_o); + end + end + + endtask + + task wait_for_ready; + begin + $display("Waiting for ready"); + @(posedge s_axis_cmd_ready); + #CLK_PERIOD; + end + endtask + + task send_ack; + begin + @(negedge scl_o); + sda2 = 0; + #CLK_PERIOD; + @(negedge scl_o); + sda2 = 1; + end + endtask + + initial begin $display("Starting I2C Master test"); initialize_testbench; - // Set address to 00000001, command to write, and data to 11111111 + // Set address to 00000001, command to write i2c_start(7'b0000001, 0); s_axis_data_tdata = 8'b10100101; s_axis_data_tvalid = 1; - $display("Waiting for ready"); + // Wait for NACK @(posedge missed_ack); $display("NACK expected!"); + + wait_for_ready(); - @(posedge s_axis_cmd_ready); - #(CLK_PERIOD); // let it cook + // Second write attempt i2c_start(7'b0000001, 0); s_axis_data_tdata = 8'b10101111; s_axis_data_tvalid = 1; - $display("Waiting for ready round 2"); // Hardcoding the acknowledgement - repeat(8) @(negedge scl_o); - // Send ACK - sda2 = 0; - #(CLK_PERIOD); // let it cook - - @(negedge scl_o); - sda2 = 1; - - @(negedge scl_o); - - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - #(CLK_PERIOD); // let it cook - sda2 = 0; - s_axis_cmd_start = 0; - s_axis_cmd_write = 0; - s_axis_cmd_valid = 0; - stop_on_idle=1; + repeat(7) @(negedge scl_o); + // Send ACK + send_ack(); + @(negedge scl_o); // let 1 pass through + send_byte(8'b01111111); + stop_on_idle = 1; - @(negedge scl_o); - #(CLK_PERIOD); // let it cook - - sda2 = 1; - - @(posedge s_axis_cmd_ready); + wait_for_ready(); #1000; - s_axis_cmd_address = 7'b0000001; - //start is implied - //s_axis_cmd_start = 0; - s_axis_cmd_read = 1; - s_axis_cmd_valid = 1; + + // Start is implied s_axis_data_tdata = 8'b10101111; s_axis_data_tvalid = 1; - $display("Now doing a read."); - + i2c_start(7'b0000001, 1); + + $display("Now doing a read"); + // Hardcoding the acknowledgement - @(negedge sda_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); + repeat(7) @(negedge scl_o); + // Send ACK - sda2 = 0; - $display("Send ACK."); - #(CLK_PERIOD); // let it cook - s_axis_cmd_valid = 0; - @(negedge scl_o); - $display("test 1"); - - @(negedge scl_o); - sda2 = 1; - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); - @(negedge scl_o); + send_ack(); + send_byte(8'b01111111); + + // Continue with next read (does not require i2c_start condition) + s_axis_cmd_read = 1; s_axis_cmd_valid = 1; - m_axis_data_tready = 1;//prepare readyness + m_axis_data_tready = 1; // prepare readiness + @(negedge scl_o); - #(CLK_PERIOD); // let it cook - stop_on_idle=1; - //@(negedge scl_o); - @(posedge m_axis_data_tvalid); - $display("received m_axis_data_tdata %d",m_axis_data_tdata); - $display("received readiness %d",s_axis_cmd_ready); - @(posedge scl_o); if (sda_wire) begin - $fatal(1,"Got NACK from master") ; + $fatal(1, "Got NACK from master"); end -//pretend we got data - @(posedge s_axis_cmd_ready); - s_axis_cmd_valid = 0;//now stop - @(posedge s_axis_cmd_ready); - // Add a timeout + + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + #(CLK_PERIOD); + stop_on_idle = 1; + @(posedge m_axis_data_tvalid); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + $display("Received readiness %d", s_axis_cmd_ready); + s_axis_cmd_valid = 0; // now stop + + wait_for_ready(); #1000; + $display("Simulation ended due to timeout"); $finish; end - endmodule +endmodule + From 442ff55411f53d145c62ca67123bca66aab23892 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 29 Jun 2024 23:04:53 +0200 Subject: [PATCH 10/47] good progress --- rtl/i2c_master.v | 20 +++++------ rtl/i2c_master_tb.v | 87 +++++++++++++++++++++++++++++++++++++-------- rtl/i2c_phy.v | 4 +-- 3 files changed, 85 insertions(+), 26 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index fbfc570..57e800b 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -363,7 +363,7 @@ always @* begin s_axis_cmd_ready_next = 1'b1; if (s_axis_cmd_ready & s_axis_cmd_valid) begin - $display("ready and valid"); + //$display("ready and valid"); // command valid if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin // read or write command @@ -398,23 +398,23 @@ always @* begin end end else begin if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin - $display("Not here"); + //$display("Not here"); // no waiting command and stop_on_idle selected, issue stop condition phy_stop_bit = 1'b1; state_next = STATE_IDLE; end else begin - $display("From read to write?"); + //$display("From read to write?"); state_next = STATE_ACTIVE_WRITE; end end end STATE_ACTIVE_READ: begin - $display("State active read"); + //$display("State active read"); // line active to current address s_axis_cmd_ready_next = ~m_axis_data_tvalid; if (s_axis_cmd_ready & s_axis_cmd_valid) begin - $display("ready and valid ative read"); + //$display("ready and valid ative read"); // command valid if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin // read or write command @@ -447,7 +447,7 @@ always @* begin state_next = STATE_READ; end end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin - $display("Not here active read"); + //$display("Not here active read"); // stop command // write nack for previous read phy_write_bit = 1'b1; @@ -471,8 +471,8 @@ always @* begin state_next = STATE_STOP; end else begin - $display("Active Read: conditions: %d, %d",s_axis_cmd_ready,~s_axis_cmd_valid); -$display("m_axis_data_tvalid %d ", m_axis_data_tvalid); + //$display("Active Read: conditions: %d, %d",s_axis_cmd_ready,~s_axis_cmd_valid); +//$display("m_axis_data_tvalid %d ", m_axis_data_tvalid); state_next = STATE_ACTIVE_READ; end end @@ -509,9 +509,9 @@ $display("m_axis_data_tvalid %d ", m_axis_data_tvalid); phy_write_bit = 1'b1; phy_tx_data = mode_read_reg; state_next = STATE_ADDRESS_1; - $display("should be %d",mode_read_reg); + //$display("should be %d",mode_read_reg); end else begin - $display("should be 0 %d",sda_o); + //$display("should be 0 %d",sda_o); // read ack bit phy_read_bit = 1'b1; state_next = STATE_ADDRESS_2; diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index c9d6ec3..ad07d49 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -49,19 +49,29 @@ wire missed_ack; // Additional wires for modeling pull-up resistors and open-drain outputs wire scl_wire; wire sda_wire; - reg sda2=1;//dummy registers - reg scl2=1;//dummy registers - + +// Existing dummy registers +reg sda2 = 1; +reg scl2 = 1; + +// New device (register) signals +wire sda_o_3; +//reg sda_o_3=1; +wire sda_t_3; +wire scl_o_3; +//reg scl_o_3=1; +wire scl_t_3; // Model pull-up resistors with weak pull-ups pullup(scl_wire); pullup(sda_wire); -// Model open-drain outputs -assign scl_wire = (scl_o & scl2) ? 1'bz : 1'b0; -assign sda_wire = (sda_o & sda2) ? 1'bz : 1'b0; +// Model open-drain outputs, including the new device +assign scl_wire = (scl_o & scl2 & scl_o_3) ? 1'bz : 1'b0; +assign sda_wire = (sda_o & sda2 & sda_o_3) ? 1'bz : 1'b0; + +always #(CLK_PERIOD / 2) clk <= ~clk; - always #(CLK_PERIOD / 2) clk <= ~clk; // Sample the bus with non-blocking assignments to avoid race conditions always @(posedge clk or posedge rst) begin if (rst) begin @@ -71,19 +81,38 @@ always @(posedge clk or posedge rst) begin scl_i <= scl_wire; sda_i <= sda_wire; - // Assert that sda_i_reg_tb is not X - if (sda_i === 1'bx) $fatal(1, "sda_i_reg_tb is X at time %t", $time); + // Assert that sda_i is not X + if (sda_i === 1'bx) $fatal(1, "sda_i is X at time %t", $time); end end - initial begin // dump file $dumpfile("i2c_master_tb.vcd"); $dumpvars(0, test_i2c_master); end +reg [7:0] data_in_3; +reg data_latch_3; +wire [7:0] data_out_3; +i2c_single_reg #( + .FILTER_LEN(4), + .DEV_ADDR(7'h70) +) i2c_reg ( + .clk(clk), + .rst(rst), + .scl_i(scl_wire), + .scl_o(scl_o_3), + .scl_t(scl_t_3), + .sda_i(sda_wire), + .sda_o(sda_o_3), + .sda_t(sda_t_3), + + .data_in(data_in_3), + .data_latch(data_latch_3), + .data_out(data_out_3) +); i2c_master UUT ( .clk(clk), @@ -198,6 +227,7 @@ task send_byte; initial begin $display("Starting I2C Master test"); initialize_testbench; + $display("Testing NACK handling."); // Set address to 00000001, command to write i2c_start(7'b0000001, 0); @@ -210,6 +240,7 @@ initial begin wait_for_ready(); + $display("Testing Writing."); // Second write attempt i2c_start(7'b0000001, 0); s_axis_data_tdata = 8'b10101111; @@ -232,7 +263,7 @@ initial begin s_axis_data_tvalid = 1; i2c_start(7'b0000001, 1); - $display("Now doing a read"); + $display("Testing reading."); // Hardcoding the acknowledgement repeat(7) @(negedge scl_o); @@ -253,17 +284,45 @@ initial begin end $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata!=8'b01111111) begin + $fatal(1, "We didn't get what we sent"); + end #(CLK_PERIOD); stop_on_idle = 1; + + send_byte(8'd69); @(posedge m_axis_data_tvalid); + if (m_axis_data_tdata!=8'd69) begin + $fatal(1, "We didn't get what we sent"); + end $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - $display("Received readiness %d", s_axis_cmd_ready); s_axis_cmd_valid = 0; // now stop wait_for_ready(); - #1000; + wait_for_ready(); + $display("Testing i2c_single_reg writing"); + i2c_start(7'h70, 0); + s_axis_data_tdata = 8'd55; + s_axis_data_tvalid = 1; + + wait_for_ready(); + if (data_out_3!=8'd55) begin + $fatal(1, "We didn't get what we sent"); + end + $display("Received data %d", data_out_3); + data_latch_3=1; + data_in_3=8'd123; + $display("Testing i2c_single_reg reading"); + #(CLK_PERIOD); + data_latch_3=0; + i2c_start(7'h70, 1); + @(posedge m_axis_data_tvalid); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata!=8'd123) begin + $fatal(1, "We didn't get what we sent"); + end - $display("Simulation ended due to timeout"); + #1000; $finish; end endmodule diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index 8f5db48..ca7104e 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -129,7 +129,7 @@ module i2c_phy ( PHY_STATE_ACTIVE: begin // bus active if (phy_start_bit) begin - $display("start bit should have reset"); + //$display("start bit should have reset"); sda_o_next = 1'b1; delay_next = prescale; @@ -147,7 +147,7 @@ module i2c_phy ( delay_next = prescale; phy_state_next = PHY_STATE_STOP_1; end else begin - $display("Do nothing, leave things as is"); + //$display("Do nothing, leave things as is"); phy_state_next = PHY_STATE_ACTIVE; end end From e6691ad007c33956b3c1746b4638b89b01e28755 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 10:07:55 +0200 Subject: [PATCH 11/47] Refactored register assignments and state transitions in i2c_single_reg module. --- rtl/i2c_single_reg.v | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index 035238c..2ac19bb 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -67,25 +67,25 @@ localparam [4:0] STATE_READ_2 = 4'd6, STATE_READ_3 = 4'd7; -reg [4:0] state_reg = STATE_IDLE; +reg [4:0] state_reg; -reg [7:0] data_reg = 8'd0; -reg [7:0] shift_reg = 8'd0; +reg [7:0] data_reg; +reg [7:0] shift_reg; -reg mode_read_reg = 1'b0; +reg mode_read_reg; -reg [3:0] bit_count_reg = 4'd0; +reg [3:0] bit_count_reg; -reg [FILTER_LEN-1:0] scl_i_filter_reg = {FILTER_LEN{1'b1}}; -reg [FILTER_LEN-1:0] sda_i_filter_reg = {FILTER_LEN{1'b1}}; +reg [FILTER_LEN-1:0] scl_i_filter_reg; +reg [FILTER_LEN-1:0] sda_i_filter_reg; -reg scl_i_reg = 1'b1; -reg sda_i_reg = 1'b1; +reg scl_i_reg; +reg sda_i_reg; -reg sda_o_reg = 1'b1; +reg sda_o_reg; -reg last_scl_i_reg = 1'b1; -reg last_sda_i_reg = 1'b1; +reg last_scl_i_reg; +reg last_sda_i_reg; assign scl_o = 1'b1; assign scl_t = 1'b1; @@ -107,7 +107,7 @@ always @(posedge clk) begin if (start_bit) begin sda_o_reg <= 1'b1; - bit_count_reg = 4'd7; + bit_count_reg <= 4'd7; state_reg <= STATE_ADDRESS; end else if (stop_bit) begin sda_o_reg <= 1'b1; @@ -193,16 +193,16 @@ always @(posedge clk) begin // read data byte if (scl_negedge) begin // shift out data bit - {sda_o_reg, shift_reg} = {shift_reg, sda_i_reg}; + {sda_o_reg, shift_reg} <= {shift_reg, sda_i_reg}; if (bit_count_reg > 0) begin - bit_count_reg = bit_count_reg-1; - state_reg = STATE_READ_1; + bit_count_reg <= bit_count_reg-1; + state_reg <= STATE_READ_1; end else begin - state_reg = STATE_READ_2; + state_reg <= STATE_READ_2; end end else begin - state_reg = STATE_READ_1; + state_reg <= STATE_READ_1; end end STATE_READ_2: begin @@ -231,6 +231,7 @@ always @(posedge clk) begin state_reg <= STATE_READ_3; end end + default: $display("This should never happen"); endcase end From af1280d49251797c66ea3cc9ccd17a94d3298355 Mon Sep 17 00:00:00 2001 From: "Kreijstal (aider)" Date: Sun, 30 Jun 2024 10:07:56 +0200 Subject: [PATCH 12/47] Updated state values to 5 bits in i2c_single_reg module. --- rtl/i2c_single_reg.v | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index 2ac19bb..cc11ce4 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -58,14 +58,14 @@ module i2c_single_reg #( ); localparam [4:0] - STATE_IDLE = 4'd0, - STATE_ADDRESS = 4'd1, - STATE_ACK = 4'd2, - STATE_WRITE_1 = 4'd3, - STATE_WRITE_2 = 4'd4, - STATE_READ_1 = 4'd5, - STATE_READ_2 = 4'd6, - STATE_READ_3 = 4'd7; + STATE_IDLE = 5'd0, + STATE_ADDRESS = 5'd1, + STATE_ACK = 5'd2, + STATE_WRITE_1 = 5'd3, + STATE_WRITE_2 = 5'd4, + STATE_READ_1 = 5'd5, + STATE_READ_2 = 5'd6, + STATE_READ_3 = 5'd7; reg [4:0] state_reg; From 9fd5aa9ebf0eae1f0e2bb577f9ade09bd8b9d37f Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 10:15:58 +0200 Subject: [PATCH 13/47] It now works with verilator --- rtl/i2c_single_reg.v | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index cc11ce4..20b299a 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -238,9 +238,8 @@ always @(posedge clk) begin if (data_latch) begin data_reg <= data_in; end - - scl_i_filter_reg <= (scl_i_filter_reg << 1) | scl_i; - sda_i_filter_reg <= (sda_i_filter_reg << 1) | sda_i; + scl_i_filter_reg <= (scl_i_filter_reg << 1) | {3'b000, scl_i}; + sda_i_filter_reg <= (sda_i_filter_reg << 1) | {3'b000, sda_i}; if (scl_i_filter_reg == {FILTER_LEN{1'b1}}) begin scl_i_reg <= 1'b1; From fa5d02516ce398ae92a13fba940fec50c71d6440 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 11:17:52 +0200 Subject: [PATCH 14/47] some changes --- rtl/i2c_master.v | 812 +++++++++++++++++++++---------------------- rtl/i2c_master_tb.v | 495 +++++++++++++------------- rtl/i2c_phy.v | 37 +- rtl/i2c_single_reg.v | 333 +++++++++--------- rtl/i2c_slave.v | 499 +++++++++++++------------- 5 files changed, 1085 insertions(+), 1091 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 57e800b..34b1234 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -30,57 +30,57 @@ THE SOFTWARE. * I2C master */ module i2c_master ( - input wire clk, - input wire rst, + input wire clk, + input wire rst, /* * Host interface */ - input wire [6:0] s_axis_cmd_address, - input wire s_axis_cmd_start, - input wire s_axis_cmd_read, - input wire s_axis_cmd_write, - input wire s_axis_cmd_write_multiple, - input wire s_axis_cmd_stop, - input wire s_axis_cmd_valid, - output wire s_axis_cmd_ready, - - input wire [7:0] s_axis_data_tdata, - input wire s_axis_data_tvalid, - output wire s_axis_data_tready, - input wire s_axis_data_tlast, - - output wire [7:0] m_axis_data_tdata, - output wire m_axis_data_tvalid, - input wire m_axis_data_tready, - output wire m_axis_data_tlast, + input wire [6:0] s_axis_cmd_address, + input wire s_axis_cmd_start, + input wire s_axis_cmd_read, + input wire s_axis_cmd_write, + input wire s_axis_cmd_write_multiple, + input wire s_axis_cmd_stop, + input wire s_axis_cmd_valid, + output wire s_axis_cmd_ready, + + input wire [7:0] s_axis_data_tdata, + input wire s_axis_data_tvalid, + output wire s_axis_data_tready, + input wire s_axis_data_tlast, + + output wire [7:0] m_axis_data_tdata, + output wire m_axis_data_tvalid, + input wire m_axis_data_tready, + output wire m_axis_data_tlast, /* * I2C interface */ - input wire scl_i, - output wire scl_o, - output wire scl_t, - input wire sda_i, - output wire sda_o, - output wire sda_t, + input wire scl_i, + output wire scl_o, + output wire scl_t, + input wire sda_i, + output wire sda_o, + output wire sda_t, /* * Status */ - output wire busy, - output wire bus_control, - output wire bus_active, - output wire missed_ack, + output wire busy, + output wire bus_control, + output wire bus_active, + output wire missed_ack, /* * Configuration */ - input wire [15:0] prescale, - input wire stop_on_idle + input wire [15:0] prescale, + input wire stop_on_idle ); -/* + /* I2C @@ -181,7 +181,7 @@ scl_o should not be connected directly to scl_i, only via AND logic or a tristat I/O pin. This would prevent devices from stretching the clock period. */ -localparam [4:0] + localparam [4:0] STATE_IDLE = 5'd0, STATE_ACTIVE_WRITE = 5'd1, STATE_ACTIVE_READ = 5'd2, @@ -196,9 +196,9 @@ localparam [4:0] STATE_STOP = 5'd11; -reg [4:0] state_reg = STATE_IDLE, state_next; + reg [4:0] state_reg = STATE_IDLE, state_next; -localparam [4:0] + localparam [4:0] PHY_STATE_IDLE = 5'd0, PHY_STATE_ACTIVE = 5'd1, PHY_STATE_REPEATED_START_1 = 5'd2, @@ -216,81 +216,81 @@ localparam [4:0] PHY_STATE_STOP_2 = 5'd14, PHY_STATE_STOP_3 = 5'd15; -wire [4:0] phy_state_reg; + wire [4:0] phy_state_reg; -reg phy_start_bit; -reg phy_stop_bit; -reg phy_write_bit; -reg phy_read_bit; -reg phy_release_bus; + reg phy_start_bit; + reg phy_stop_bit; + reg phy_write_bit; + reg phy_read_bit; + reg phy_release_bus; -reg phy_tx_data; + reg phy_tx_data; -//reg phy_rx_data_reg = 1'b0, phy_rx_data_next; -wire phy_rx_data_reg; + //reg phy_rx_data_reg = 1'b0, phy_rx_data_next; + wire phy_rx_data_reg; -reg [6:0] addr_reg = 7'd0, addr_next; -reg [7:0] data_reg = 8'd0, data_next; -reg last_reg = 1'b0, last_next; + reg [6:0] addr_reg = 7'd0, addr_next; + reg [7:0] data_reg = 8'd0, data_next; + reg last_reg = 1'b0, last_next; -reg mode_read_reg = 1'b0, mode_read_next; -reg mode_write_multiple_reg = 1'b0, mode_write_multiple_next; -reg mode_stop_reg = 1'b0, mode_stop_next; + reg mode_read_reg = 1'b0, mode_read_next; + reg mode_write_multiple_reg = 1'b0, mode_write_multiple_next; + reg mode_stop_reg = 1'b0, mode_stop_next; -reg [3:0] bit_count_reg = 4'd0, bit_count_next; + reg [3:0] bit_count_reg = 4'd0, bit_count_next; -reg s_axis_cmd_ready_reg = 1'b0, s_axis_cmd_ready_next; + reg s_axis_cmd_ready_reg = 1'b0, s_axis_cmd_ready_next; -reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; + reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; -reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; -reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; -reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; + reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; + reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; + reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; -reg scl_i_reg = 1'b1; -reg sda_i_reg = 1'b1; + reg scl_i_reg = 1'b1; + reg sda_i_reg = 1'b1; -reg scl_o_reg = 1'b1, scl_o_next; -reg sda_o_reg = 1'b1, sda_o_next; + reg scl_o_reg = 1'b1, scl_o_next; + reg sda_o_reg = 1'b1, sda_o_next; -reg last_scl_i_reg = 1'b1; -reg last_sda_i_reg = 1'b1; + reg last_scl_i_reg = 1'b1; + reg last_sda_i_reg = 1'b1; -reg busy_reg = 1'b0; -reg bus_active_reg = 1'b0; -wire bus_control_reg; -wire phy_busy; -//reg bus_control_reg = 1'b0, bus_control_next; -reg missed_ack_reg = 1'b0, missed_ack_next; + reg busy_reg = 1'b0; + reg bus_active_reg = 1'b0; + wire bus_control_reg; + wire phy_busy; + //reg bus_control_reg = 1'b0, bus_control_next; + reg missed_ack_reg = 1'b0, missed_ack_next; -assign s_axis_cmd_ready = s_axis_cmd_ready_reg; + assign s_axis_cmd_ready = s_axis_cmd_ready_reg; -assign s_axis_data_tready = s_axis_data_tready_reg; + assign s_axis_data_tready = s_axis_data_tready_reg; -assign m_axis_data_tdata = m_axis_data_tdata_reg; -assign m_axis_data_tvalid = m_axis_data_tvalid_reg; -assign m_axis_data_tlast = m_axis_data_tlast_reg; + assign m_axis_data_tdata = m_axis_data_tdata_reg; + assign m_axis_data_tvalid = m_axis_data_tvalid_reg; + assign m_axis_data_tlast = m_axis_data_tlast_reg; -//assign scl_o = scl_o_reg; -//assign scl_t = scl_o_reg; -//assign sda_o = sda_o_reg; -//assign sda_t = sda_o_reg; + //assign scl_o = scl_o_reg; + //assign scl_t = scl_o_reg; + //assign sda_o = sda_o_reg; + //assign sda_t = sda_o_reg; -assign busy = busy_reg; -assign bus_active = bus_active_reg; -assign bus_control = bus_control_reg; -assign missed_ack = missed_ack_reg; + assign busy = busy_reg; + assign bus_active = bus_active_reg; + assign bus_control = bus_control_reg; + assign missed_ack = missed_ack_reg; -wire scl_posedge = scl_i_reg & ~last_scl_i_reg; -wire scl_negedge = ~scl_i_reg & last_scl_i_reg; -wire sda_posedge = sda_i_reg & ~last_sda_i_reg; -wire sda_negedge = ~sda_i_reg & last_sda_i_reg; + wire scl_posedge = scl_i_reg & ~last_scl_i_reg; + wire scl_negedge = ~scl_i_reg & last_scl_i_reg; + wire sda_posedge = sda_i_reg & ~last_sda_i_reg; + wire sda_negedge = ~sda_i_reg & last_sda_i_reg; -wire start_bit = sda_negedge & scl_i_reg; -wire stop_bit = sda_posedge & scl_i_reg; + wire start_bit = sda_negedge & scl_i_reg; + wire stop_bit = sda_posedge & scl_i_reg; -always @* begin + always @* begin state_next = STATE_IDLE; phy_start_bit = 1'b0; @@ -322,304 +322,301 @@ always @* begin // generate delays if (phy_state_reg != PHY_STATE_IDLE && phy_state_reg != PHY_STATE_ACTIVE) begin - // wait for phy operation - state_next = state_reg; + // wait for phy operation + state_next = state_reg; end else begin - // process states - case (state_reg) - STATE_IDLE: begin - // line idle - s_axis_cmd_ready_next = 1'b1; - - if (s_axis_cmd_ready & s_axis_cmd_valid) begin - // command valid - if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin - // read or write command - addr_next = s_axis_cmd_address; - mode_read_next = s_axis_cmd_read; - mode_write_multiple_next = s_axis_cmd_write_multiple; - mode_stop_next = s_axis_cmd_stop; - - s_axis_cmd_ready_next = 1'b0; - - // start bit - if (bus_active) begin - state_next = STATE_START_WAIT; - end else begin - phy_start_bit = 1'b1; - bit_count_next = 4'd8; - state_next = STATE_ADDRESS_1; - end - end else begin - // invalid or unspecified - ignore - state_next = STATE_IDLE; - end - end else begin - state_next = STATE_IDLE; - end - end - STATE_ACTIVE_WRITE: begin - // line active with current address and read/write mode - s_axis_cmd_ready_next = 1'b1; - - if (s_axis_cmd_ready & s_axis_cmd_valid) begin - //$display("ready and valid"); - // command valid - if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin - // read or write command - addr_next = s_axis_cmd_address; - mode_read_next = s_axis_cmd_read; - mode_write_multiple_next = s_axis_cmd_write_multiple; - mode_stop_next = s_axis_cmd_stop; - - s_axis_cmd_ready_next = 1'b0; - - if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_read) begin - // address or mode mismatch or forced start - repeated start - - // repeated start bit - phy_start_bit = 1'b1; - bit_count_next = 4'd8; - state_next = STATE_ADDRESS_1; - end else begin - // address and mode match - - // start write - s_axis_data_tready_next = 1'b1; - state_next = STATE_WRITE_1; - end - end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin - // stop command - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; - end else begin - // invalid or unspecified - ignore - state_next = STATE_ACTIVE_WRITE; - end - end else begin - if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin - //$display("Not here"); - // no waiting command and stop_on_idle selected, issue stop condition - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; - end else begin - //$display("From read to write?"); - state_next = STATE_ACTIVE_WRITE; - end - end - end - STATE_ACTIVE_READ: begin - //$display("State active read"); - // line active to current address - s_axis_cmd_ready_next = ~m_axis_data_tvalid; - - if (s_axis_cmd_ready & s_axis_cmd_valid) begin - //$display("ready and valid ative read"); - // command valid - if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin - // read or write command - addr_next = s_axis_cmd_address; - mode_read_next = s_axis_cmd_read; - mode_write_multiple_next = s_axis_cmd_write_multiple; - mode_stop_next = s_axis_cmd_stop; - - s_axis_cmd_ready_next = 1'b0; - - if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_write) begin - // address or mode mismatch or forced start - repeated start - - // write nack for previous read - $display("mode mismatch forced restart, write nack"); - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - // repeated start bit - state_next = STATE_START; - end else begin - // address and mode match - - $display("sending ack and continue with next read"); - // write ack for previous read - phy_write_bit = 1'b1; - phy_tx_data = 1'b0; - // start next read - bit_count_next = 4'd8; - data_next = 8'd0; - state_next = STATE_READ; - end - end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin - //$display("Not here active read"); - // stop command - // write nack for previous read - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - // send stop bit - state_next = STATE_STOP; - end else begin - $display("active read: invalid or unspecified - ignore.. ?"); - // invalid or unspecified - ignore - state_next = STATE_ACTIVE_READ; - end - end else begin - - if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin - // no waiting command and stop_on_idle selected, issue stop condition - // write ack for previous read - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - // send stop bit - $display("got last bit and received, so stopping"); - - state_next = STATE_STOP; - end else begin - //$display("Active Read: conditions: %d, %d",s_axis_cmd_ready,~s_axis_cmd_valid); -//$display("m_axis_data_tvalid %d ", m_axis_data_tvalid); - state_next = STATE_ACTIVE_READ; - end - end - end - STATE_START_WAIT: begin - // wait for bus idle - - if (bus_active) begin - state_next = STATE_START_WAIT; - end else begin - // bus is idle, take control - phy_start_bit = 1'b1; - bit_count_next = 4'd8; - state_next = STATE_ADDRESS_1; - end - end - STATE_START: begin - // send start bit - + // process states + case (state_reg) + STATE_IDLE: begin + // line idle + s_axis_cmd_ready_next = 1'b1; + + if (s_axis_cmd_ready & s_axis_cmd_valid) begin + // command valid + if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin + // read or write command + addr_next = s_axis_cmd_address; + mode_read_next = s_axis_cmd_read; + mode_write_multiple_next = s_axis_cmd_write_multiple; + mode_stop_next = s_axis_cmd_stop; + + s_axis_cmd_ready_next = 1'b0; + + // start bit + if (bus_active) begin + state_next = STATE_START_WAIT; + end else begin phy_start_bit = 1'b1; bit_count_next = 4'd8; state_next = STATE_ADDRESS_1; + end + end else begin + // invalid or unspecified - ignore + state_next = STATE_IDLE; end - STATE_ADDRESS_1: begin - // send address - bit_count_next = bit_count_reg - 1; - if (bit_count_reg > 1) begin - // send address - phy_write_bit = 1'b1; - phy_tx_data = addr_reg[bit_count_reg-2]; - state_next = STATE_ADDRESS_1; - end else if (bit_count_reg > 0) begin - // send read/write bit - phy_write_bit = 1'b1; - phy_tx_data = mode_read_reg; - state_next = STATE_ADDRESS_1; - //$display("should be %d",mode_read_reg); - end else begin - //$display("should be 0 %d",sda_o); - // read ack bit - phy_read_bit = 1'b1; - state_next = STATE_ADDRESS_2; - end - end - STATE_ADDRESS_2: begin - // read ack bit - missed_ack_next = phy_rx_data_reg; - if (missed_ack_next) begin - $display("got NACK"); - end - else - $display("got ACK"); - - if (mode_read_reg) begin - // start read - bit_count_next = 4'd8; - data_next = 8'b0; - state_next = STATE_READ; - end else begin - // start write - s_axis_data_tready_next = 1'b1; - state_next = STATE_WRITE_1; - end - end - STATE_WRITE_1: begin - s_axis_data_tready_next = 1'b1; + end else begin + state_next = STATE_IDLE; + end + end + STATE_ACTIVE_WRITE: begin + // line active with current address and read/write mode + s_axis_cmd_ready_next = 1'b1; + + if (s_axis_cmd_ready & s_axis_cmd_valid) begin + //$display("ready and valid"); + // command valid + if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin + // read or write command + addr_next = s_axis_cmd_address; + mode_read_next = s_axis_cmd_read; + mode_write_multiple_next = s_axis_cmd_write_multiple; + mode_stop_next = s_axis_cmd_stop; + + s_axis_cmd_ready_next = 1'b0; + + if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_read) begin + // address or mode mismatch or forced start - repeated start + + // repeated start bit + phy_start_bit = 1'b1; + bit_count_next = 4'd8; + state_next = STATE_ADDRESS_1; + end else begin + // address and mode match - if (s_axis_data_tready & s_axis_data_tvalid) begin - // got data, start write - data_next = s_axis_data_tdata; - last_next = s_axis_data_tlast; - bit_count_next = 4'd8; - s_axis_data_tready_next = 1'b0; - state_next = STATE_WRITE_2; - end else begin - // wait for data - state_next = STATE_WRITE_1; - end + // start write + s_axis_data_tready_next = 1'b1; + state_next = STATE_WRITE_1; + end + end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin + // stop command + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end else begin + // invalid or unspecified - ignore + state_next = STATE_ACTIVE_WRITE; end - STATE_WRITE_2: begin - // send data - bit_count_next = bit_count_reg - 1; - if (bit_count_reg > 0) begin - // write data bit - phy_write_bit = 1'b1; - phy_tx_data = data_reg[bit_count_reg-1]; - state_next = STATE_WRITE_2; - end else begin - // read ack bit - phy_read_bit = 1'b1; - state_next = STATE_WRITE_3; - end + end else begin + if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin + //$display("Not here"); + // no waiting command and stop_on_idle selected, issue stop condition + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end else begin + //$display("From read to write?"); + state_next = STATE_ACTIVE_WRITE; end - STATE_WRITE_3: begin - // read ack bit - missed_ack_next = phy_rx_data_reg; - - if (mode_write_multiple_reg && !last_reg) begin - // more to write - state_next = STATE_WRITE_1; - end else if (mode_stop_reg) begin - // last cycle and stop selected - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; - end else begin - // otherwise, return to bus active state - state_next = STATE_ACTIVE_WRITE; - end + end + end + STATE_ACTIVE_READ: begin + //$display("State active read"); + // line active to current address + s_axis_cmd_ready_next = ~m_axis_data_tvalid; + + if (s_axis_cmd_ready & s_axis_cmd_valid) begin + //$display("ready and valid ative read"); + // command valid + if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin + // read or write command + addr_next = s_axis_cmd_address; + mode_read_next = s_axis_cmd_read; + mode_write_multiple_next = s_axis_cmd_write_multiple; + mode_stop_next = s_axis_cmd_stop; + + s_axis_cmd_ready_next = 1'b0; + + if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_write) begin + // address or mode mismatch or forced start - repeated start + + // write nack for previous read + $display("mode mismatch forced restart, write nack"); + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + // repeated start bit + state_next = STATE_START; + end else begin + // address and mode match + + $display("sending ack and continue with next read"); + // write ack for previous read + phy_write_bit = 1'b1; + phy_tx_data = 1'b0; + // start next read + bit_count_next = 4'd8; + data_next = 8'd0; + state_next = STATE_READ; + end + end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin + //$display("Not here active read"); + // stop command + // write nack for previous read + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + // send stop bit + state_next = STATE_STOP; + end else begin + $display("active read: invalid or unspecified - ignore.. ?"); + // invalid or unspecified - ignore + state_next = STATE_ACTIVE_READ; end - STATE_READ: begin - // read data - - bit_count_next = bit_count_reg - 1; - data_next = {data_reg[6:0], phy_rx_data_reg}; - if (bit_count_reg > 0) begin - // read next bit - phy_read_bit = 1'b1; - state_next = STATE_READ; - end else begin - // output data word - m_axis_data_tdata_next = data_next; - m_axis_data_tvalid_next = 1'b1; - m_axis_data_tlast_next = 1'b0; - if (mode_stop_reg) begin - // send nack and stop - m_axis_data_tlast_next = 1'b1; - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - state_next = STATE_STOP; - end else begin - // return to bus active state - state_next = STATE_ACTIVE_READ; - end - end + end else begin + + if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin + // no waiting command and stop_on_idle selected, issue stop condition + // write ack for previous read + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + // send stop bit + $display("got last bit and received, so stopping"); + + state_next = STATE_STOP; + end else begin + //$display("Active Read: conditions: %d, %d",s_axis_cmd_ready,~s_axis_cmd_valid); + //$display("m_axis_data_tvalid %d ", m_axis_data_tvalid); + state_next = STATE_ACTIVE_READ; end - STATE_STOP: begin - // send stop bit - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; + end + end + STATE_START_WAIT: begin + // wait for bus idle + + if (bus_active) begin + state_next = STATE_START_WAIT; + end else begin + // bus is idle, take control + phy_start_bit = 1'b1; + bit_count_next = 4'd8; + state_next = STATE_ADDRESS_1; + end + end + STATE_START: begin + // send start bit + + phy_start_bit = 1'b1; + bit_count_next = 4'd8; + state_next = STATE_ADDRESS_1; + end + STATE_ADDRESS_1: begin + // send address + bit_count_next = bit_count_reg - 1; + if (bit_count_reg > 1) begin + // send address + phy_write_bit = 1'b1; + phy_tx_data = addr_reg[bit_count_reg-2]; + state_next = STATE_ADDRESS_1; + end else if (bit_count_reg > 0) begin + // send read/write bit + phy_write_bit = 1'b1; + phy_tx_data = mode_read_reg; + state_next = STATE_ADDRESS_1; + //$display("should be %d",mode_read_reg); + end else begin + //$display("should be 0 %d",sda_o); + // read ack bit + phy_read_bit = 1'b1; + state_next = STATE_ADDRESS_2; + end + end + STATE_ADDRESS_2: begin + // read ack bit + missed_ack_next = phy_rx_data_reg; + if (missed_ack_next) begin + $display("got NACK"); + end else $display("got ACK"); + + if (mode_read_reg) begin + // start read + bit_count_next = 4'd8; + data_next = 8'b0; + state_next = STATE_READ; + end else begin + // start write + s_axis_data_tready_next = 1'b1; + state_next = STATE_WRITE_1; + end + end + STATE_WRITE_1: begin + s_axis_data_tready_next = 1'b1; + + if (s_axis_data_tready & s_axis_data_tvalid) begin + // got data, start write + data_next = s_axis_data_tdata; + last_next = s_axis_data_tlast; + bit_count_next = 4'd8; + s_axis_data_tready_next = 1'b0; + state_next = STATE_WRITE_2; + end else begin + // wait for data + state_next = STATE_WRITE_1; + end + end + STATE_WRITE_2: begin + // send data + bit_count_next = bit_count_reg - 1; + if (bit_count_reg > 0) begin + // write data bit + phy_write_bit = 1'b1; + phy_tx_data = data_reg[bit_count_reg-1]; + state_next = STATE_WRITE_2; + end else begin + // read ack bit + phy_read_bit = 1'b1; + state_next = STATE_WRITE_3; + end + end + STATE_WRITE_3: begin + // read ack bit + missed_ack_next = phy_rx_data_reg; + + if (mode_write_multiple_reg && !last_reg) begin + // more to write + state_next = STATE_WRITE_1; + end else if (mode_stop_reg) begin + // last cycle and stop selected + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end else begin + // otherwise, return to bus active state + state_next = STATE_ACTIVE_WRITE; + end + end + STATE_READ: begin + // read data + + bit_count_next = bit_count_reg - 1; + data_next = {data_reg[6:0], phy_rx_data_reg}; + if (bit_count_reg > 0) begin + // read next bit + phy_read_bit = 1'b1; + state_next = STATE_READ; + end else begin + // output data word + m_axis_data_tdata_next = data_next; + m_axis_data_tvalid_next = 1'b1; + m_axis_data_tlast_next = 1'b0; + if (mode_stop_reg) begin + // send nack and stop + m_axis_data_tlast_next = 1'b1; + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + state_next = STATE_STOP; + end else begin + // return to bus active state + state_next = STATE_ACTIVE_READ; end - default: $display("I don't think case default should get triggered"); - endcase + end + end + STATE_STOP: begin + // send stop bit + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end + default: $display("I don't think case default should get triggered"); + endcase end -end + end -i2c_phy phy_instance -( + i2c_phy phy_instance ( .clk(clk), .rst(rst), .phy_start_bit(phy_start_bit), @@ -642,55 +639,56 @@ i2c_phy phy_instance ); -always @(posedge clk) begin - state_reg <= state_next; + always @(posedge clk or negedge rst) begin + if (rst) begin + state_reg <= STATE_IDLE; + s_axis_cmd_ready_reg <= 1'b0; + s_axis_data_tready_reg <= 1'b0; + m_axis_data_tvalid_reg <= 1'b0; + busy_reg <= 1'b0; + missed_ack_reg <= 1'b0; + + end else begin + state_reg <= state_next; - addr_reg <= addr_next; - data_reg <= data_next; - last_reg <= last_next; + addr_reg <= addr_next; + data_reg <= data_next; + last_reg <= last_next; - mode_read_reg <= mode_read_next; - mode_write_multiple_reg <= mode_write_multiple_next; - mode_stop_reg <= mode_stop_next; + mode_read_reg <= mode_read_next; + mode_write_multiple_reg <= mode_write_multiple_next; + mode_stop_reg <= mode_stop_next; - bit_count_reg <= bit_count_next; + bit_count_reg <= bit_count_next; - s_axis_cmd_ready_reg <= s_axis_cmd_ready_next; + s_axis_cmd_ready_reg <= s_axis_cmd_ready_next; - s_axis_data_tready_reg <= s_axis_data_tready_next; + s_axis_data_tready_reg <= s_axis_data_tready_next; - m_axis_data_tdata_reg <= m_axis_data_tdata_next; - m_axis_data_tlast_reg <= m_axis_data_tlast_next; - m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; + m_axis_data_tdata_reg <= m_axis_data_tdata_next; + m_axis_data_tlast_reg <= m_axis_data_tlast_next; + m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; - scl_i_reg <= scl_i; - sda_i_reg <= sda_i; + scl_i_reg <= scl_i; + sda_i_reg <= sda_i; - last_scl_i_reg <= scl_i_reg; - last_sda_i_reg <= sda_i_reg; + last_scl_i_reg <= scl_i_reg; + last_sda_i_reg <= sda_i_reg; - busy_reg <= !(state_reg == STATE_IDLE || state_reg == STATE_ACTIVE_WRITE || state_reg == STATE_ACTIVE_READ) || !(phy_state_reg == PHY_STATE_IDLE || phy_state_reg == PHY_STATE_ACTIVE); + busy_reg <= !(state_reg == STATE_IDLE || state_reg == STATE_ACTIVE_WRITE || state_reg == STATE_ACTIVE_READ) || !(phy_state_reg == PHY_STATE_IDLE || phy_state_reg == PHY_STATE_ACTIVE); - if (start_bit) begin + if (start_bit) begin bus_active_reg <= 1'b1; - end else if (stop_bit) begin + end else if (stop_bit) begin bus_active_reg <= 1'b0; - end else begin + end else begin bus_active_reg <= bus_active_reg; - end + end - missed_ack_reg <= missed_ack_next; - - if (rst) begin - state_reg <= STATE_IDLE; - s_axis_cmd_ready_reg <= 1'b0; - s_axis_data_tready_reg <= 1'b0; - m_axis_data_tvalid_reg <= 1'b0; - busy_reg <= 1'b0; - missed_ack_reg <= 1'b0; + missed_ack_reg <= missed_ack_next; end -end + end endmodule diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index ad07d49..806dd81 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -1,153 +1,152 @@ // Language: Verilog 2001 -`timescale 1ns / 1ps +`timescale 1ns/1ps /* * Testbench for i2c_master */ -module test_i2c_master; +module i2c_master_tb; -// Parameters + // Parameters parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [6:0] s_axis_cmd_address = 0; -reg s_axis_cmd_start = 0; -reg s_axis_cmd_read = 0; -reg s_axis_cmd_write = 0; -reg s_axis_cmd_write_multiple = 0; -reg s_axis_cmd_stop = 0; -reg s_axis_cmd_valid = 0; -reg [7:0] s_axis_data_tdata = 0; -reg s_axis_data_tvalid = 0; -reg s_axis_data_tlast = 0; -reg m_axis_data_tready = 0; -reg scl_i = 1; -reg sda_i = 1; -reg [15:0] prescale = 0; -reg stop_on_idle = 0; - -// Outputs -wire s_axis_cmd_ready; -wire s_axis_data_tready; -wire [7:0] m_axis_data_tdata; -wire m_axis_data_tvalid; -wire m_axis_data_tlast; -wire scl_o; -wire scl_t; -wire sda_o; -wire sda_t; -wire busy; -wire bus_control; -wire bus_active; -wire missed_ack; - -// Additional wires for modeling pull-up resistors and open-drain outputs -wire scl_wire; -wire sda_wire; - -// Existing dummy registers -reg sda2 = 1; -reg scl2 = 1; - -// New device (register) signals -wire sda_o_3; -//reg sda_o_3=1; -wire sda_t_3; -wire scl_o_3; -//reg scl_o_3=1; -wire scl_t_3; - -// Model pull-up resistors with weak pull-ups -pullup(scl_wire); -pullup(sda_wire); - -// Model open-drain outputs, including the new device -assign scl_wire = (scl_o & scl2 & scl_o_3) ? 1'bz : 1'b0; -assign sda_wire = (sda_o & sda2 & sda_o_3) ? 1'bz : 1'b0; - -always #(CLK_PERIOD / 2) clk <= ~clk; - -// Sample the bus with non-blocking assignments to avoid race conditions -always @(posedge clk or posedge rst) begin + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [6:0] s_axis_cmd_address = 0; + reg s_axis_cmd_start = 0; + reg s_axis_cmd_read = 0; + reg s_axis_cmd_write = 0; + reg s_axis_cmd_write_multiple = 0; + reg s_axis_cmd_stop = 0; + reg s_axis_cmd_valid = 0; + reg [7:0] s_axis_data_tdata = 0; + reg s_axis_data_tvalid = 0; + reg s_axis_data_tlast = 0; + reg m_axis_data_tready = 0; + reg scl_i = 1; + reg sda_i = 1; + reg [15:0] prescale = 0; + reg stop_on_idle = 0; + + // Outputs + wire s_axis_cmd_ready; + wire s_axis_data_tready; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire scl_o; + wire scl_t; + wire sda_o; + wire sda_t; + wire busy; + wire bus_control; + wire bus_active; + wire missed_ack; + + // Additional wires for modeling pull-up resistors and open-drain outputs + wire scl_wire; + wire sda_wire; + + // Existing dummy registers + reg sda2 = 1; + reg scl2 = 1; + + // New device (register) signals + wire sda_o_3; + //reg sda_o_3=1; + wire sda_t_3; + wire scl_o_3; + //reg scl_o_3=1; + wire scl_t_3; + + // Model pull-up resistors with weak pull-ups + pullup (scl_wire); + pullup (sda_wire); + + // Model open-drain outputs, including the new device + assign scl_wire = (scl_o & scl2 & scl_o_3) ? 1'bz : 1'b0; + assign sda_wire = (sda_o & sda2 & sda_o_3) ? 1'bz : 1'b0; + + always #(CLK_PERIOD / 2) clk <= ~clk; + + // Sample the bus with non-blocking assignments to avoid race conditions + always @(posedge clk or posedge rst) begin if (rst) begin - scl_i <= 1'b1; - sda_i <= 1'b1; + scl_i <= 1'b1; + sda_i <= 1'b1; end else begin - scl_i <= scl_wire; - sda_i <= sda_wire; - - // Assert that sda_i is not X - if (sda_i === 1'bx) $fatal(1, "sda_i is X at time %t", $time); + scl_i <= scl_wire; + sda_i <= sda_wire; + + // Assert that sda_i is not X + if (sda_i === 1'bx) $fatal(1, "sda_i is X at time %t", $time); end -end + end -initial begin + initial begin // dump file - $dumpfile("i2c_master_tb.vcd"); - $dumpvars(0, test_i2c_master); - -end -reg [7:0] data_in_3; -reg data_latch_3; -wire [7:0] data_out_3; -i2c_single_reg #( - .FILTER_LEN(4), - .DEV_ADDR(7'h70) -) i2c_reg ( - .clk(clk), - .rst(rst), - - .scl_i(scl_wire), - .scl_o(scl_o_3), - .scl_t(scl_t_3), - .sda_i(sda_wire), - .sda_o(sda_o_3), - .sda_t(sda_t_3), - - .data_in(data_in_3), - .data_latch(data_latch_3), - .data_out(data_out_3) -); -i2c_master -UUT ( - .clk(clk), - .rst(rst), - .s_axis_cmd_address(s_axis_cmd_address), - .s_axis_cmd_start(s_axis_cmd_start), - .s_axis_cmd_read(s_axis_cmd_read), - .s_axis_cmd_write(s_axis_cmd_write), - .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), - .s_axis_cmd_stop(s_axis_cmd_stop), - .s_axis_cmd_valid(s_axis_cmd_valid), - .s_axis_cmd_ready(s_axis_cmd_ready), - .s_axis_data_tdata(s_axis_data_tdata), - .s_axis_data_tvalid(s_axis_data_tvalid), - .s_axis_data_tready(s_axis_data_tready), - .s_axis_data_tlast(s_axis_data_tlast), - .m_axis_data_tdata(m_axis_data_tdata), - .m_axis_data_tvalid(m_axis_data_tvalid), - .m_axis_data_tready(m_axis_data_tready), - .m_axis_data_tlast(m_axis_data_tlast), - .scl_i(scl_i), - .scl_o(scl_o), - .scl_t(scl_t), - .sda_i(sda_i), - .sda_o(sda_o), - .sda_t(sda_t), - .busy(busy), - .bus_control(bus_control), - .bus_active(bus_active), - .missed_ack(missed_ack), - .prescale(prescale), - .stop_on_idle(stop_on_idle) -); - - task initialize_testbench; + $dumpfile("i2c_master_tb.fst"); + $dumpvars(0, i2c_master_tb); + + end + reg [7:0] data_in_3; + reg data_latch_3; + wire [7:0] data_out_3; + i2c_single_reg #( + .FILTER_LEN(4), + .DEV_ADDR (7'h70) + ) i2c_reg ( + .clk(clk), + .rst(rst), + + .scl_i(scl_wire), + .scl_o(scl_o_3), + .scl_t(scl_t_3), + .sda_i(sda_wire), + .sda_o(sda_o_3), + .sda_t(sda_t_3), + + .data_in(data_in_3), + .data_latch(data_latch_3), + .data_out(data_out_3) + ); + i2c_master UUT ( + .clk(clk), + .rst(rst), + .s_axis_cmd_address(s_axis_cmd_address), + .s_axis_cmd_start(s_axis_cmd_start), + .s_axis_cmd_read(s_axis_cmd_read), + .s_axis_cmd_write(s_axis_cmd_write), + .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), + .s_axis_cmd_stop(s_axis_cmd_stop), + .s_axis_cmd_valid(s_axis_cmd_valid), + .s_axis_cmd_ready(s_axis_cmd_ready), + .s_axis_data_tdata(s_axis_data_tdata), + .s_axis_data_tvalid(s_axis_data_tvalid), + .s_axis_data_tready(s_axis_data_tready), + .s_axis_data_tlast(s_axis_data_tlast), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .scl_i(scl_i), + .scl_o(scl_o), + .scl_t(scl_t), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .busy(busy), + .bus_control(bus_control), + .bus_active(bus_active), + .missed_ack(missed_ack), + .prescale(prescale), + .stop_on_idle(stop_on_idle) + ); + + task initialize_testbench; begin clk = 0; rst = 1; @@ -183,29 +182,29 @@ UUT ( s_axis_cmd_write = !is_read; s_axis_cmd_valid = 1; - @(negedge sda_wire); - @(negedge scl_wire);//start condition done! - + @(negedge sda_wire); + @(negedge scl_wire); //start condition done! + s_axis_cmd_start = 0; - s_axis_cmd_read = 0; + s_axis_cmd_read = 0; s_axis_cmd_write = 0; s_axis_cmd_valid = 0; end endtask -task send_byte; - input [7:0] byte_to_send; - integer i; - begin - for (i = 7; i >= 0; i = i - 1) begin - sda2 = byte_to_send[i]; - @(negedge scl_o); + task send_byte; + input [7:0] byte_to_send; + integer i; + begin + for (i = 7; i >= 0; i = i - 1) begin + sda2 = byte_to_send[i]; + @(negedge scl_o); + end end - end endtask - task wait_for_ready; + task wait_for_ready; begin $display("Waiting for ready"); @(posedge s_axis_cmd_ready); @@ -213,7 +212,7 @@ task send_byte; end endtask - task send_ack; + task send_ack; begin @(negedge scl_o); sda2 = 0; @@ -224,107 +223,105 @@ task send_byte; endtask -initial begin - $display("Starting I2C Master test"); - initialize_testbench; - $display("Testing NACK handling."); - - // Set address to 00000001, command to write - i2c_start(7'b0000001, 0); - s_axis_data_tdata = 8'b10100101; - s_axis_data_tvalid = 1; - - // Wait for NACK - @(posedge missed_ack); - $display("NACK expected!"); - - wait_for_ready(); - - $display("Testing Writing."); - // Second write attempt - i2c_start(7'b0000001, 0); - s_axis_data_tdata = 8'b10101111; - s_axis_data_tvalid = 1; - - // Hardcoding the acknowledgement - repeat(7) @(negedge scl_o); - - // Send ACK - send_ack(); - @(negedge scl_o); // let 1 pass through - send_byte(8'b01111111); - stop_on_idle = 1; - - wait_for_ready(); - #1000; - - // Start is implied - s_axis_data_tdata = 8'b10101111; - s_axis_data_tvalid = 1; - i2c_start(7'b0000001, 1); - - $display("Testing reading."); - - // Hardcoding the acknowledgement - repeat(7) @(negedge scl_o); - - // Send ACK - s_axis_cmd_valid = 0; - send_ack(); - send_byte(8'b01111111); - - // Continue with next read (does not require i2c_start condition) - s_axis_cmd_read = 1; - s_axis_cmd_valid = 1; - m_axis_data_tready = 1; // prepare readiness - - @(negedge scl_o); - if (sda_wire) begin - $fatal(1, "Got NACK from master"); - end + initial begin + $display("Starting I2C Master test"); + initialize_testbench; + $display("Testing NACK handling."); - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - if (m_axis_data_tdata!=8'b01111111) begin - $fatal(1, "We didn't get what we sent"); - end - #(CLK_PERIOD); - stop_on_idle = 1; + // Set address to 00000001, command to write + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10100101; + s_axis_data_tvalid = 1; - send_byte(8'd69); - @(posedge m_axis_data_tvalid); - if (m_axis_data_tdata!=8'd69) begin - $fatal(1, "We didn't get what we sent"); - end - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - s_axis_cmd_valid = 0; // now stop - - wait_for_ready(); - wait_for_ready(); - $display("Testing i2c_single_reg writing"); - i2c_start(7'h70, 0); - s_axis_data_tdata = 8'd55; - s_axis_data_tvalid = 1; - - wait_for_ready(); - if (data_out_3!=8'd55) begin - $fatal(1, "We didn't get what we sent"); - end - $display("Received data %d", data_out_3); - data_latch_3=1; - data_in_3=8'd123; - $display("Testing i2c_single_reg reading"); - #(CLK_PERIOD); - data_latch_3=0; - i2c_start(7'h70, 1); - @(posedge m_axis_data_tvalid); - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - if (m_axis_data_tdata!=8'd123) begin - $fatal(1, "We didn't get what we sent"); - end + // Wait for NACK + @(posedge missed_ack); + $display("NACK expected!"); - #1000; - $finish; -end -endmodule + wait_for_ready(); + + $display("Testing Writing."); + // Second write attempt + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + + // Hardcoding the acknowledgement + repeat (7) @(negedge scl_o); + // Send ACK + send_ack(); + @(negedge scl_o); // let 1 pass through + send_byte(8'b01111111); + stop_on_idle = 1; + wait_for_ready(); + #1000; + + // Start is implied + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + i2c_start(7'b0000001, 1); + + $display("Testing reading."); + + // Hardcoding the acknowledgement + repeat (7) @(negedge scl_o); + + // Send ACK + s_axis_cmd_valid = 0; + send_ack(); + send_byte(8'b01111111); + + // Continue with next read (does not require i2c_start condition) + s_axis_cmd_read = 1; + s_axis_cmd_valid = 1; + m_axis_data_tready = 1; // prepare readiness + + @(negedge scl_o); + if (sda_wire) begin + $fatal(1, "Got NACK from master"); + end + + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'b01111111) begin + $fatal(1, "We didn't get what we sent"); + end + #(CLK_PERIOD); + stop_on_idle = 1; + + send_byte(8'd69); + @(posedge m_axis_data_tvalid); + if (m_axis_data_tdata != 8'd69) begin + $fatal(1, "We didn't get what we sent"); + end + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + s_axis_cmd_valid = 0; // now stop + + wait_for_ready(); + wait_for_ready(); + $display("Testing i2c_single_reg writing"); + i2c_start(7'h70, 0); + s_axis_data_tdata = 8'd55; + s_axis_data_tvalid = 1; + + wait_for_ready(); + if (data_out_3 != 8'd55) begin + $fatal(1, "We didn't get what we sent"); + end + $display("Received data %d", data_out_3); + data_latch_3 = 1; + data_in_3 = 8'd123; + $display("Testing i2c_single_reg reading"); + #(CLK_PERIOD); + data_latch_3 = 0; + i2c_start(7'h70, 1); + @(posedge m_axis_data_tvalid); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'd123) begin + $fatal(1, "We didn't get what we sent"); + end + + #1000; + $finish; + end +endmodule diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index ca7104e..a06922e 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -315,24 +315,7 @@ module i2c_phy ( end - always @(posedge clk) begin - phy_state_reg <= phy_state_next; - - phy_rx_data_reg <= phy_rx_data_next; - - - delay_reg <= delay_next; - delay_scl_reg <= delay_scl_next; - delay_sda_reg <= delay_sda_next; - - - scl_i_reg <= scl_i; - sda_i_reg <= sda_i; - - scl_o_reg <= scl_o_next; - sda_o_reg <= sda_o_next; - - bus_control_reg <= bus_control_next; + always @(posedge clk or negedge rst) begin if (rst) begin phy_rx_data_reg <= 1'b0; @@ -343,6 +326,24 @@ module i2c_phy ( scl_o_reg <= 1'b1; sda_o_reg <= 1'b1; bus_control_reg <= 1'b0; + end else begin + phy_state_reg <= phy_state_next; + + phy_rx_data_reg <= phy_rx_data_next; + + + delay_reg <= delay_next; + delay_scl_reg <= delay_scl_next; + delay_sda_reg <= delay_sda_next; + + + scl_i_reg <= scl_i; + sda_i_reg <= sda_i; + + scl_o_reg <= scl_o_next; + sda_o_reg <= sda_o_next; + + bus_control_reg <= bus_control_next; end end diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index 20b299a..d467164 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -24,8 +24,8 @@ THE SOFTWARE. // Language: Verilog 2001 -`resetall -`timescale 1ns / 1ps +`resetall +`timescale 1ns / 1ps `default_nettype none /* @@ -33,21 +33,20 @@ THE SOFTWARE. */ module i2c_single_reg #( parameter FILTER_LEN = 4, - parameter DEV_ADDR = 7'h70 -) -( - input wire clk, - input wire rst, + parameter DEV_ADDR = 7'h70 +) ( + input wire clk, + input wire rst, /* * I2C interface */ - input wire scl_i, - output wire scl_o, - output wire scl_t, - input wire sda_i, - output wire sda_o, - output wire sda_t, + input wire scl_i, + output wire scl_o, + output wire scl_t, + input wire sda_i, + output wire sda_o, + output wire sda_t, /* * Data register @@ -57,7 +56,7 @@ module i2c_single_reg #( output wire [7:0] data_out ); -localparam [4:0] + localparam [4:0] STATE_IDLE = 5'd0, STATE_ADDRESS = 5'd1, STATE_ACK = 5'd2, @@ -67,201 +66,201 @@ localparam [4:0] STATE_READ_2 = 5'd6, STATE_READ_3 = 5'd7; -reg [4:0] state_reg; + reg [4:0] state_reg; -reg [7:0] data_reg; -reg [7:0] shift_reg; + reg [7:0] data_reg; + reg [7:0] shift_reg; -reg mode_read_reg; + reg mode_read_reg; -reg [3:0] bit_count_reg; + reg [3:0] bit_count_reg; -reg [FILTER_LEN-1:0] scl_i_filter_reg; -reg [FILTER_LEN-1:0] sda_i_filter_reg; + reg [FILTER_LEN-1:0] scl_i_filter_reg; + reg [FILTER_LEN-1:0] sda_i_filter_reg; -reg scl_i_reg; -reg sda_i_reg; + reg scl_i_reg; + reg sda_i_reg; -reg sda_o_reg; + reg sda_o_reg; -reg last_scl_i_reg; -reg last_sda_i_reg; + reg last_scl_i_reg; + reg last_sda_i_reg; -assign scl_o = 1'b1; -assign scl_t = 1'b1; -assign sda_o = sda_o_reg; -assign sda_t = sda_o_reg; + assign scl_o = 1'b1; + assign scl_t = 1'b1; + assign sda_o = sda_o_reg; + assign sda_t = sda_o_reg; -assign data_out = data_reg; + assign data_out = data_reg; -wire scl_posedge = scl_i_reg && !last_scl_i_reg; -wire scl_negedge = !scl_i_reg && last_scl_i_reg; -wire sda_posedge = sda_i_reg && !last_sda_i_reg; -wire sda_negedge = !sda_i_reg && last_sda_i_reg; + wire scl_posedge = scl_i_reg && !last_scl_i_reg; + wire scl_negedge = !scl_i_reg && last_scl_i_reg; + wire sda_posedge = sda_i_reg && !last_sda_i_reg; + wire sda_negedge = !sda_i_reg && last_sda_i_reg; -wire start_bit = sda_negedge && scl_i_reg; -wire stop_bit = sda_posedge && scl_i_reg; + wire start_bit = sda_negedge && scl_i_reg; + wire stop_bit = sda_posedge && scl_i_reg; -always @(posedge clk) begin + always @(posedge clk or negedge rst) begin + if (rst) begin + state_reg <= STATE_IDLE; + sda_o_reg <= 1'b1; + end else begin - if (start_bit) begin + if (start_bit) begin sda_o_reg <= 1'b1; bit_count_reg <= 4'd7; state_reg <= STATE_ADDRESS; - end else if (stop_bit) begin + end else if (stop_bit) begin sda_o_reg <= 1'b1; state_reg <= STATE_IDLE; - end else begin + end else begin case (state_reg) - STATE_IDLE: begin - // line idle - sda_o_reg <= 1'b1; - - state_reg <= STATE_IDLE; - end - STATE_ADDRESS: begin - // read address - sda_o_reg <= 1'b1; - - if (scl_posedge) begin - if (bit_count_reg > 0) begin - // shift in address - bit_count_reg <= bit_count_reg-1; - shift_reg <= {shift_reg[6:0], sda_i_reg}; - state_reg <= STATE_ADDRESS; - end else begin - // check address - mode_read_reg <= sda_i_reg; - if (shift_reg[6:0] == DEV_ADDR) begin - // it's a match, send ACK - state_reg <= STATE_ACK; - end else begin - // no match, return to idle - state_reg <= STATE_IDLE; - end - end + STATE_IDLE: begin + // line idle + sda_o_reg <= 1'b1; + + state_reg <= STATE_IDLE; + end + STATE_ADDRESS: begin + // read address + sda_o_reg <= 1'b1; + + if (scl_posedge) begin + if (bit_count_reg > 0) begin + // shift in address + bit_count_reg <= bit_count_reg - 1; + shift_reg <= {shift_reg[6:0], sda_i_reg}; + state_reg <= STATE_ADDRESS; + end else begin + // check address + mode_read_reg <= sda_i_reg; + if (shift_reg[6:0] == DEV_ADDR) begin + // it's a match, send ACK + state_reg <= STATE_ACK; end else begin - state_reg <= STATE_ADDRESS; + // no match, return to idle + state_reg <= STATE_IDLE; end + end + end else begin + state_reg <= STATE_ADDRESS; end - STATE_ACK: begin - // send ACK bit - if (scl_negedge) begin - sda_o_reg <= 1'b0; - bit_count_reg <= 4'd7; - if (mode_read_reg) begin - // reading - shift_reg <= data_reg; - state_reg <= STATE_READ_1; - end else begin - // writing - state_reg <= STATE_WRITE_1; - end - end else begin - state_reg <= STATE_ACK; - end + end + STATE_ACK: begin + // send ACK bit + if (scl_negedge) begin + sda_o_reg <= 1'b0; + bit_count_reg <= 4'd7; + if (mode_read_reg) begin + // reading + shift_reg <= data_reg; + state_reg <= STATE_READ_1; + end else begin + // writing + state_reg <= STATE_WRITE_1; + end + end else begin + state_reg <= STATE_ACK; end - STATE_WRITE_1: begin - // write data byte - if (scl_negedge) begin - sda_o_reg <= 1'b1; - state_reg <= STATE_WRITE_2; - end else begin - state_reg <= STATE_WRITE_1; - end + end + STATE_WRITE_1: begin + // write data byte + if (scl_negedge) begin + sda_o_reg <= 1'b1; + state_reg <= STATE_WRITE_2; + end else begin + state_reg <= STATE_WRITE_1; end - STATE_WRITE_2: begin - // write data byte - sda_o_reg <= 1'b1; - if (scl_posedge) begin - // shift in data bit - shift_reg <= {shift_reg[6:0], sda_i_reg}; - if (bit_count_reg > 0) begin - bit_count_reg <= bit_count_reg-1; - state_reg <= STATE_WRITE_2; - end else begin - data_reg <= {shift_reg[6:0], sda_i_reg}; - state_reg <= STATE_ACK; - end - end else begin - state_reg <= STATE_WRITE_2; - end + end + STATE_WRITE_2: begin + // write data byte + sda_o_reg <= 1'b1; + if (scl_posedge) begin + // shift in data bit + shift_reg <= {shift_reg[6:0], sda_i_reg}; + if (bit_count_reg > 0) begin + bit_count_reg <= bit_count_reg - 1; + state_reg <= STATE_WRITE_2; + end else begin + data_reg <= {shift_reg[6:0], sda_i_reg}; + state_reg <= STATE_ACK; + end + end else begin + state_reg <= STATE_WRITE_2; end - STATE_READ_1: begin - // read data byte - if (scl_negedge) begin - // shift out data bit - {sda_o_reg, shift_reg} <= {shift_reg, sda_i_reg}; - - if (bit_count_reg > 0) begin - bit_count_reg <= bit_count_reg-1; - state_reg <= STATE_READ_1; - end else begin - state_reg <= STATE_READ_2; - end - end else begin - state_reg <= STATE_READ_1; - end + end + STATE_READ_1: begin + // read data byte + if (scl_negedge) begin + // shift out data bit + {sda_o_reg, shift_reg} <= {shift_reg, sda_i_reg}; + + if (bit_count_reg > 0) begin + bit_count_reg <= bit_count_reg - 1; + state_reg <= STATE_READ_1; + end else begin + state_reg <= STATE_READ_2; + end + end else begin + state_reg <= STATE_READ_1; end - STATE_READ_2: begin - // read ACK bit - if (scl_negedge) begin - // release SDA - sda_o_reg <= 1'b1; - state_reg <= STATE_READ_3; - end else begin - state_reg <= STATE_READ_2; - end + end + STATE_READ_2: begin + // read ACK bit + if (scl_negedge) begin + // release SDA + sda_o_reg <= 1'b1; + state_reg <= STATE_READ_3; + end else begin + state_reg <= STATE_READ_2; end - STATE_READ_3: begin - // read ACK bit - if (scl_posedge) begin - if (sda_i_reg) begin - // NACK, return to idle - state_reg <= STATE_IDLE; - end else begin - // ACK, read another byte - bit_count_reg <= 4'd7; - shift_reg <= data_reg; - state_reg <= STATE_READ_1; - end - end else begin - state_reg <= STATE_READ_3; - end + end + STATE_READ_3: begin + // read ACK bit + if (scl_posedge) begin + if (sda_i_reg) begin + // NACK, return to idle + state_reg <= STATE_IDLE; + end else begin + // ACK, read another byte + bit_count_reg <= 4'd7; + shift_reg <= data_reg; + state_reg <= STATE_READ_1; + end + end else begin + state_reg <= STATE_READ_3; end - default: $display("This should never happen"); + end + default: $display("default output of i2c_single_reg triggered atm this does nothing"); endcase - end + end - if (data_latch) begin + if (data_latch) begin data_reg <= data_in; - end - scl_i_filter_reg <= (scl_i_filter_reg << 1) | {3'b000, scl_i}; - sda_i_filter_reg <= (sda_i_filter_reg << 1) | {3'b000, sda_i}; + end + scl_i_filter_reg <= (scl_i_filter_reg << 1) | {3'b000, scl_i}; + sda_i_filter_reg <= (sda_i_filter_reg << 1) | {3'b000, sda_i}; - if (scl_i_filter_reg == {FILTER_LEN{1'b1}}) begin + if (scl_i_filter_reg == {FILTER_LEN{1'b1}}) begin scl_i_reg <= 1'b1; - end else if (scl_i_filter_reg == {FILTER_LEN{1'b0}}) begin + end else if (scl_i_filter_reg == {FILTER_LEN{1'b0}}) begin scl_i_reg <= 1'b0; - end + end - if (sda_i_filter_reg == {FILTER_LEN{1'b1}}) begin + if (sda_i_filter_reg == {FILTER_LEN{1'b1}}) begin sda_i_reg <= 1'b1; - end else if (sda_i_filter_reg == {FILTER_LEN{1'b0}}) begin + end else if (sda_i_filter_reg == {FILTER_LEN{1'b0}}) begin sda_i_reg <= 1'b0; - end + end - last_scl_i_reg <= scl_i_reg; - last_sda_i_reg <= sda_i_reg; + last_scl_i_reg <= scl_i_reg; + last_sda_i_reg <= sda_i_reg; - if (rst) begin - state_reg <= STATE_IDLE; - sda_o_reg <= 1'b1; end -end - + end endmodule `resetall diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index 11b6a39..2cf26ef 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -31,52 +31,51 @@ THE SOFTWARE. */ module i2c_slave #( parameter FILTER_LEN = 4 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * Host interface */ - input wire release_bus, + input wire release_bus, - input wire [7:0] s_axis_data_tdata, - input wire s_axis_data_tvalid, - output wire s_axis_data_tready, - input wire s_axis_data_tlast, + input wire [7:0] s_axis_data_tdata, + input wire s_axis_data_tvalid, + output wire s_axis_data_tready, + input wire s_axis_data_tlast, - output wire [7:0] m_axis_data_tdata, - output wire m_axis_data_tvalid, - input wire m_axis_data_tready, - output wire m_axis_data_tlast, + output wire [7:0] m_axis_data_tdata, + output wire m_axis_data_tvalid, + input wire m_axis_data_tready, + output wire m_axis_data_tlast, /* * I2C interface */ - input wire scl_i, - output wire scl_o, - output wire scl_t, - input wire sda_i, - output wire sda_o, - output wire sda_t, + input wire scl_i, + output wire scl_o, + output wire scl_t, + input wire sda_i, + output wire sda_o, + output wire sda_t, /* * Status */ - output wire busy, - output wire [6:0] bus_address, - output wire bus_addressed, - output wire bus_active, + output wire busy, + output wire [6:0] bus_address, + output wire bus_addressed, + output wire bus_active, /* * Configuration */ - input wire enable, - input wire [6:0] device_address, - input wire [6:0] device_address_mask + input wire enable, + input wire [6:0] device_address, + input wire [6:0] device_address_mask ); -/* + /* I2C @@ -168,7 +167,7 @@ I/O pin. This would prevent devices from stretching the clock period. */ -localparam [4:0] + localparam [4:0] STATE_IDLE = 4'd0, STATE_ADDRESS = 4'd1, STATE_ACK = 4'd2, @@ -178,66 +177,66 @@ localparam [4:0] STATE_READ_2 = 4'd6, STATE_READ_3 = 4'd7; -reg [4:0] state_reg = STATE_IDLE, state_next; + reg [4:0] state_reg = STATE_IDLE, state_next; -reg [6:0] addr_reg = 7'd0, addr_next; -reg [7:0] data_reg = 8'd0, data_next; -reg data_valid_reg = 1'b0, data_valid_next; -reg data_out_reg_valid_reg = 1'b0, data_out_reg_valid_next; -reg last_reg = 1'b0, last_next; + reg [6:0] addr_reg = 7'd0, addr_next; + reg [7:0] data_reg = 8'd0, data_next; + reg data_valid_reg = 1'b0, data_valid_next; + reg data_out_reg_valid_reg = 1'b0, data_out_reg_valid_next; + reg last_reg = 1'b0, last_next; -reg mode_read_reg = 1'b0, mode_read_next; + reg mode_read_reg = 1'b0, mode_read_next; -reg [3:0] bit_count_reg = 4'd0, bit_count_next; + reg [3:0] bit_count_reg = 4'd0, bit_count_next; -reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; + reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; -reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; -reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; -reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; + reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; + reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; + reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; -reg [FILTER_LEN-1:0] scl_i_filter = {FILTER_LEN{1'b1}}; -reg [FILTER_LEN-1:0] sda_i_filter = {FILTER_LEN{1'b1}}; + reg [FILTER_LEN-1:0] scl_i_filter = {FILTER_LEN{1'b1}}; + reg [FILTER_LEN-1:0] sda_i_filter = {FILTER_LEN{1'b1}}; -reg scl_i_reg = 1'b1; -reg sda_i_reg = 1'b1; + reg scl_i_reg = 1'b1; + reg sda_i_reg = 1'b1; -reg scl_o_reg = 1'b1, scl_o_next; -reg sda_o_reg = 1'b1, sda_o_next; + reg scl_o_reg = 1'b1, scl_o_next; + reg sda_o_reg = 1'b1, sda_o_next; -reg last_scl_i_reg = 1'b1; -reg last_sda_i_reg = 1'b1; + reg last_scl_i_reg = 1'b1; + reg last_sda_i_reg = 1'b1; -reg busy_reg = 1'b0; -reg bus_active_reg = 1'b0; -reg bus_addressed_reg = 1'b0, bus_addressed_next; + reg busy_reg = 1'b0; + reg bus_active_reg = 1'b0; + reg bus_addressed_reg = 1'b0, bus_addressed_next; -assign bus_address = addr_reg; + assign bus_address = addr_reg; -assign s_axis_data_tready = s_axis_data_tready_reg; + assign s_axis_data_tready = s_axis_data_tready_reg; -assign m_axis_data_tdata = m_axis_data_tdata_reg; -assign m_axis_data_tvalid = m_axis_data_tvalid_reg; -assign m_axis_data_tlast = m_axis_data_tlast_reg; + assign m_axis_data_tdata = m_axis_data_tdata_reg; + assign m_axis_data_tvalid = m_axis_data_tvalid_reg; + assign m_axis_data_tlast = m_axis_data_tlast_reg; -assign scl_o = scl_o_reg; -assign scl_t = scl_o_reg; -assign sda_o = sda_o_reg; -assign sda_t = sda_o_reg; + assign scl_o = scl_o_reg; + assign scl_t = scl_o_reg; + assign sda_o = sda_o_reg; + assign sda_t = sda_o_reg; -assign busy = busy_reg; -assign bus_active = bus_active_reg; -assign bus_addressed = bus_addressed_reg; + assign busy = busy_reg; + assign bus_active = bus_active_reg; + assign bus_addressed = bus_addressed_reg; -assign scl_posedge = scl_i_reg && !last_scl_i_reg; -assign scl_negedge = !scl_i_reg && last_scl_i_reg; -assign sda_posedge = sda_i_reg && !last_sda_i_reg; -assign sda_negedge = !sda_i_reg && last_sda_i_reg; + assign scl_posedge = scl_i_reg && !last_scl_i_reg; + assign scl_negedge = !scl_i_reg && last_scl_i_reg; + assign sda_posedge = sda_i_reg && !last_sda_i_reg; + assign sda_negedge = !sda_i_reg && last_sda_i_reg; -assign start_bit = sda_negedge && scl_i_reg; -assign stop_bit = sda_posedge && scl_i_reg; + assign start_bit = sda_negedge && scl_i_reg; + assign stop_bit = sda_posedge && scl_i_reg; -always @* begin + always @* begin state_next = STATE_IDLE; addr_next = addr_reg; @@ -262,181 +261,181 @@ always @* begin bus_addressed_next = bus_addressed_reg; if (start_bit) begin - // got start bit, latch out data, read address - data_valid_next = 1'b0; - data_out_reg_valid_next = 1'b0; - bit_count_next = 4'd7; - m_axis_data_tlast_next = 1'b1; - m_axis_data_tvalid_next = data_out_reg_valid_reg; - bus_addressed_next = 1'b0; - state_next = STATE_ADDRESS; + // got start bit, latch out data, read address + data_valid_next = 1'b0; + data_out_reg_valid_next = 1'b0; + bit_count_next = 4'd7; + m_axis_data_tlast_next = 1'b1; + m_axis_data_tvalid_next = data_out_reg_valid_reg; + bus_addressed_next = 1'b0; + state_next = STATE_ADDRESS; end else if (release_bus || stop_bit) begin - // got stop bit or release bus command, latch out data, return to idle - data_valid_next = 1'b0; - data_out_reg_valid_next = 1'b0; - m_axis_data_tlast_next = 1'b1; - m_axis_data_tvalid_next = data_out_reg_valid_reg; - bus_addressed_next = 1'b0; - state_next = STATE_IDLE; + // got stop bit or release bus command, latch out data, return to idle + data_valid_next = 1'b0; + data_out_reg_valid_next = 1'b0; + m_axis_data_tlast_next = 1'b1; + m_axis_data_tvalid_next = data_out_reg_valid_reg; + bus_addressed_next = 1'b0; + state_next = STATE_IDLE; end else begin - case (state_reg) - STATE_IDLE: begin - // line idle - data_valid_next = 1'b0; - data_out_reg_valid_next = 1'b0; - bus_addressed_next = 1'b0; + case (state_reg) + STATE_IDLE: begin + // line idle + data_valid_next = 1'b0; + data_out_reg_valid_next = 1'b0; + bus_addressed_next = 1'b0; + state_next = STATE_IDLE; + end + STATE_ADDRESS: begin + // read address + if (scl_posedge) begin + if (bit_count_reg > 0) begin + // shift in address + bit_count_next = bit_count_reg - 1; + data_next = {data_reg[6:0], sda_i_reg}; + state_next = STATE_ADDRESS; + end else begin + // check address + if (enable && (device_address & device_address_mask) == (data_reg[6:0] & device_address_mask)) begin + // it's a match, save read/write bit and send ACK + addr_next = data_reg[6:0]; + mode_read_next = sda_i_reg; + bus_addressed_next = 1'b1; + state_next = STATE_ACK; + end else begin + // no match, return to idle state_next = STATE_IDLE; + end end - STATE_ADDRESS: begin - // read address - if (scl_posedge) begin - if (bit_count_reg > 0) begin - // shift in address - bit_count_next = bit_count_reg-1; - data_next = {data_reg[6:0], sda_i_reg}; - state_next = STATE_ADDRESS; - end else begin - // check address - if (enable && (device_address & device_address_mask) == (data_reg[6:0] & device_address_mask)) begin - // it's a match, save read/write bit and send ACK - addr_next = data_reg[6:0]; - mode_read_next = sda_i_reg; - bus_addressed_next = 1'b1; - state_next = STATE_ACK; - end else begin - // no match, return to idle - state_next = STATE_IDLE; - end - end - end else begin - state_next = STATE_ADDRESS; - end - end - STATE_ACK: begin - // send ACK bit - if (scl_negedge) begin - sda_o_next = 1'b0; - bit_count_next = 4'd7; - if (mode_read_reg) begin - // reading - s_axis_data_tready_next = 1'b1; - data_valid_next = 1'b0; - state_next = STATE_READ_1; - end else begin - // writing - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_ACK; - end - end - STATE_WRITE_1: begin - // write data byte - if (scl_negedge || !scl_o_reg) begin - sda_o_next = 1'b1; - if (m_axis_data_tvalid && !m_axis_data_tready) begin - // data waiting in output register, so stretch clock - scl_o_next = 1'b0; - state_next = STATE_WRITE_1; - end else begin - scl_o_next = 1'b1; - if (data_valid_reg) begin - // store data in output register - m_axis_data_tdata_next = data_reg; - m_axis_data_tlast_next = 1'b0; - end - data_valid_next = 1'b0; - data_out_reg_valid_next = data_valid_reg; - state_next = STATE_WRITE_2; - end - end else begin - state_next = STATE_WRITE_1; - end + end else begin + state_next = STATE_ADDRESS; + end + end + STATE_ACK: begin + // send ACK bit + if (scl_negedge) begin + sda_o_next = 1'b0; + bit_count_next = 4'd7; + if (mode_read_reg) begin + // reading + s_axis_data_tready_next = 1'b1; + data_valid_next = 1'b0; + state_next = STATE_READ_1; + end else begin + // writing + state_next = STATE_WRITE_1; end - STATE_WRITE_2: begin - // write data byte - if (scl_posedge) begin - // shift in data bit - data_next = {data_reg[6:0], sda_i_reg}; - if (bit_count_reg > 0) begin - bit_count_next = bit_count_reg-1; - state_next = STATE_WRITE_2; - end else begin - // latch out previous data byte since we now know it's not the last one - m_axis_data_tvalid_next = data_out_reg_valid_reg; - data_out_reg_valid_next = 1'b0; - data_valid_next = 1'b1; - state_next = STATE_ACK; - end - end else begin - state_next = STATE_WRITE_2; - end + end else begin + state_next = STATE_ACK; + end + end + STATE_WRITE_1: begin + // write data byte + if (scl_negedge || !scl_o_reg) begin + sda_o_next = 1'b1; + if (m_axis_data_tvalid && !m_axis_data_tready) begin + // data waiting in output register, so stretch clock + scl_o_next = 1'b0; + state_next = STATE_WRITE_1; + end else begin + scl_o_next = 1'b1; + if (data_valid_reg) begin + // store data in output register + m_axis_data_tdata_next = data_reg; + m_axis_data_tlast_next = 1'b0; + end + data_valid_next = 1'b0; + data_out_reg_valid_next = data_valid_reg; + state_next = STATE_WRITE_2; end - STATE_READ_1: begin - // read data byte - if (s_axis_data_tready && s_axis_data_tvalid) begin - // data valid; latch it in - s_axis_data_tready_next = 1'b0; - data_next = s_axis_data_tdata; - data_valid_next = 1'b1; - end else begin - // keep ready high if we're waiting for data - s_axis_data_tready_next = !data_valid_reg; - end - - if (scl_negedge || !scl_o_reg) begin - // shift out data bit - if (!data_valid_reg) begin - // waiting for data, so stretch clock - scl_o_next = 1'b0; - state_next = STATE_READ_1; - end else begin - scl_o_next = 1'b1; - {sda_o_next, data_next} = {data_reg, 1'b0}; - - if (bit_count_reg > 0) begin - bit_count_next = bit_count_reg-1; - state_next = STATE_READ_1; - end else begin - state_next = STATE_READ_2; - end - end - end else begin - state_next = STATE_READ_1; - end + end else begin + state_next = STATE_WRITE_1; + end + end + STATE_WRITE_2: begin + // write data byte + if (scl_posedge) begin + // shift in data bit + data_next = {data_reg[6:0], sda_i_reg}; + if (bit_count_reg > 0) begin + bit_count_next = bit_count_reg - 1; + state_next = STATE_WRITE_2; + end else begin + // latch out previous data byte since we now know it's not the last one + m_axis_data_tvalid_next = data_out_reg_valid_reg; + data_out_reg_valid_next = 1'b0; + data_valid_next = 1'b1; + state_next = STATE_ACK; end - STATE_READ_2: begin - // read ACK bit - if (scl_negedge) begin - // release SDA - sda_o_next = 1'b1; - state_next = STATE_READ_3; - end else begin - state_next = STATE_READ_2; - end + end else begin + state_next = STATE_WRITE_2; + end + end + STATE_READ_1: begin + // read data byte + if (s_axis_data_tready && s_axis_data_tvalid) begin + // data valid; latch it in + s_axis_data_tready_next = 1'b0; + data_next = s_axis_data_tdata; + data_valid_next = 1'b1; + end else begin + // keep ready high if we're waiting for data + s_axis_data_tready_next = !data_valid_reg; + end + + if (scl_negedge || !scl_o_reg) begin + // shift out data bit + if (!data_valid_reg) begin + // waiting for data, so stretch clock + scl_o_next = 1'b0; + state_next = STATE_READ_1; + end else begin + scl_o_next = 1'b1; + {sda_o_next, data_next} = {data_reg, 1'b0}; + + if (bit_count_reg > 0) begin + bit_count_next = bit_count_reg - 1; + state_next = STATE_READ_1; + end else begin + state_next = STATE_READ_2; + end end - STATE_READ_3: begin - // read ACK bit - if (scl_posedge) begin - if (sda_i_reg) begin - // NACK, return to idle - state_next = STATE_IDLE; - end else begin - // ACK, read another byte - bit_count_next = 4'd7; - s_axis_data_tready_next = 1'b1; - data_valid_next = 1'b0; - state_next = STATE_READ_1; - end - end else begin - state_next = STATE_READ_3; - end + end else begin + state_next = STATE_READ_1; + end + end + STATE_READ_2: begin + // read ACK bit + if (scl_negedge) begin + // release SDA + sda_o_next = 1'b1; + state_next = STATE_READ_3; + end else begin + state_next = STATE_READ_2; + end + end + STATE_READ_3: begin + // read ACK bit + if (scl_posedge) begin + if (sda_i_reg) begin + // NACK, return to idle + state_next = STATE_IDLE; + end else begin + // ACK, read another byte + bit_count_next = 4'd7; + s_axis_data_tready_next = 1'b1; + data_valid_next = 1'b0; + state_next = STATE_READ_1; end - endcase + end else begin + state_next = STATE_READ_3; + end + end + endcase end -end + end -always @(posedge clk) begin + always @(posedge clk) begin state_reg <= state_next; addr_reg <= addr_next; @@ -459,15 +458,15 @@ always @(posedge clk) begin sda_i_filter <= (sda_i_filter << 1) | sda_i; if (scl_i_filter == {FILTER_LEN{1'b1}}) begin - scl_i_reg <= 1'b1; + scl_i_reg <= 1'b1; end else if (scl_i_filter == {FILTER_LEN{1'b0}}) begin - scl_i_reg <= 1'b0; + scl_i_reg <= 1'b0; end if (sda_i_filter == {FILTER_LEN{1'b1}}) begin - sda_i_reg <= 1'b1; + sda_i_reg <= 1'b1; end else if (sda_i_filter == {FILTER_LEN{1'b0}}) begin - sda_i_reg <= 1'b0; + sda_i_reg <= 1'b0; end scl_o_reg <= scl_o_next; @@ -479,25 +478,25 @@ always @(posedge clk) begin busy_reg <= !(state_reg == STATE_IDLE); if (start_bit) begin - bus_active_reg <= 1'b1; + bus_active_reg <= 1'b1; end else if (stop_bit) begin - bus_active_reg <= 1'b0; + bus_active_reg <= 1'b0; end else begin - bus_active_reg <= bus_active_reg; + bus_active_reg <= bus_active_reg; end bus_addressed_reg <= bus_addressed_next; if (rst) begin - state_reg <= STATE_IDLE; - s_axis_data_tready_reg <= 1'b0; - m_axis_data_tvalid_reg <= 1'b0; - scl_o_reg <= 1'b1; - sda_o_reg <= 1'b1; - busy_reg <= 1'b0; - bus_active_reg <= 1'b0; - bus_addressed_reg <= 1'b0; + state_reg <= STATE_IDLE; + s_axis_data_tready_reg <= 1'b0; + m_axis_data_tvalid_reg <= 1'b0; + scl_o_reg <= 1'b1; + sda_o_reg <= 1'b1; + busy_reg <= 1'b0; + bus_active_reg <= 1'b0; + bus_addressed_reg <= 1'b0; end -end + end endmodule From bafe0a735754874c81cb6bff07fca74cd39e4f5d Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 11:22:47 +0200 Subject: [PATCH 15/47] making everything a task --- rtl/i2c_master_tb.v | 179 ++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 91 deletions(-) diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index 806dd81..47ed1f8 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -222,105 +222,102 @@ module i2c_master_tb; end endtask - - initial begin - $display("Starting I2C Master test"); - initialize_testbench; - $display("Testing NACK handling."); - - // Set address to 00000001, command to write - i2c_start(7'b0000001, 0); - s_axis_data_tdata = 8'b10100101; - s_axis_data_tvalid = 1; - - // Wait for NACK - @(posedge missed_ack); - $display("NACK expected!"); - - wait_for_ready(); - - $display("Testing Writing."); - // Second write attempt - i2c_start(7'b0000001, 0); - s_axis_data_tdata = 8'b10101111; - s_axis_data_tvalid = 1; - - // Hardcoding the acknowledgement - repeat (7) @(negedge scl_o); - - // Send ACK - send_ack(); - @(negedge scl_o); // let 1 pass through - send_byte(8'b01111111); - stop_on_idle = 1; - - wait_for_ready(); - #1000; - - // Start is implied - s_axis_data_tdata = 8'b10101111; - s_axis_data_tvalid = 1; - i2c_start(7'b0000001, 1); - - $display("Testing reading."); - - // Hardcoding the acknowledgement - repeat (7) @(negedge scl_o); - - // Send ACK - s_axis_cmd_valid = 0; - send_ack(); - send_byte(8'b01111111); - - // Continue with next read (does not require i2c_start condition) - s_axis_cmd_read = 1; - s_axis_cmd_valid = 1; - m_axis_data_tready = 1; // prepare readiness - - @(negedge scl_o); - if (sda_wire) begin - $fatal(1, "Got NACK from master"); + // Task to test NACK handling +task test_nack_handling; + begin + $display("Testing NACK handling."); + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10100101; + s_axis_data_tvalid = 1; + @(posedge missed_ack); + $display("NACK expected!"); + wait_for_ready(); end +endtask - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - if (m_axis_data_tdata != 8'b01111111) begin - $fatal(1, "We didn't get what we sent"); +// Task to test writing +task test_writing; + begin + $display("Testing Writing."); + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + repeat(7) @(negedge scl_o); + send_ack(); + @(negedge scl_o); + //send_byte(8'b01111111); + stop_on_idle = 1; + wait_for_ready(); + #1000; end - #(CLK_PERIOD); - stop_on_idle = 1; +endtask - send_byte(8'd69); - @(posedge m_axis_data_tvalid); - if (m_axis_data_tdata != 8'd69) begin - $fatal(1, "We didn't get what we sent"); +// Task to test reading +task test_reading; + begin + $display("Testing reading."); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + i2c_start(7'b0000001, 1); + repeat(7) @(negedge scl_o); + s_axis_cmd_valid = 0; + send_ack(); + send_byte(8'b01111111); + s_axis_cmd_read = 1; + s_axis_cmd_valid = 1; + m_axis_data_tready = 1; + @(negedge scl_o); + if (sda_wire) $fatal(1, "Got NACK from master"); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'b01111111) $fatal(1, "We didn't get what we sent"); + #(CLK_PERIOD); + stop_on_idle = 1; + send_byte(8'd69); + @(posedge m_axis_data_tvalid); + if (m_axis_data_tdata != 8'd69) $fatal(1, "We didn't get what we sent"); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + s_axis_cmd_valid = 0; + wait_for_ready(); + wait_for_ready(); end - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - s_axis_cmd_valid = 0; // now stop - - wait_for_ready(); - wait_for_ready(); - $display("Testing i2c_single_reg writing"); - i2c_start(7'h70, 0); - s_axis_data_tdata = 8'd55; - s_axis_data_tvalid = 1; - - wait_for_ready(); - if (data_out_3 != 8'd55) begin - $fatal(1, "We didn't get what we sent"); +endtask + +// Task to test i2c_single_reg writing +task test_i2c_single_reg_writing; + begin + $display("Testing i2c_single_reg writing"); + i2c_start(7'h70, 0); + s_axis_data_tdata = 8'd55; + s_axis_data_tvalid = 1; + wait_for_ready(); + if (data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); + $display("Received data %d", data_out_3); end - $display("Received data %d", data_out_3); - data_latch_3 = 1; - data_in_3 = 8'd123; - $display("Testing i2c_single_reg reading"); - #(CLK_PERIOD); - data_latch_3 = 0; - i2c_start(7'h70, 1); - @(posedge m_axis_data_tvalid); - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - if (m_axis_data_tdata != 8'd123) begin - $fatal(1, "We didn't get what we sent"); +endtask + +// Task to test i2c_single_reg reading +task test_i2c_single_reg_reading; + begin + $display("Testing i2c_single_reg reading"); + data_latch_3 = 1; + data_in_3 = 8'd123; + #(CLK_PERIOD); + data_latch_3 = 0; + i2c_start(7'h70, 1); + @(posedge m_axis_data_tvalid); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'd123) $fatal(1, "We didn't get what we sent"); end +endtask + initial begin + $display("Starting I2C Master test"); + initialize_testbench; + test_nack_handling(); + test_writing(); + test_reading(); + test_i2c_single_reg_writing(); + test_i2c_single_reg_reading(); #1000; $finish; end From def7b23a2f2f390abbcd33be63bcb6c8c6477a34 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 11:24:12 +0200 Subject: [PATCH 16/47] making everything a task --- rtl/i2c_master_tb.v | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index 47ed1f8..acadfa7 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -246,10 +246,7 @@ task test_writing; send_ack(); @(negedge scl_o); //send_byte(8'b01111111); - stop_on_idle = 1; - wait_for_ready(); - #1000; - end + end endtask // Task to test reading @@ -278,7 +275,6 @@ task test_reading; $display("Received m_axis_data_tdata %d", m_axis_data_tdata); s_axis_cmd_valid = 0; wait_for_ready(); - wait_for_ready(); end endtask @@ -314,8 +310,13 @@ endtask $display("Starting I2C Master test"); initialize_testbench; test_nack_handling(); + stop_on_idle = 1; test_writing(); + wait_for_ready(); + #1000; + test_reading(); + wait_for_ready(); test_i2c_single_reg_writing(); test_i2c_single_reg_reading(); #1000; From e55ce7f29eb20c18df88f21ebf4c980c85f0446b Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 11:41:26 +0200 Subject: [PATCH 17/47] Updated state parameters and added padding bits to the input filters. --- rtl/i2c_slave.v | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index 2cf26ef..e4c69c0 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -168,14 +168,14 @@ I/O pin. This would prevent devices from stretching the clock period. */ localparam [4:0] - STATE_IDLE = 4'd0, - STATE_ADDRESS = 4'd1, - STATE_ACK = 4'd2, - STATE_WRITE_1 = 4'd3, - STATE_WRITE_2 = 4'd4, - STATE_READ_1 = 4'd5, - STATE_READ_2 = 4'd6, - STATE_READ_3 = 4'd7; + STATE_IDLE = 5'd0, + STATE_ADDRESS = 5'd1, + STATE_ACK = 5'd2, + STATE_WRITE_1 = 5'd3, + STATE_WRITE_2 = 5'd4, + STATE_READ_1 = 5'd5, + STATE_READ_2 = 5'd6, + STATE_READ_3 = 5'd7; reg [4:0] state_reg = STATE_IDLE, state_next; @@ -431,6 +431,7 @@ I/O pin. This would prevent devices from stretching the clock period. state_next = STATE_READ_3; end end + default:$display("default of slave triggered, do nothing"); endcase end end @@ -454,8 +455,8 @@ I/O pin. This would prevent devices from stretching the clock period. m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; m_axis_data_tlast_reg <= m_axis_data_tlast_next; - scl_i_filter <= (scl_i_filter << 1) | scl_i; - sda_i_filter <= (sda_i_filter << 1) | sda_i; + scl_i_filter <= (scl_i_filter << 1) | {3'b000, scl_i}; + sda_i_filter <= (sda_i_filter << 1) | {3'b000, sda_i}; if (scl_i_filter == {FILTER_LEN{1'b1}}) begin scl_i_reg <= 1'b1; From 42ee37af7d2d9a8c127ea7cb40c58cade952c56d Mon Sep 17 00:00:00 2001 From: "Kreijstal (aider)" Date: Sun, 30 Jun 2024 11:41:27 +0200 Subject: [PATCH 18/47] Added signal declarations and updated signal assignments for I2C slave module. --- rtl/i2c_slave.v | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index e4c69c0..8462a87 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -211,6 +211,14 @@ I/O pin. This would prevent devices from stretching the clock period. reg bus_active_reg = 1'b0; reg bus_addressed_reg = 1'b0, bus_addressed_next; + // Signal declarations + reg scl_posedge; + reg scl_negedge; + reg sda_posedge; + reg sda_negedge; + reg start_bit; + reg stop_bit; + assign bus_address = addr_reg; assign s_axis_data_tready = s_axis_data_tready_reg; @@ -228,13 +236,15 @@ I/O pin. This would prevent devices from stretching the clock period. assign bus_active = bus_active_reg; assign bus_addressed = bus_addressed_reg; - assign scl_posedge = scl_i_reg && !last_scl_i_reg; - assign scl_negedge = !scl_i_reg && last_scl_i_reg; - assign sda_posedge = sda_i_reg && !last_sda_i_reg; - assign sda_negedge = !sda_i_reg && last_sda_i_reg; + always @* begin + scl_posedge = scl_i_reg && !last_scl_i_reg; + scl_negedge = !scl_i_reg && last_scl_i_reg; + sda_posedge = sda_i_reg && !last_sda_i_reg; + sda_negedge = !sda_i_reg && last_sda_i_reg; - assign start_bit = sda_negedge && scl_i_reg; - assign stop_bit = sda_posedge && scl_i_reg; + start_bit = sda_negedge && scl_i_reg; + stop_bit = sda_posedge && scl_i_reg; + end always @* begin state_next = STATE_IDLE; From 657fbdc61dc86cd9c5db6b5ba2e22abbb812715e Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 11:42:38 +0200 Subject: [PATCH 19/47] generated blocks work --- rtl/i2c_master_tb.v | 152 +++++++++++++++++++++++++++++++------------- 1 file changed, 108 insertions(+), 44 deletions(-) diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index acadfa7..072cb15 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -10,11 +10,14 @@ module i2c_master_tb; // Parameters parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) - // Inputs - reg clk = 0; + parameter ENABLE_DEVICE_3 = 1; // Set to 0 to disable device 3 + parameter ENABLE_DEVICE_4 = 1; // Set to 0 to disable device 4 + + reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; + // I2C master signals reg [6:0] s_axis_cmd_address = 0; reg s_axis_cmd_start = 0; reg s_axis_cmd_read = 0; @@ -31,7 +34,6 @@ module i2c_master_tb; reg [15:0] prescale = 0; reg stop_on_idle = 0; - // Outputs wire s_axis_cmd_ready; wire s_axis_data_tready; wire [7:0] m_axis_data_tdata; @@ -46,29 +48,111 @@ module i2c_master_tb; wire bus_active; wire missed_ack; - // Additional wires for modeling pull-up resistors and open-drain outputs + // Wires for modeling pull-up resistors and open-drain outputs wire scl_wire; wire sda_wire; - // Existing dummy registers + // Dummy registers reg sda2 = 1; reg scl2 = 1; - // New device (register) signals - wire sda_o_3; - //reg sda_o_3=1; - wire sda_t_3; - wire scl_o_3; - //reg scl_o_3=1; - wire scl_t_3; + // Generate block for Device 3 + generate + if (ENABLE_DEVICE_3) begin : device_3 + wire sda_o_3; + wire sda_t_3; + wire scl_o_3; + wire scl_t_3; + reg [7:0] data_in_3; + reg data_latch_3; + wire [7:0] data_out_3; + + i2c_single_reg #( + .FILTER_LEN(4), + .DEV_ADDR (7'h70) + ) i2c_reg ( + .clk(clk), + .rst(rst), + .scl_i(scl_wire), + .scl_o(scl_o_3), + .scl_t(scl_t_3), + .sda_i(sda_wire), + .sda_o(sda_o_3), + .sda_t(sda_t_3), + .data_in(data_in_3), + .data_latch(data_latch_3), + .data_out(data_out_3) + ); + end + endgenerate + + // Generate block for Device 4 + generate + if (ENABLE_DEVICE_4) begin : device_4 + wire sda_o_4; + wire sda_t_4; + wire scl_o_4; + wire scl_t_4; + wire [7:0] m_axis_data_tdata_4; + wire m_axis_data_tvalid_4; + wire m_axis_data_tready_4; + wire m_axis_data_tlast_4; + wire [7:0] s_axis_data_tdata_4; + wire s_axis_data_tvalid_4; + wire s_axis_data_tready_4; + wire s_axis_data_tlast_4; + wire busy_4; + wire [6:0] bus_address_4; + wire bus_addressed_4; + wire bus_active_4; + reg release_bus_4; + reg enable_4; + reg [6:0] device_address_4; + reg [6:0] device_address_mask_4; + + i2c_slave #( + .FILTER_LEN(4) + ) i2c_slave_inst ( + .clk(clk), + .rst(rst), + .release_bus(release_bus_4), + .s_axis_data_tdata(s_axis_data_tdata_4), + .s_axis_data_tvalid(s_axis_data_tvalid_4), + .s_axis_data_tready(s_axis_data_tready_4), + .s_axis_data_tlast(s_axis_data_tlast_4), + .m_axis_data_tdata(m_axis_data_tdata_4), + .m_axis_data_tvalid(m_axis_data_tvalid_4), + .m_axis_data_tready(m_axis_data_tready_4), + .m_axis_data_tlast(m_axis_data_tlast_4), + .scl_i(scl_wire), + .scl_o(scl_o_4), + .scl_t(scl_t_4), + .sda_i(sda_wire), + .sda_o(sda_o_4), + .sda_t(sda_t_4), + .busy(busy_4), + .bus_address(bus_address_4), + .bus_addressed(bus_addressed_4), + .bus_active(bus_active_4), + .enable(enable_4), + .device_address(device_address_4), + .device_address_mask(device_address_mask_4) + ); + end + endgenerate // Model pull-up resistors with weak pull-ups pullup (scl_wire); pullup (sda_wire); - // Model open-drain outputs, including the new device - assign scl_wire = (scl_o & scl2 & scl_o_3) ? 1'bz : 1'b0; - assign sda_wire = (sda_o & sda2 & sda_o_3) ? 1'bz : 1'b0; + // Model open-drain outputs, including conditional devices + assign scl_wire = (scl_o & scl2 & + (ENABLE_DEVICE_3 ? device_3.scl_o_3 : 1'b1) & + (ENABLE_DEVICE_4 ? device_4.scl_o_4 : 1'b1)) ? 1'bz : 1'b0; + assign sda_wire = (sda_o & sda2 & + (ENABLE_DEVICE_3 ? device_3.sda_o_3 : 1'b1) & + (ENABLE_DEVICE_4 ? device_4.sda_o_4 : 1'b1)) ? 1'bz : 1'b0; + always #(CLK_PERIOD / 2) clk <= ~clk; @@ -92,27 +176,7 @@ module i2c_master_tb; $dumpvars(0, i2c_master_tb); end - reg [7:0] data_in_3; - reg data_latch_3; - wire [7:0] data_out_3; - i2c_single_reg #( - .FILTER_LEN(4), - .DEV_ADDR (7'h70) - ) i2c_reg ( - .clk(clk), - .rst(rst), - - .scl_i(scl_wire), - .scl_o(scl_o_3), - .scl_t(scl_t_3), - .sda_i(sda_wire), - .sda_o(sda_o_3), - .sda_t(sda_t_3), - .data_in(data_in_3), - .data_latch(data_latch_3), - .data_out(data_out_3) - ); i2c_master UUT ( .clk(clk), .rst(rst), @@ -245,7 +309,8 @@ task test_writing; repeat(7) @(negedge scl_o); send_ack(); @(negedge scl_o); - //send_byte(8'b01111111); + //send_byte(8'b01111111); + wait_for_ready(); end endtask @@ -286,8 +351,8 @@ task test_i2c_single_reg_writing; s_axis_data_tdata = 8'd55; s_axis_data_tvalid = 1; wait_for_ready(); - if (data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); - $display("Received data %d", data_out_3); + if (device_3.data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); + $display("Received data %d", device_3.data_out_3); end endtask @@ -295,10 +360,10 @@ endtask task test_i2c_single_reg_reading; begin $display("Testing i2c_single_reg reading"); - data_latch_3 = 1; - data_in_3 = 8'd123; + device_3.data_latch_3 = 1; + device_3.data_in_3 = 8'd123; #(CLK_PERIOD); - data_latch_3 = 0; + device_3.data_latch_3 = 0; i2c_start(7'h70, 1); @(posedge m_axis_data_tvalid); $display("Received m_axis_data_tdata %d", m_axis_data_tdata); @@ -310,10 +375,9 @@ endtask $display("Starting I2C Master test"); initialize_testbench; test_nack_handling(); - stop_on_idle = 1; + stop_on_idle = 1; test_writing(); - wait_for_ready(); - #1000; + #1000;//stopping test_reading(); wait_for_ready(); From df1c3880e1c1202dbb44547492cd81dfd8d75815 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 11:48:08 +0200 Subject: [PATCH 20/47] verible format called everywhere --- rtl/i2c_init.v | 572 +++++++++++++------------- rtl/i2c_master_axil.v | 796 ++++++++++++++++++------------------ rtl/i2c_master_tb.v | 148 +++---- rtl/i2c_master_wbs_16.v | 780 ++++++++++++++++++----------------- rtl/i2c_master_wbs_8.v | 782 +++++++++++++++++------------------ rtl/i2c_phy_tb.sv | 43 +- rtl/i2c_single_reg.v | 4 +- rtl/i2c_slave.v | 2 +- rtl/i2c_slave_axil_master.v | 545 ++++++++++++------------ rtl/i2c_slave_wbm.v | 502 +++++++++++------------ 10 files changed, 2102 insertions(+), 2072 deletions(-) diff --git a/rtl/i2c_init.v b/rtl/i2c_init.v index ebef6c1..ba1b588 100644 --- a/rtl/i2c_init.v +++ b/rtl/i2c_init.v @@ -30,38 +30,38 @@ THE SOFTWARE. * I2C init */ module i2c_init ( - input wire clk, - input wire rst, + input wire clk, + input wire rst, /* * I2C master interface */ - output wire [6:0] m_axis_cmd_address, - output wire m_axis_cmd_start, - output wire m_axis_cmd_read, - output wire m_axis_cmd_write, - output wire m_axis_cmd_write_multiple, - output wire m_axis_cmd_stop, - output wire m_axis_cmd_valid, - input wire m_axis_cmd_ready, - - output wire [7:0] m_axis_data_tdata, - output wire m_axis_data_tvalid, - input wire m_axis_data_tready, - output wire m_axis_data_tlast, + output wire [6:0] m_axis_cmd_address, + output wire m_axis_cmd_start, + output wire m_axis_cmd_read, + output wire m_axis_cmd_write, + output wire m_axis_cmd_write_multiple, + output wire m_axis_cmd_stop, + output wire m_axis_cmd_valid, + input wire m_axis_cmd_ready, + + output wire [7:0] m_axis_data_tdata, + output wire m_axis_data_tvalid, + input wire m_axis_data_tready, + output wire m_axis_data_tlast, /* * Status */ - output wire busy, + output wire busy, /* * Configuration */ - input wire start + input wire start ); -/* + /* Generic module for I2C bus initialization. Good for use when multiple devices on an I2C bus must be initialized on system start without intervention of a @@ -134,87 +134,87 @@ write 0x11223344 to register 0x0004 on devices at 0x50, 0x51, 0x52, and 0x53 */ -// init_data ROM -localparam INIT_DATA_LEN = 22; + // init_data ROM + localparam INIT_DATA_LEN = 22; -reg [8:0] init_data [INIT_DATA_LEN-1:0]; + reg [8:0] init_data[INIT_DATA_LEN-1:0]; -initial begin + initial begin // single address - init_data[0] = {2'b01, 7'h50}; // start write to address 0x50 - init_data[1] = {1'b1, 8'h00}; // write address 0x0004 + init_data[0] = {2'b01, 7'h50}; // start write to address 0x50 + init_data[1] = {1'b1, 8'h00}; // write address 0x0004 init_data[2] = {1'b1, 8'h04}; - init_data[3] = {1'b1, 8'h11}; // write data 0x11223344 + init_data[3] = {1'b1, 8'h11}; // write data 0x11223344 init_data[4] = {1'b1, 8'h22}; init_data[5] = {1'b1, 8'h33}; init_data[6] = {1'b1, 8'h44}; // multiple addresses - init_data[7] = {2'b00, 7'b0001001}; // start data block - init_data[8] = {2'b00, 7'b0000011}; // start write to current address - init_data[9] = {1'b1, 8'h00}; // write address 0x0004 + init_data[7] = {2'b00, 7'b0001001}; // start data block + init_data[8] = {2'b00, 7'b0000011}; // start write to current address + init_data[9] = {1'b1, 8'h00}; // write address 0x0004 init_data[10] = {1'b1, 8'h04}; - init_data[11] = {1'b1, 8'h11}; // write data 0x11223344 + init_data[11] = {1'b1, 8'h11}; // write data 0x11223344 init_data[12] = {1'b1, 8'h22}; init_data[13] = {1'b1, 8'h33}; init_data[14] = {1'b1, 8'h44}; - init_data[15] = {2'b00, 7'b0001000}; // start address block - init_data[16] = {2'b01, 7'h50}; // start write to address 0x50 - init_data[17] = {2'b01, 7'h51}; // start write to address 0x51 - init_data[18] = {2'b01, 7'h52}; // start write to address 0x52 - init_data[19] = {2'b01, 7'h53}; // start write to address 0x53 - init_data[20] = 9'd1; // exit mode - init_data[21] = 9'd0; // stop -end - -localparam [3:0] + init_data[15] = {2'b00, 7'b0001000}; // start address block + init_data[16] = {2'b01, 7'h50}; // start write to address 0x50 + init_data[17] = {2'b01, 7'h51}; // start write to address 0x51 + init_data[18] = {2'b01, 7'h52}; // start write to address 0x52 + init_data[19] = {2'b01, 7'h53}; // start write to address 0x53 + init_data[20] = 9'd1; // exit mode + init_data[21] = 9'd0; // stop + end + + localparam [3:0] STATE_IDLE = 3'd0, STATE_RUN = 3'd1, STATE_TABLE_1 = 3'd2, STATE_TABLE_2 = 3'd3, STATE_TABLE_3 = 3'd4; -reg [4:0] state_reg = STATE_IDLE, state_next; + reg [4:0] state_reg = STATE_IDLE, state_next; -parameter AW = $clog2(INIT_DATA_LEN); + parameter AW = $clog2(INIT_DATA_LEN); -reg [8:0] init_data_reg = 9'd0; + reg [8:0] init_data_reg = 9'd0; -reg [AW-1:0] address_reg = {AW{1'b0}}, address_next; -reg [AW-1:0] address_ptr_reg = {AW{1'b0}}, address_ptr_next; -reg [AW-1:0] data_ptr_reg = {AW{1'b0}}, data_ptr_next; + reg [AW-1:0] address_reg = {AW{1'b0}}, address_next; + reg [AW-1:0] address_ptr_reg = {AW{1'b0}}, address_ptr_next; + reg [AW-1:0] data_ptr_reg = {AW{1'b0}}, data_ptr_next; -reg [6:0] cur_address_reg = 7'd0, cur_address_next; + reg [6:0] cur_address_reg = 7'd0, cur_address_next; -reg [31:0] delay_counter_reg = 32'd0, delay_counter_next; + reg [31:0] delay_counter_reg = 32'd0, delay_counter_next; -reg [6:0] m_axis_cmd_address_reg = 7'd0, m_axis_cmd_address_next; -reg m_axis_cmd_start_reg = 1'b0, m_axis_cmd_start_next; -reg m_axis_cmd_write_reg = 1'b0, m_axis_cmd_write_next; -reg m_axis_cmd_stop_reg = 1'b0, m_axis_cmd_stop_next; -reg m_axis_cmd_valid_reg = 1'b0, m_axis_cmd_valid_next; + reg [6:0] m_axis_cmd_address_reg = 7'd0, m_axis_cmd_address_next; + reg m_axis_cmd_start_reg = 1'b0, m_axis_cmd_start_next; + reg m_axis_cmd_write_reg = 1'b0, m_axis_cmd_write_next; + reg m_axis_cmd_stop_reg = 1'b0, m_axis_cmd_stop_next; + reg m_axis_cmd_valid_reg = 1'b0, m_axis_cmd_valid_next; -reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; -reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; + reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; + reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; -reg start_flag_reg = 1'b0, start_flag_next; + reg start_flag_reg = 1'b0, start_flag_next; -reg busy_reg = 1'b0; + reg busy_reg = 1'b0; -assign m_axis_cmd_address = m_axis_cmd_address_reg; -assign m_axis_cmd_start = m_axis_cmd_start_reg; -assign m_axis_cmd_read = 1'b0; -assign m_axis_cmd_write = m_axis_cmd_write_reg; -assign m_axis_cmd_write_multiple = 1'b0; -assign m_axis_cmd_stop = m_axis_cmd_stop_reg; -assign m_axis_cmd_valid = m_axis_cmd_valid_reg; + assign m_axis_cmd_address = m_axis_cmd_address_reg; + assign m_axis_cmd_start = m_axis_cmd_start_reg; + assign m_axis_cmd_read = 1'b0; + assign m_axis_cmd_write = m_axis_cmd_write_reg; + assign m_axis_cmd_write_multiple = 1'b0; + assign m_axis_cmd_stop = m_axis_cmd_stop_reg; + assign m_axis_cmd_valid = m_axis_cmd_valid_reg; -assign m_axis_data_tdata = m_axis_data_tdata_reg; -assign m_axis_data_tvalid = m_axis_data_tvalid_reg; -assign m_axis_data_tlast = 1'b1; + assign m_axis_data_tdata = m_axis_data_tdata_reg; + assign m_axis_data_tvalid = m_axis_data_tvalid_reg; + assign m_axis_data_tlast = 1'b1; -assign busy = busy_reg; + assign busy = busy_reg; -always @* begin + always @* begin state_next = STATE_IDLE; address_next = address_reg; @@ -237,216 +237,216 @@ always @* begin start_flag_next = start_flag_reg; if (m_axis_cmd_valid | m_axis_data_tvalid) begin - // wait for output registers to clear - state_next = state_reg; + // wait for output registers to clear + state_next = state_reg; end else if (delay_counter_reg != 0) begin - // delay - delay_counter_next = delay_counter_reg - 1; - state_next = state_reg; + // delay + delay_counter_next = delay_counter_reg - 1; + state_next = state_reg; end else begin - case (state_reg) - STATE_IDLE: begin - // wait for start signal - if (~start_flag_reg & start) begin - address_next = {AW{1'b0}}; - start_flag_next = 1'b1; - state_next = STATE_RUN; - end else begin - state_next = STATE_IDLE; - end - end - STATE_RUN: begin - // process commands - if (init_data_reg[8] == 1'b1) begin - // write data - m_axis_cmd_write_next = 1'b1; - m_axis_cmd_stop_next = 1'b0; - m_axis_cmd_valid_next = 1'b1; - - m_axis_data_tdata_next = init_data_reg[7:0]; - m_axis_data_tvalid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg[8:7] == 2'b01) begin - // write address - m_axis_cmd_address_next = init_data_reg[6:0]; - m_axis_cmd_start_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg[8:4] == 5'b00001) begin - // delay - delay_counter_next = 32'd1 << (init_data_reg[3:0]+16); - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg == 9'b001000001) begin - // send stop - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_RUN; - end - end - STATE_TABLE_1: begin - // find address table start - if (init_data_reg == 9'b000001000) begin - // address table start - address_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_2; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 1) begin - // exit mode - address_next = address_reg + 1; - state_next = STATE_RUN; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end - end - STATE_TABLE_2: begin - // find next address - if (init_data_reg[8:7] == 2'b01) begin - // write address command - // store address and move to data table - cur_address_next = init_data_reg[6:0]; - address_ptr_next = address_reg + 1; - address_next = data_ptr_reg; - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 9'd1) begin - // exit mode - address_next = address_reg + 1; - state_next = STATE_RUN; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_TABLE_2; - end - end - STATE_TABLE_3: begin - // process data table with selected address - if (init_data_reg[8] == 1'b1) begin - // write data - m_axis_cmd_write_next = 1'b1; - m_axis_cmd_stop_next = 1'b0; - m_axis_cmd_valid_next = 1'b1; - - m_axis_data_tdata_next = init_data_reg[7:0]; - m_axis_data_tvalid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg[8:7] == 2'b01) begin - // write address - m_axis_cmd_address_next = init_data_reg[6:0]; - m_axis_cmd_start_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b000000011) begin - // write current address - m_axis_cmd_address_next = cur_address_reg; - m_axis_cmd_start_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b001000001) begin - // send stop - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 9'b000001000) begin - // address table start - address_next = address_ptr_reg; - state_next = STATE_TABLE_2; - end else if (init_data_reg == 9'd1) begin - // exit mode - address_next = address_reg + 1; - state_next = STATE_RUN; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_TABLE_3; - end - end - endcase + case (state_reg) + STATE_IDLE: begin + // wait for start signal + if (~start_flag_reg & start) begin + address_next = {AW{1'b0}}; + start_flag_next = 1'b1; + state_next = STATE_RUN; + end else begin + state_next = STATE_IDLE; + end + end + STATE_RUN: begin + // process commands + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_data_tdata_next = init_data_reg[7:0]; + m_axis_data_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:4] == 5'b00001) begin + // delay + delay_counter_next = 32'd1 << (init_data_reg[3:0] + 16); + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_RUN; + end + end + STATE_TABLE_1: begin + // find address table start + if (init_data_reg == 9'b000001000) begin + // address table start + address_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end + end + STATE_TABLE_2: begin + // find next address + if (init_data_reg[8:7] == 2'b01) begin + // write address command + // store address and move to data table + cur_address_next = init_data_reg[6:0]; + address_ptr_next = address_reg + 1; + address_next = data_ptr_reg; + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end + end + STATE_TABLE_3: begin + // process data table with selected address + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_data_tdata_next = init_data_reg[7:0]; + m_axis_data_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000000011) begin + // write current address + m_axis_cmd_address_next = cur_address_reg; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'b000001000) begin + // address table start + address_next = address_ptr_reg; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_3; + end + end + endcase end -end + end -always @(posedge clk) begin + always @(posedge clk) begin state_reg <= state_next; // read init_data ROM @@ -474,26 +474,26 @@ always @(posedge clk) begin busy_reg <= (state_reg != STATE_IDLE); if (rst) begin - state_reg <= STATE_IDLE; + state_reg <= STATE_IDLE; - init_data_reg <= 9'd0; + init_data_reg <= 9'd0; - address_reg <= {AW{1'b0}}; - address_ptr_reg <= {AW{1'b0}}; - data_ptr_reg <= {AW{1'b0}}; + address_reg <= {AW{1'b0}}; + address_ptr_reg <= {AW{1'b0}}; + data_ptr_reg <= {AW{1'b0}}; - cur_address_reg <= 7'd0; + cur_address_reg <= 7'd0; - delay_counter_reg <= 32'd0; + delay_counter_reg <= 32'd0; - m_axis_cmd_valid_reg <= 1'b0; + m_axis_cmd_valid_reg <= 1'b0; - m_axis_data_tvalid_reg <= 1'b0; + m_axis_data_tvalid_reg <= 1'b0; - start_flag_reg <= 1'b0; + start_flag_reg <= 1'b0; - busy_reg <= 1'b0; + busy_reg <= 1'b0; end -end + end endmodule diff --git a/rtl/i2c_master_axil.v b/rtl/i2c_master_axil.v index 10c0625..d1c5232 100644 --- a/rtl/i2c_master_axil.v +++ b/rtl/i2c_master_axil.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * I2C master AXI lite wrapper */ -module i2c_master_axil # -( +module i2c_master_axil #( parameter DEFAULT_PRESCALE = 1, parameter FIXED_PRESCALE = 0, parameter CMD_FIFO = 1, @@ -39,45 +38,44 @@ module i2c_master_axil # parameter WRITE_FIFO_DEPTH = 32, parameter READ_FIFO = 1, parameter READ_FIFO_DEPTH = 32 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * Host interface */ - input wire [3:0] s_axil_awaddr, - input wire [2:0] s_axil_awprot, + input wire [ 3:0] s_axil_awaddr, + input wire [ 2:0] s_axil_awprot, input wire s_axil_awvalid, output wire s_axil_awready, input wire [31:0] s_axil_wdata, - input wire [3:0] s_axil_wstrb, + input wire [ 3:0] s_axil_wstrb, input wire s_axil_wvalid, output wire s_axil_wready, - output wire [1:0] s_axil_bresp, + output wire [ 1:0] s_axil_bresp, output wire s_axil_bvalid, input wire s_axil_bready, - input wire [3:0] s_axil_araddr, - input wire [2:0] s_axil_arprot, + input wire [ 3:0] s_axil_araddr, + input wire [ 2:0] s_axil_arprot, input wire s_axil_arvalid, output wire s_axil_arready, output wire [31:0] s_axil_rdata, - output wire [1:0] s_axil_rresp, + output wire [ 1:0] s_axil_rresp, output wire s_axil_rvalid, input wire s_axil_rready, /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t ); -/* + /* I2C @@ -295,208 +293,219 @@ I/O pin. This would prevent devices from stretching the clock period. */ -reg s_axil_awready_reg = 1'b0, s_axil_awready_next; -reg s_axil_wready_reg = 1'b0, s_axil_wready_next; -reg s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next; -reg s_axil_arready_reg = 1'b0, s_axil_arready_next; -reg [31:0] s_axil_rdata_reg = 32'd0, s_axil_rdata_next; -reg s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next; - -reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; -reg cmd_start_reg = 1'b0, cmd_start_next; -reg cmd_read_reg = 1'b0, cmd_read_next; -reg cmd_write_reg = 1'b0, cmd_write_next; -reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; -reg cmd_stop_reg = 1'b0, cmd_stop_next; -reg cmd_valid_reg = 1'b0, cmd_valid_next; -wire cmd_ready; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; -reg data_in_last_reg = 1'b0, data_in_last_next; - -wire [7:0] data_out; -wire data_out_valid; -reg data_out_ready_reg = 1'b0, data_out_ready_next; -wire data_out_last; - -reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; - -reg missed_ack_reg = 1'b0, missed_ack_next; - -assign s_axil_awready = s_axil_awready_reg; -assign s_axil_wready = s_axil_wready_reg; -assign s_axil_bresp = 2'b00; -assign s_axil_bvalid = s_axil_bvalid_reg; -assign s_axil_arready = s_axil_arready_reg; -assign s_axil_rdata = s_axil_rdata_reg; -assign s_axil_rresp = 2'b00; -assign s_axil_rvalid = s_axil_rvalid_reg; - -wire [6:0] cmd_address_int; -wire cmd_start_int; -wire cmd_read_int; -wire cmd_write_int; -wire cmd_write_multiple_int; -wire cmd_stop_int; -wire cmd_valid_int; -wire cmd_ready_int; - -wire [7:0] data_in_int; -wire data_in_valid_int; -wire data_in_ready_int; -wire data_in_last_int; - -wire [7:0] data_out_int; -wire data_out_valid_int; -wire data_out_ready_int; -wire data_out_last_int; - -wire busy_int; -wire bus_control_int; -wire bus_active_int; -wire missed_ack_int; - -wire cmd_fifo_empty = !cmd_valid_int; -wire cmd_fifo_full = !cmd_ready; -wire write_fifo_empty = !data_in_valid_int; -wire write_fifo_full = !data_in_ready; -wire read_fifo_empty = !data_out_valid; -wire read_fifo_full = !data_out_ready_int; - -reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; -reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; - -generate - -if (CMD_FIFO) begin - axis_fifo #( - .DEPTH(CMD_FIFO_DEPTH), - .DATA_WIDTH(7+5), - .KEEP_ENABLE(0), - .LAST_ENABLE(0), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - cmd_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata({cmd_address_reg, cmd_start_reg, cmd_read_reg, cmd_write_reg, cmd_write_multiple_reg, cmd_stop_reg}), - .s_axis_tkeep(0), - .s_axis_tvalid(cmd_valid_reg), - .s_axis_tready(cmd_ready), - .s_axis_tlast(1'b0), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata({cmd_address_int, cmd_start_int, cmd_read_int, cmd_write_int, cmd_write_multiple_int, cmd_stop_int}), - .m_axis_tkeep(), - .m_axis_tvalid(cmd_valid_int), - .m_axis_tready(cmd_ready_int), - .m_axis_tlast(), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign cmd_address_int = cmd_address_reg; - assign cmd_start_int = cmd_start_reg; - assign cmd_read_int = cmd_read_reg; - assign cmd_write_int = cmd_write_reg; - assign cmd_write_multiple_int = cmd_write_multiple_reg; - assign cmd_stop_int = cmd_stop_reg; - assign cmd_valid_int = cmd_valid_reg; - assign cmd_ready = cmd_ready_int; -end - -if (WRITE_FIFO) begin - axis_fifo #( - .DEPTH(WRITE_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - write_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_in_reg), - .s_axis_tkeep(0), - .s_axis_tvalid(data_in_valid_reg), - .s_axis_tready(data_in_ready), - .s_axis_tlast(data_in_last_reg), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata(data_in_int), - .m_axis_tkeep(), - .m_axis_tvalid(data_in_valid_int), - .m_axis_tready(data_in_ready_int), - .m_axis_tlast(data_in_last_int), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_in_int = data_in_reg; - assign data_in_valid = data_in_valid_reg; - assign data_in_ready = data_in_ready_int; - assign data_in_last = data_in_last_reg; -end - -if (READ_FIFO) begin - axis_fifo #( - .DEPTH(READ_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - read_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_out_int), - .s_axis_tkeep(0), - .s_axis_tvalid(data_out_valid_int), - .s_axis_tready(data_out_ready_int), - .s_axis_tlast(data_out_last_int), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(0), - // AXI output - .m_axis_tdata(data_out), - .m_axis_tkeep(), - .m_axis_tvalid(data_out_valid), - .m_axis_tready(data_out_ready_reg), - .m_axis_tlast(data_out_last), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_out = data_out_int; - assign data_out_valid = data_out_valid_int; - assign data_out_ready_int = data_out_ready_reg; - assign data_out_last = data_out_last_int; -end - -endgenerate - -always @* begin + reg s_axil_awready_reg = 1'b0, s_axil_awready_next; + reg s_axil_wready_reg = 1'b0, s_axil_wready_next; + reg s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next; + reg s_axil_arready_reg = 1'b0, s_axil_arready_next; + reg [31:0] s_axil_rdata_reg = 32'd0, s_axil_rdata_next; + reg s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next; + + reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; + reg cmd_start_reg = 1'b0, cmd_start_next; + reg cmd_read_reg = 1'b0, cmd_read_next; + reg cmd_write_reg = 1'b0, cmd_write_next; + reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; + reg cmd_stop_reg = 1'b0, cmd_stop_next; + reg cmd_valid_reg = 1'b0, cmd_valid_next; + wire cmd_ready; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + reg data_in_last_reg = 1'b0, data_in_last_next; + + wire [7:0] data_out; + wire data_out_valid; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire data_out_last; + + reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; + + reg missed_ack_reg = 1'b0, missed_ack_next; + + assign s_axil_awready = s_axil_awready_reg; + assign s_axil_wready = s_axil_wready_reg; + assign s_axil_bresp = 2'b00; + assign s_axil_bvalid = s_axil_bvalid_reg; + assign s_axil_arready = s_axil_arready_reg; + assign s_axil_rdata = s_axil_rdata_reg; + assign s_axil_rresp = 2'b00; + assign s_axil_rvalid = s_axil_rvalid_reg; + + wire [6:0] cmd_address_int; + wire cmd_start_int; + wire cmd_read_int; + wire cmd_write_int; + wire cmd_write_multiple_int; + wire cmd_stop_int; + wire cmd_valid_int; + wire cmd_ready_int; + + wire [7:0] data_in_int; + wire data_in_valid_int; + wire data_in_ready_int; + wire data_in_last_int; + + wire [7:0] data_out_int; + wire data_out_valid_int; + wire data_out_ready_int; + wire data_out_last_int; + + wire busy_int; + wire bus_control_int; + wire bus_active_int; + wire missed_ack_int; + + wire cmd_fifo_empty = !cmd_valid_int; + wire cmd_fifo_full = !cmd_ready; + wire write_fifo_empty = !data_in_valid_int; + wire write_fifo_full = !data_in_ready; + wire read_fifo_empty = !data_out_valid; + wire read_fifo_full = !data_out_ready_int; + + reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; + reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; + + generate + + if (CMD_FIFO) begin + axis_fifo #( + .DEPTH(CMD_FIFO_DEPTH), + .DATA_WIDTH(7 + 5), + .KEEP_ENABLE(0), + .LAST_ENABLE(0), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) cmd_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata({ + cmd_address_reg, + cmd_start_reg, + cmd_read_reg, + cmd_write_reg, + cmd_write_multiple_reg, + cmd_stop_reg + }), + .s_axis_tkeep(0), + .s_axis_tvalid(cmd_valid_reg), + .s_axis_tready(cmd_ready), + .s_axis_tlast(1'b0), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata({ + cmd_address_int, + cmd_start_int, + cmd_read_int, + cmd_write_int, + cmd_write_multiple_int, + cmd_stop_int + }), + .m_axis_tkeep(), + .m_axis_tvalid(cmd_valid_int), + .m_axis_tready(cmd_ready_int), + .m_axis_tlast(), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign cmd_address_int = cmd_address_reg; + assign cmd_start_int = cmd_start_reg; + assign cmd_read_int = cmd_read_reg; + assign cmd_write_int = cmd_write_reg; + assign cmd_write_multiple_int = cmd_write_multiple_reg; + assign cmd_stop_int = cmd_stop_reg; + assign cmd_valid_int = cmd_valid_reg; + assign cmd_ready = cmd_ready_int; + end + + if (WRITE_FIFO) begin + axis_fifo #( + .DEPTH(WRITE_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) write_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_in_reg), + .s_axis_tkeep(0), + .s_axis_tvalid(data_in_valid_reg), + .s_axis_tready(data_in_ready), + .s_axis_tlast(data_in_last_reg), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata(data_in_int), + .m_axis_tkeep(), + .m_axis_tvalid(data_in_valid_int), + .m_axis_tready(data_in_ready_int), + .m_axis_tlast(data_in_last_int), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_in_int = data_in_reg; + assign data_in_valid = data_in_valid_reg; + assign data_in_ready = data_in_ready_int; + assign data_in_last = data_in_last_reg; + end + + if (READ_FIFO) begin + axis_fifo #( + .DEPTH(READ_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) read_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_out_int), + .s_axis_tkeep(0), + .s_axis_tvalid(data_out_valid_int), + .s_axis_tready(data_out_ready_int), + .s_axis_tlast(data_out_last_int), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(0), + // AXI output + .m_axis_tdata(data_out), + .m_axis_tkeep(), + .m_axis_tvalid(data_out_valid), + .m_axis_tready(data_out_ready_reg), + .m_axis_tlast(data_out_last), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_out = data_out_int; + assign data_out_valid = data_out_valid_int; + assign data_out_ready_int = data_out_ready_reg; + assign data_out_last = data_out_last_int; + end + + endgenerate + + always @* begin s_axil_awready_next = 1'b0; s_axil_wready_next = 1'b0; s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_bready; @@ -526,128 +535,132 @@ always @* begin write_fifo_overflow_next = write_fifo_overflow_reg; if (s_axil_awvalid && s_axil_wvalid && !s_axil_bvalid) begin - // write operation - s_axil_awready_next = 1'b1; - s_axil_wready_next = 1'b1; - s_axil_bvalid_next = 1'b1; - - case ({s_axil_awaddr[3:2], 2'b00}) - 4'h0: begin - // status register - if (s_axil_wstrb[0]) begin - if (s_axil_wdata[3]) begin - missed_ack_next = missed_ack_int; - end - end - if (s_axil_wstrb[1]) begin - if (s_axil_wdata[10]) begin - cmd_fifo_overflow_next = 1'b0; - end - if (s_axil_wdata[13]) begin - write_fifo_overflow_next = 1'b0; - end - end + // write operation + s_axil_awready_next = 1'b1; + s_axil_wready_next = 1'b1; + s_axil_bvalid_next = 1'b1; + + case ({ + s_axil_awaddr[3:2], 2'b00 + }) + 4'h0: begin + // status register + if (s_axil_wstrb[0]) begin + if (s_axil_wdata[3]) begin + missed_ack_next = missed_ack_int; end - 4'h4: begin - // command - if (s_axil_wstrb[0]) begin - cmd_address_next = s_axil_wdata[6:0]; - end - if (s_axil_wstrb[1]) begin - cmd_start_next = s_axil_wdata[8]; - cmd_read_next = s_axil_wdata[9]; - cmd_write_next = s_axil_wdata[10]; - cmd_write_multiple_next = s_axil_wdata[11]; - cmd_stop_next = s_axil_wdata[12]; - cmd_valid_next = cmd_start_next || cmd_read_next || cmd_write_next || cmd_write_multiple_next || cmd_stop_next; - - cmd_fifo_overflow_next = cmd_fifo_overflow_next || (cmd_valid_next && !cmd_ready); - end + end + if (s_axil_wstrb[1]) begin + if (s_axil_wdata[10]) begin + cmd_fifo_overflow_next = 1'b0; end - 4'h8: begin - // data - if (s_axil_wstrb[0]) begin - data_in_next = s_axil_wdata[7:0]; - - if (s_axil_wstrb[1]) begin - // only valid with atomic 16 bit write - data_in_last_next = s_axil_wdata[9]; - end else begin - data_in_last_next = 1'b0; - end - - data_in_valid_next = 1'b1; - - write_fifo_overflow_next = write_fifo_overflow_next || !data_in_ready; - end + if (s_axil_wdata[13]) begin + write_fifo_overflow_next = 1'b0; end - 4'hC: begin - // prescale - if (!FIXED_PRESCALE && s_axil_wstrb[0]) begin - prescale_next[7:0] = s_axil_wdata[7:0]; - end - if (!FIXED_PRESCALE && s_axil_wstrb[1]) begin - prescale_next[15:8] = s_axil_wdata[15:8]; - end + end + end + 4'h4: begin + // command + if (s_axil_wstrb[0]) begin + cmd_address_next = s_axil_wdata[6:0]; + end + if (s_axil_wstrb[1]) begin + cmd_start_next = s_axil_wdata[8]; + cmd_read_next = s_axil_wdata[9]; + cmd_write_next = s_axil_wdata[10]; + cmd_write_multiple_next = s_axil_wdata[11]; + cmd_stop_next = s_axil_wdata[12]; + cmd_valid_next = cmd_start_next || cmd_read_next || cmd_write_next || cmd_write_multiple_next || cmd_stop_next; + + cmd_fifo_overflow_next = cmd_fifo_overflow_next || (cmd_valid_next && !cmd_ready); + end + end + 4'h8: begin + // data + if (s_axil_wstrb[0]) begin + data_in_next = s_axil_wdata[7:0]; + + if (s_axil_wstrb[1]) begin + // only valid with atomic 16 bit write + data_in_last_next = s_axil_wdata[9]; + end else begin + data_in_last_next = 1'b0; end - endcase + + data_in_valid_next = 1'b1; + + write_fifo_overflow_next = write_fifo_overflow_next || !data_in_ready; + end + end + 4'hC: begin + // prescale + if (!FIXED_PRESCALE && s_axil_wstrb[0]) begin + prescale_next[7:0] = s_axil_wdata[7:0]; + end + if (!FIXED_PRESCALE && s_axil_wstrb[1]) begin + prescale_next[15:8] = s_axil_wdata[15:8]; + end + end + endcase end if (s_axil_arvalid && !s_axil_rvalid) begin - // read operation - s_axil_arready_next = 1'b1; - s_axil_rvalid_next = 1'b1; - s_axil_rdata_next = 32'd0; - - case ({s_axil_araddr[3:2], 2'b00}) - 4'h0: begin - // status - s_axil_rdata_next[0] = busy_int; - s_axil_rdata_next[1] = bus_control_int; - s_axil_rdata_next[2] = bus_active_int; - s_axil_rdata_next[3] = missed_ack_reg; - s_axil_rdata_next[4] = 1'b0; - s_axil_rdata_next[5] = 1'b0; - s_axil_rdata_next[6] = 1'b0; - s_axil_rdata_next[7] = 1'b0; - s_axil_rdata_next[8] = cmd_fifo_empty; - s_axil_rdata_next[9] = cmd_fifo_full; - s_axil_rdata_next[10] = cmd_fifo_overflow_reg; - s_axil_rdata_next[11] = write_fifo_empty; - s_axil_rdata_next[12] = write_fifo_full; - s_axil_rdata_next[13] = write_fifo_overflow_reg; - s_axil_rdata_next[14] = read_fifo_empty; - s_axil_rdata_next[15] = read_fifo_full; - end - 4'h4: begin - // command - s_axil_rdata_next[6:0] = cmd_address_reg; - s_axil_rdata_next[7] = 1'b0; - s_axil_rdata_next[8] = cmd_start_reg; - s_axil_rdata_next[9] = cmd_read_reg; - s_axil_rdata_next[10] = cmd_write_reg; - s_axil_rdata_next[11] = cmd_write_multiple_reg; - s_axil_rdata_next[12] = cmd_stop_reg; - s_axil_rdata_next[13] = 1'b0; - s_axil_rdata_next[14] = 1'b0; - s_axil_rdata_next[15] = 1'b0; - end - 4'h8: begin - // data - s_axil_rdata_next[7:0] = data_out; - s_axil_rdata_next[8] = data_out_valid; - s_axil_rdata_next[9] = data_out_last; - data_out_ready_next = data_out_valid; - end - 4'hC: begin - // prescale - s_axil_rdata_next = prescale_reg; - end - endcase + // read operation + s_axil_arready_next = 1'b1; + s_axil_rvalid_next = 1'b1; + s_axil_rdata_next = 32'd0; + + case ({ + s_axil_araddr[3:2], 2'b00 + }) + 4'h0: begin + // status + s_axil_rdata_next[0] = busy_int; + s_axil_rdata_next[1] = bus_control_int; + s_axil_rdata_next[2] = bus_active_int; + s_axil_rdata_next[3] = missed_ack_reg; + s_axil_rdata_next[4] = 1'b0; + s_axil_rdata_next[5] = 1'b0; + s_axil_rdata_next[6] = 1'b0; + s_axil_rdata_next[7] = 1'b0; + s_axil_rdata_next[8] = cmd_fifo_empty; + s_axil_rdata_next[9] = cmd_fifo_full; + s_axil_rdata_next[10] = cmd_fifo_overflow_reg; + s_axil_rdata_next[11] = write_fifo_empty; + s_axil_rdata_next[12] = write_fifo_full; + s_axil_rdata_next[13] = write_fifo_overflow_reg; + s_axil_rdata_next[14] = read_fifo_empty; + s_axil_rdata_next[15] = read_fifo_full; + end + 4'h4: begin + // command + s_axil_rdata_next[6:0] = cmd_address_reg; + s_axil_rdata_next[7] = 1'b0; + s_axil_rdata_next[8] = cmd_start_reg; + s_axil_rdata_next[9] = cmd_read_reg; + s_axil_rdata_next[10] = cmd_write_reg; + s_axil_rdata_next[11] = cmd_write_multiple_reg; + s_axil_rdata_next[12] = cmd_stop_reg; + s_axil_rdata_next[13] = 1'b0; + s_axil_rdata_next[14] = 1'b0; + s_axil_rdata_next[15] = 1'b0; + end + 4'h8: begin + // data + s_axil_rdata_next[7:0] = data_out; + s_axil_rdata_next[8] = data_out_valid; + s_axil_rdata_next[9] = data_out_last; + data_out_ready_next = data_out_valid; + end + 4'hC: begin + // prescale + s_axil_rdata_next = prescale_reg; + end + endcase end -end + end -always @(posedge clk) begin + always @(posedge clk) begin s_axil_awready_reg <= s_axil_awready_next; s_axil_wready_reg <= s_axil_wready_next; s_axil_bvalid_reg <= s_axil_bvalid_next; @@ -677,63 +690,62 @@ always @(posedge clk) begin write_fifo_overflow_reg <= write_fifo_overflow_next; if (rst) begin - s_axil_awready_reg <= 1'b0; - s_axil_wready_reg <= 1'b0; - s_axil_bvalid_reg <= 1'b0; - s_axil_arready_reg <= 1'b0; - s_axil_rvalid_reg <= 1'b0; - cmd_valid_reg <= 1'b0; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - prescale_reg <= DEFAULT_PRESCALE; - missed_ack_reg <= 1'b0; - cmd_fifo_overflow_reg <= 1'b0; - write_fifo_overflow_reg <= 1'b0; + s_axil_awready_reg <= 1'b0; + s_axil_wready_reg <= 1'b0; + s_axil_bvalid_reg <= 1'b0; + s_axil_arready_reg <= 1'b0; + s_axil_rvalid_reg <= 1'b0; + cmd_valid_reg <= 1'b0; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + prescale_reg <= DEFAULT_PRESCALE; + missed_ack_reg <= 1'b0; + cmd_fifo_overflow_reg <= 1'b0; + write_fifo_overflow_reg <= 1'b0; end -end - -i2c_master -i2c_master_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .s_axis_cmd_address(cmd_address_int), - .s_axis_cmd_start(cmd_start_int), - .s_axis_cmd_read(cmd_read_int), - .s_axis_cmd_write(cmd_write_int), - .s_axis_cmd_write_multiple(cmd_write_multiple_int), - .s_axis_cmd_stop(cmd_stop_int), - .s_axis_cmd_valid(cmd_valid_int), - .s_axis_cmd_ready(cmd_ready_int), - - .s_axis_data_tdata(data_in_int), - .s_axis_data_tvalid(data_in_valid_int), - .s_axis_data_tready(data_in_ready_int), - .s_axis_data_tlast(data_in_last_int), - - .m_axis_data_tdata(data_out_int), - .m_axis_data_tvalid(data_out_valid_int), - .m_axis_data_tready(data_out_ready_int), - .m_axis_data_tlast(data_out_last_int), - - // I2C interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(busy_int), - .bus_control(bus_control_int), - .bus_active(bus_active_int), - .missed_ack(missed_ack_int), - - // Configuration - .prescale(prescale_reg), - .stop_on_idle(1'b0) -); + end + + i2c_master i2c_master_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .s_axis_cmd_address(cmd_address_int), + .s_axis_cmd_start(cmd_start_int), + .s_axis_cmd_read(cmd_read_int), + .s_axis_cmd_write(cmd_write_int), + .s_axis_cmd_write_multiple(cmd_write_multiple_int), + .s_axis_cmd_stop(cmd_stop_int), + .s_axis_cmd_valid(cmd_valid_int), + .s_axis_cmd_ready(cmd_ready_int), + + .s_axis_data_tdata (data_in_int), + .s_axis_data_tvalid(data_in_valid_int), + .s_axis_data_tready(data_in_ready_int), + .s_axis_data_tlast (data_in_last_int), + + .m_axis_data_tdata (data_out_int), + .m_axis_data_tvalid(data_out_valid_int), + .m_axis_data_tready(data_out_ready_int), + .m_axis_data_tlast (data_out_last_int), + + // I2C interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(busy_int), + .bus_control(bus_control_int), + .bus_active(bus_active_int), + .missed_ack(missed_ack_int), + + // Configuration + .prescale(prescale_reg), + .stop_on_idle(1'b0) + ); endmodule diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index 072cb15..103d6fe 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -1,6 +1,6 @@ // Language: Verilog 2001 -`timescale 1ns/1ps +`timescale 1ns / 1ps /* * Testbench for i2c_master @@ -10,10 +10,10 @@ module i2c_master_tb; // Parameters parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) - parameter ENABLE_DEVICE_3 = 1; // Set to 0 to disable device 3 + parameter ENABLE_DEVICE_3 = 1; // Set to 0 to disable device 3 parameter ENABLE_DEVICE_4 = 1; // Set to 0 to disable device 4 - reg clk = 0; + reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; @@ -287,89 +287,89 @@ module i2c_master_tb; endtask // Task to test NACK handling -task test_nack_handling; + task test_nack_handling; begin - $display("Testing NACK handling."); - i2c_start(7'b0000001, 0); - s_axis_data_tdata = 8'b10100101; - s_axis_data_tvalid = 1; - @(posedge missed_ack); - $display("NACK expected!"); - wait_for_ready(); + $display("Testing NACK handling."); + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10100101; + s_axis_data_tvalid = 1; + @(posedge missed_ack); + $display("NACK expected!"); + wait_for_ready(); end -endtask + endtask -// Task to test writing -task test_writing; + // Task to test writing + task test_writing; begin - $display("Testing Writing."); - i2c_start(7'b0000001, 0); - s_axis_data_tdata = 8'b10101111; - s_axis_data_tvalid = 1; - repeat(7) @(negedge scl_o); - send_ack(); - @(negedge scl_o); - //send_byte(8'b01111111); - wait_for_ready(); - end -endtask + $display("Testing Writing."); + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + repeat (7) @(negedge scl_o); + send_ack(); + @(negedge scl_o); + //send_byte(8'b01111111); + wait_for_ready(); + end + endtask -// Task to test reading -task test_reading; + // Task to test reading + task test_reading; begin - $display("Testing reading."); - s_axis_data_tdata = 8'b10101111; - s_axis_data_tvalid = 1; - i2c_start(7'b0000001, 1); - repeat(7) @(negedge scl_o); - s_axis_cmd_valid = 0; - send_ack(); - send_byte(8'b01111111); - s_axis_cmd_read = 1; - s_axis_cmd_valid = 1; - m_axis_data_tready = 1; - @(negedge scl_o); - if (sda_wire) $fatal(1, "Got NACK from master"); - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - if (m_axis_data_tdata != 8'b01111111) $fatal(1, "We didn't get what we sent"); - #(CLK_PERIOD); - stop_on_idle = 1; - send_byte(8'd69); - @(posedge m_axis_data_tvalid); - if (m_axis_data_tdata != 8'd69) $fatal(1, "We didn't get what we sent"); - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - s_axis_cmd_valid = 0; - wait_for_ready(); + $display("Testing reading."); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + i2c_start(7'b0000001, 1); + repeat (7) @(negedge scl_o); + s_axis_cmd_valid = 0; + send_ack(); + send_byte(8'b01111111); + s_axis_cmd_read = 1; + s_axis_cmd_valid = 1; + m_axis_data_tready = 1; + @(negedge scl_o); + if (sda_wire) $fatal(1, "Got NACK from master"); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'b01111111) $fatal(1, "We didn't get what we sent"); + #(CLK_PERIOD); + stop_on_idle = 1; + send_byte(8'd69); + @(posedge m_axis_data_tvalid); + if (m_axis_data_tdata != 8'd69) $fatal(1, "We didn't get what we sent"); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + s_axis_cmd_valid = 0; + wait_for_ready(); end -endtask + endtask -// Task to test i2c_single_reg writing -task test_i2c_single_reg_writing; + // Task to test i2c_single_reg writing + task test_i2c_single_reg_writing; begin - $display("Testing i2c_single_reg writing"); - i2c_start(7'h70, 0); - s_axis_data_tdata = 8'd55; - s_axis_data_tvalid = 1; - wait_for_ready(); - if (device_3.data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); - $display("Received data %d", device_3.data_out_3); + $display("Testing i2c_single_reg writing"); + i2c_start(7'h70, 0); + s_axis_data_tdata = 8'd55; + s_axis_data_tvalid = 1; + wait_for_ready(); + if (device_3.data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); + $display("Received data %d", device_3.data_out_3); end -endtask + endtask -// Task to test i2c_single_reg reading -task test_i2c_single_reg_reading; + // Task to test i2c_single_reg reading + task test_i2c_single_reg_reading; begin - $display("Testing i2c_single_reg reading"); - device_3.data_latch_3 = 1; - device_3.data_in_3 = 8'd123; - #(CLK_PERIOD); - device_3.data_latch_3 = 0; - i2c_start(7'h70, 1); - @(posedge m_axis_data_tvalid); - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - if (m_axis_data_tdata != 8'd123) $fatal(1, "We didn't get what we sent"); + $display("Testing i2c_single_reg reading"); + device_3.data_latch_3 = 1; + device_3.data_in_3 = 8'd123; + #(CLK_PERIOD); + device_3.data_latch_3 = 0; + i2c_start(7'h70, 1); + @(posedge m_axis_data_tvalid); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'd123) $fatal(1, "We didn't get what we sent"); end -endtask + endtask initial begin $display("Starting I2C Master test"); @@ -377,7 +377,7 @@ endtask test_nack_handling(); stop_on_idle = 1; test_writing(); - #1000;//stopping + #1000; //stopping test_reading(); wait_for_ready(); diff --git a/rtl/i2c_master_wbs_16.v b/rtl/i2c_master_wbs_16.v index d592b00..b95d87d 100644 --- a/rtl/i2c_master_wbs_16.v +++ b/rtl/i2c_master_wbs_16.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * I2C master wishbone slave wrapper (16 bit) */ -module i2c_master_wbs_16 # -( +module i2c_master_wbs_16 #( parameter DEFAULT_PRESCALE = 1, parameter FIXED_PRESCALE = 0, parameter CMD_FIFO = 1, @@ -39,34 +38,33 @@ module i2c_master_wbs_16 # parameter WRITE_FIFO_DEPTH = 32, parameter READ_FIFO = 1, parameter READ_FIFO_DEPTH = 32 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * Host interface */ - input wire [2:0] wbs_adr_i, // ADR_I() address - input wire [15:0] wbs_dat_i, // DAT_I() data in - output wire [15:0] wbs_dat_o, // DAT_O() data out - input wire wbs_we_i, // WE_I write enable input - input wire [1:0] wbs_sel_i, // SEL_I() select input - input wire wbs_stb_i, // STB_I strobe input - output wire wbs_ack_o, // ACK_O acknowledge output - input wire wbs_cyc_i, // CYC_I cycle input + input wire [ 2:0] wbs_adr_i, // ADR_I() address + input wire [15:0] wbs_dat_i, // DAT_I() data in + output wire [15:0] wbs_dat_o, // DAT_O() data out + input wire wbs_we_i, // WE_I write enable input + input wire [ 1:0] wbs_sel_i, // SEL_I() select input + input wire wbs_stb_i, // STB_I strobe input + output wire wbs_ack_o, // ACK_O acknowledge output + input wire wbs_cyc_i, // CYC_I cycle input /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t ); -/* + /* I2C @@ -252,198 +250,209 @@ I/O pin. This would prevent devices from stretching the clock period. */ -reg [15:0] wbs_dat_o_reg = 16'd0, wbs_dat_o_next; -reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; - -reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; -reg cmd_start_reg = 1'b0, cmd_start_next; -reg cmd_read_reg = 1'b0, cmd_read_next; -reg cmd_write_reg = 1'b0, cmd_write_next; -reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; -reg cmd_stop_reg = 1'b0, cmd_stop_next; -reg cmd_valid_reg = 1'b0, cmd_valid_next; -wire cmd_ready; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; -reg data_in_last_reg = 1'b0, data_in_last_next; - -wire [7:0] data_out; -wire data_out_valid; -reg data_out_ready_reg = 1'b0, data_out_ready_next; -wire data_out_last; - -reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; - -reg missed_ack_reg = 1'b0, missed_ack_next; - -assign wbs_dat_o = wbs_dat_o_reg; -assign wbs_ack_o = wbs_ack_o_reg; - -wire [6:0] cmd_address_int; -wire cmd_start_int; -wire cmd_read_int; -wire cmd_write_int; -wire cmd_write_multiple_int; -wire cmd_stop_int; -wire cmd_valid_int; -wire cmd_ready_int; - -wire [7:0] data_in_int; -wire data_in_valid_int; -wire data_in_ready_int; -wire data_in_last_int; - -wire [7:0] data_out_int; -wire data_out_valid_int; -wire data_out_ready_int; -wire data_out_last_int; - -wire busy_int; -wire bus_control_int; -wire bus_active_int; -wire missed_ack_int; - -wire cmd_fifo_empty = ~cmd_valid_int; -wire cmd_fifo_full = ~cmd_ready; -wire write_fifo_empty = ~data_in_valid_int; -wire write_fifo_full = ~data_in_ready; -wire read_fifo_empty = ~data_out_valid; -wire read_fifo_full = ~data_out_ready_int; - -reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; -reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; - -generate - -if (CMD_FIFO) begin - axis_fifo #( - .DEPTH(CMD_FIFO_DEPTH), - .DATA_WIDTH(7+5), - .KEEP_ENABLE(0), - .LAST_ENABLE(0), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - cmd_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata({cmd_address_reg, cmd_start_reg, cmd_read_reg, cmd_write_reg, cmd_write_multiple_reg, cmd_stop_reg}), - .s_axis_tkeep(0), - .s_axis_tvalid(cmd_valid_reg), - .s_axis_tready(cmd_ready), - .s_axis_tlast(1'b0), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata({cmd_address_int, cmd_start_int, cmd_read_int, cmd_write_int, cmd_write_multiple_int, cmd_stop_int}), - .m_axis_tkeep(), - .m_axis_tvalid(cmd_valid_int), - .m_axis_tready(cmd_ready_int), - .m_axis_tlast(), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign cmd_address_int = cmd_address_reg; - assign cmd_start_int = cmd_start_reg; - assign cmd_read_int = cmd_read_reg; - assign cmd_write_int = cmd_write_reg; - assign cmd_write_multiple_int = cmd_write_multiple_reg; - assign cmd_stop_int = cmd_stop_reg; - assign cmd_valid_int = cmd_valid_reg; - assign cmd_ready = cmd_ready_int; -end - -if (WRITE_FIFO) begin - axis_fifo #( - .DEPTH(WRITE_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - write_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_in_reg), - .s_axis_tkeep(0), - .s_axis_tvalid(data_in_valid_reg), - .s_axis_tready(data_in_ready), - .s_axis_tlast(data_in_last_reg), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata(data_in_int), - .m_axis_tkeep(), - .m_axis_tvalid(data_in_valid_int), - .m_axis_tready(data_in_ready_int), - .m_axis_tlast(data_in_last_int), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_in_int = data_in_reg; - assign data_in_valid = data_in_valid_reg; - assign data_in_ready = data_in_ready_int; - assign data_in_last = data_in_last_reg; -end - -if (READ_FIFO) begin - axis_fifo #( - .DEPTH(READ_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - read_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_out_int), - .s_axis_tkeep(0), - .s_axis_tvalid(data_out_valid_int), - .s_axis_tready(data_out_ready_int), - .s_axis_tlast(data_out_last_int), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(0), - // AXI output - .m_axis_tdata(data_out), - .m_axis_tkeep(), - .m_axis_tvalid(data_out_valid), - .m_axis_tready(data_out_ready_reg), - .m_axis_tlast(data_out_last), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_out = data_out_int; - assign data_out_valid = data_out_valid_int; - assign data_out_ready_int = data_out_ready_reg; - assign data_out_last = data_out_last_int; -end - -endgenerate - -always @* begin + reg [15:0] wbs_dat_o_reg = 16'd0, wbs_dat_o_next; + reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; + + reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; + reg cmd_start_reg = 1'b0, cmd_start_next; + reg cmd_read_reg = 1'b0, cmd_read_next; + reg cmd_write_reg = 1'b0, cmd_write_next; + reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; + reg cmd_stop_reg = 1'b0, cmd_stop_next; + reg cmd_valid_reg = 1'b0, cmd_valid_next; + wire cmd_ready; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + reg data_in_last_reg = 1'b0, data_in_last_next; + + wire [7:0] data_out; + wire data_out_valid; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire data_out_last; + + reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; + + reg missed_ack_reg = 1'b0, missed_ack_next; + + assign wbs_dat_o = wbs_dat_o_reg; + assign wbs_ack_o = wbs_ack_o_reg; + + wire [6:0] cmd_address_int; + wire cmd_start_int; + wire cmd_read_int; + wire cmd_write_int; + wire cmd_write_multiple_int; + wire cmd_stop_int; + wire cmd_valid_int; + wire cmd_ready_int; + + wire [7:0] data_in_int; + wire data_in_valid_int; + wire data_in_ready_int; + wire data_in_last_int; + + wire [7:0] data_out_int; + wire data_out_valid_int; + wire data_out_ready_int; + wire data_out_last_int; + + wire busy_int; + wire bus_control_int; + wire bus_active_int; + wire missed_ack_int; + + wire cmd_fifo_empty = ~cmd_valid_int; + wire cmd_fifo_full = ~cmd_ready; + wire write_fifo_empty = ~data_in_valid_int; + wire write_fifo_full = ~data_in_ready; + wire read_fifo_empty = ~data_out_valid; + wire read_fifo_full = ~data_out_ready_int; + + reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; + reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; + + generate + + if (CMD_FIFO) begin + axis_fifo #( + .DEPTH(CMD_FIFO_DEPTH), + .DATA_WIDTH(7 + 5), + .KEEP_ENABLE(0), + .LAST_ENABLE(0), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) cmd_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata({ + cmd_address_reg, + cmd_start_reg, + cmd_read_reg, + cmd_write_reg, + cmd_write_multiple_reg, + cmd_stop_reg + }), + .s_axis_tkeep(0), + .s_axis_tvalid(cmd_valid_reg), + .s_axis_tready(cmd_ready), + .s_axis_tlast(1'b0), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata({ + cmd_address_int, + cmd_start_int, + cmd_read_int, + cmd_write_int, + cmd_write_multiple_int, + cmd_stop_int + }), + .m_axis_tkeep(), + .m_axis_tvalid(cmd_valid_int), + .m_axis_tready(cmd_ready_int), + .m_axis_tlast(), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign cmd_address_int = cmd_address_reg; + assign cmd_start_int = cmd_start_reg; + assign cmd_read_int = cmd_read_reg; + assign cmd_write_int = cmd_write_reg; + assign cmd_write_multiple_int = cmd_write_multiple_reg; + assign cmd_stop_int = cmd_stop_reg; + assign cmd_valid_int = cmd_valid_reg; + assign cmd_ready = cmd_ready_int; + end + + if (WRITE_FIFO) begin + axis_fifo #( + .DEPTH(WRITE_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) write_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_in_reg), + .s_axis_tkeep(0), + .s_axis_tvalid(data_in_valid_reg), + .s_axis_tready(data_in_ready), + .s_axis_tlast(data_in_last_reg), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata(data_in_int), + .m_axis_tkeep(), + .m_axis_tvalid(data_in_valid_int), + .m_axis_tready(data_in_ready_int), + .m_axis_tlast(data_in_last_int), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_in_int = data_in_reg; + assign data_in_valid = data_in_valid_reg; + assign data_in_ready = data_in_ready_int; + assign data_in_last = data_in_last_reg; + end + + if (READ_FIFO) begin + axis_fifo #( + .DEPTH(READ_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) read_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_out_int), + .s_axis_tkeep(0), + .s_axis_tvalid(data_out_valid_int), + .s_axis_tready(data_out_ready_int), + .s_axis_tlast(data_out_last_int), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(0), + // AXI output + .m_axis_tdata(data_out), + .m_axis_tkeep(), + .m_axis_tvalid(data_out_valid), + .m_axis_tready(data_out_ready_reg), + .m_axis_tlast(data_out_last), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_out = data_out_int; + assign data_out_valid = data_out_valid_int; + assign data_out_ready_int = data_out_ready_reg; + assign data_out_last = data_out_last_int; + end + + endgenerate + + always @* begin wbs_dat_o_next = 8'd0; wbs_ack_o_next = 1'b0; @@ -467,129 +476,129 @@ always @* begin cmd_fifo_overflow_next = cmd_fifo_overflow_reg; write_fifo_overflow_next = write_fifo_overflow_reg; - + if (wbs_cyc_i & wbs_stb_i) begin - // bus cycle - if (wbs_we_i) begin - // write cycle - case (wbs_adr_i) - 3'h0: begin - // status register - if (wbs_sel_i[0]) begin - if (wbs_dat_i[3]) begin - missed_ack_next = missed_ack_int; - end - end - if (wbs_sel_i[1]) begin - if (wbs_dat_i[10]) begin - cmd_fifo_overflow_next = 1'b0; - end - if (wbs_dat_i[13]) begin - write_fifo_overflow_next = 1'b0; - end - end - end - 3'h2: begin - // command - if (wbs_sel_i[0]) begin - cmd_address_next = wbs_dat_i[6:0]; - end - if (wbs_sel_i[1]) begin - cmd_start_next = wbs_dat_i[8]; - cmd_read_next = wbs_dat_i[9]; - cmd_write_next = wbs_dat_i[10]; - cmd_write_multiple_next = wbs_dat_i[11]; - cmd_stop_next = wbs_dat_i[12]; - cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_write_multiple_next | cmd_stop_next); - - cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); - end - end - 3'h4: begin - // data - if (wbs_sel_i[0]) begin - data_in_next = wbs_dat_i[7:0]; - - if (wbs_sel_i[1]) begin - // only valid with atomic 16 bit write - data_in_last_next = wbs_dat_i[9]; - end else begin - data_in_last_next = 1'b0; - end - - data_in_valid_next = ~wbs_ack_o_reg; - - write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; - end - end - 3'h6: begin - // prescale - if (!FIXED_PRESCALE && wbs_sel_i[0]) begin - prescale_next[7:0] = wbs_dat_i[7:0]; - end - if (!FIXED_PRESCALE && wbs_sel_i[1]) begin - prescale_next[15:0] = wbs_dat_i[15:0]; - end - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end else begin - // read cycle - case (wbs_adr_i) - 3'h0: begin - // status - wbs_dat_o_next[0] = busy_int; - wbs_dat_o_next[1] = bus_control_int; - wbs_dat_o_next[2] = bus_active_int; - wbs_dat_o_next[3] = missed_ack_reg; - wbs_dat_o_next[4] = 1'b0; - wbs_dat_o_next[5] = 1'b0; - wbs_dat_o_next[6] = 1'b0; - wbs_dat_o_next[7] = 1'b0; - wbs_dat_o_next[8] = cmd_fifo_empty; - wbs_dat_o_next[9] = cmd_fifo_full; - wbs_dat_o_next[10] = cmd_fifo_overflow_reg; - wbs_dat_o_next[11] = write_fifo_empty; - wbs_dat_o_next[12] = write_fifo_full; - wbs_dat_o_next[13] = write_fifo_overflow_reg; - wbs_dat_o_next[14] = read_fifo_empty; - wbs_dat_o_next[15] = read_fifo_full; - end - 3'h2: begin - // command - wbs_dat_o_next[6:0] = cmd_address_reg; - wbs_dat_o_next[7] = 1'b0; - wbs_dat_o_next[8] = cmd_start_reg; - wbs_dat_o_next[9] = cmd_read_reg; - wbs_dat_o_next[10] = cmd_write_reg; - wbs_dat_o_next[11] = cmd_write_multiple_reg; - wbs_dat_o_next[12] = cmd_stop_reg; - wbs_dat_o_next[13] = 1'b0; - wbs_dat_o_next[14] = 1'b0; - wbs_dat_o_next[15] = 1'b0; - end - 3'h4: begin - // data - wbs_dat_o_next[7:0] = data_out; - wbs_dat_o_next[8] = data_out_valid; - wbs_dat_o_next[9] = data_out_last; - wbs_dat_o_next[15:10] = 6'd0; - - if (wbs_sel_i[0]) begin - data_out_ready_next = !wbs_ack_o_reg && data_out_valid; - end - end - 3'h6: begin - // prescale - wbs_dat_o_next = prescale_reg; - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end + // bus cycle + if (wbs_we_i) begin + // write cycle + case (wbs_adr_i) + 3'h0: begin + // status register + if (wbs_sel_i[0]) begin + if (wbs_dat_i[3]) begin + missed_ack_next = missed_ack_int; + end + end + if (wbs_sel_i[1]) begin + if (wbs_dat_i[10]) begin + cmd_fifo_overflow_next = 1'b0; + end + if (wbs_dat_i[13]) begin + write_fifo_overflow_next = 1'b0; + end + end + end + 3'h2: begin + // command + if (wbs_sel_i[0]) begin + cmd_address_next = wbs_dat_i[6:0]; + end + if (wbs_sel_i[1]) begin + cmd_start_next = wbs_dat_i[8]; + cmd_read_next = wbs_dat_i[9]; + cmd_write_next = wbs_dat_i[10]; + cmd_write_multiple_next = wbs_dat_i[11]; + cmd_stop_next = wbs_dat_i[12]; + cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_write_multiple_next | cmd_stop_next); + + cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); + end + end + 3'h4: begin + // data + if (wbs_sel_i[0]) begin + data_in_next = wbs_dat_i[7:0]; + + if (wbs_sel_i[1]) begin + // only valid with atomic 16 bit write + data_in_last_next = wbs_dat_i[9]; + end else begin + data_in_last_next = 1'b0; + end + + data_in_valid_next = ~wbs_ack_o_reg; + + write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; + end + end + 3'h6: begin + // prescale + if (!FIXED_PRESCALE && wbs_sel_i[0]) begin + prescale_next[7:0] = wbs_dat_i[7:0]; + end + if (!FIXED_PRESCALE && wbs_sel_i[1]) begin + prescale_next[15:0] = wbs_dat_i[15:0]; + end + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end else begin + // read cycle + case (wbs_adr_i) + 3'h0: begin + // status + wbs_dat_o_next[0] = busy_int; + wbs_dat_o_next[1] = bus_control_int; + wbs_dat_o_next[2] = bus_active_int; + wbs_dat_o_next[3] = missed_ack_reg; + wbs_dat_o_next[4] = 1'b0; + wbs_dat_o_next[5] = 1'b0; + wbs_dat_o_next[6] = 1'b0; + wbs_dat_o_next[7] = 1'b0; + wbs_dat_o_next[8] = cmd_fifo_empty; + wbs_dat_o_next[9] = cmd_fifo_full; + wbs_dat_o_next[10] = cmd_fifo_overflow_reg; + wbs_dat_o_next[11] = write_fifo_empty; + wbs_dat_o_next[12] = write_fifo_full; + wbs_dat_o_next[13] = write_fifo_overflow_reg; + wbs_dat_o_next[14] = read_fifo_empty; + wbs_dat_o_next[15] = read_fifo_full; + end + 3'h2: begin + // command + wbs_dat_o_next[6:0] = cmd_address_reg; + wbs_dat_o_next[7] = 1'b0; + wbs_dat_o_next[8] = cmd_start_reg; + wbs_dat_o_next[9] = cmd_read_reg; + wbs_dat_o_next[10] = cmd_write_reg; + wbs_dat_o_next[11] = cmd_write_multiple_reg; + wbs_dat_o_next[12] = cmd_stop_reg; + wbs_dat_o_next[13] = 1'b0; + wbs_dat_o_next[14] = 1'b0; + wbs_dat_o_next[15] = 1'b0; + end + 3'h4: begin + // data + wbs_dat_o_next[7:0] = data_out; + wbs_dat_o_next[8] = data_out_valid; + wbs_dat_o_next[9] = data_out_last; + wbs_dat_o_next[15:10] = 6'd0; + + if (wbs_sel_i[0]) begin + data_out_ready_next = !wbs_ack_o_reg && data_out_valid; + end + end + 3'h6: begin + // prescale + wbs_dat_o_next = prescale_reg; + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end end -end + end -always @(posedge clk) begin + always @(posedge clk) begin wbs_dat_o_reg <= wbs_dat_o_next; wbs_ack_o_reg <= wbs_ack_o_next; @@ -615,59 +624,58 @@ always @(posedge clk) begin write_fifo_overflow_reg <= write_fifo_overflow_next; if (rst) begin - wbs_ack_o_reg <= 1'b0; - cmd_valid_reg <= 1'b0; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - prescale_reg <= DEFAULT_PRESCALE; - missed_ack_reg <= 1'b0; - cmd_fifo_overflow_reg <= 0; - write_fifo_overflow_reg <= 0; + wbs_ack_o_reg <= 1'b0; + cmd_valid_reg <= 1'b0; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + prescale_reg <= DEFAULT_PRESCALE; + missed_ack_reg <= 1'b0; + cmd_fifo_overflow_reg <= 0; + write_fifo_overflow_reg <= 0; end -end - -i2c_master -i2c_master_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .s_axis_cmd_address(cmd_address_int), - .s_axis_cmd_start(cmd_start_int), - .s_axis_cmd_read(cmd_read_int), - .s_axis_cmd_write(cmd_write_int), - .s_axis_cmd_write_multiple(cmd_write_multiple_int), - .s_axis_cmd_stop(cmd_stop_int), - .s_axis_cmd_valid(cmd_valid_int), - .s_axis_cmd_ready(cmd_ready_int), - - .s_axis_data_tdata(data_in_int), - .s_axis_data_tvalid(data_in_valid_int), - .s_axis_data_tready(data_in_ready_int), - .s_axis_data_tlast(data_in_last_int), - - .m_axis_data_tdata(data_out_int), - .m_axis_data_tvalid(data_out_valid_int), - .m_axis_data_tready(data_out_ready_int), - .m_axis_data_tlast(data_out_last_int), - - // I2C interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(busy_int), - .bus_control(bus_control_int), - .bus_active(bus_active_int), - .missed_ack(missed_ack_int), - - // Configuration - .prescale(prescale_reg), - .stop_on_idle(1'b0) -); + end + + i2c_master i2c_master_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .s_axis_cmd_address(cmd_address_int), + .s_axis_cmd_start(cmd_start_int), + .s_axis_cmd_read(cmd_read_int), + .s_axis_cmd_write(cmd_write_int), + .s_axis_cmd_write_multiple(cmd_write_multiple_int), + .s_axis_cmd_stop(cmd_stop_int), + .s_axis_cmd_valid(cmd_valid_int), + .s_axis_cmd_ready(cmd_ready_int), + + .s_axis_data_tdata (data_in_int), + .s_axis_data_tvalid(data_in_valid_int), + .s_axis_data_tready(data_in_ready_int), + .s_axis_data_tlast (data_in_last_int), + + .m_axis_data_tdata (data_out_int), + .m_axis_data_tvalid(data_out_valid_int), + .m_axis_data_tready(data_out_ready_int), + .m_axis_data_tlast (data_out_last_int), + + // I2C interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(busy_int), + .bus_control(bus_control_int), + .bus_active(bus_active_int), + .missed_ack(missed_ack_int), + + // Configuration + .prescale(prescale_reg), + .stop_on_idle(1'b0) + ); endmodule diff --git a/rtl/i2c_master_wbs_8.v b/rtl/i2c_master_wbs_8.v index 0db2fb0..72264a8 100644 --- a/rtl/i2c_master_wbs_8.v +++ b/rtl/i2c_master_wbs_8.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * I2C master wishbone slave wrapper (8 bit) */ -module i2c_master_wbs_8 # -( +module i2c_master_wbs_8 #( parameter DEFAULT_PRESCALE = 1, parameter FIXED_PRESCALE = 0, parameter CMD_FIFO = 1, @@ -39,33 +38,32 @@ module i2c_master_wbs_8 # parameter WRITE_FIFO_DEPTH = 32, parameter READ_FIFO = 1, parameter READ_FIFO_DEPTH = 32 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * Host interface */ - input wire [2:0] wbs_adr_i, // ADR_I() address - input wire [7:0] wbs_dat_i, // DAT_I() data in - output wire [7:0] wbs_dat_o, // DAT_O() data out - input wire wbs_we_i, // WE_I write enable input - input wire wbs_stb_i, // STB_I strobe input - output wire wbs_ack_o, // ACK_O acknowledge output - input wire wbs_cyc_i, // CYC_I cycle input + input wire [2:0] wbs_adr_i, // ADR_I() address + input wire [7:0] wbs_dat_i, // DAT_I() data in + output wire [7:0] wbs_dat_o, // DAT_O() data out + input wire wbs_we_i, // WE_I write enable input + input wire wbs_stb_i, // STB_I strobe input + output wire wbs_ack_o, // ACK_O acknowledge output + input wire wbs_cyc_i, // CYC_I cycle input /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t ); -/* + /* I2C @@ -239,199 +237,210 @@ I/O pin. This would prevent devices from stretching the clock period. */ -reg [7:0] wbs_dat_o_reg = 8'd0, wbs_dat_o_next; -reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; - -reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; -reg cmd_start_reg = 1'b0, cmd_start_next; -reg cmd_read_reg = 1'b0, cmd_read_next; -reg cmd_write_reg = 1'b0, cmd_write_next; -reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; -reg cmd_stop_reg = 1'b0, cmd_stop_next; -reg cmd_valid_reg = 1'b0, cmd_valid_next; -wire cmd_ready; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; -reg data_in_last_reg = 1'b0, data_in_last_next; - -wire [7:0] data_out; -wire data_out_valid; -reg data_out_ready_reg = 1'b0, data_out_ready_next; -wire data_out_last; - -reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; - -reg missed_ack_reg = 1'b0, missed_ack_next; - -assign wbs_dat_o = wbs_dat_o_reg; -assign wbs_ack_o = wbs_ack_o_reg; - -wire [6:0] cmd_address_int; -wire cmd_start_int; -wire cmd_read_int; -wire cmd_write_int; -wire cmd_write_multiple_int; -wire cmd_stop_int; -wire cmd_valid_int; -wire cmd_ready_int; - -wire [7:0] data_in_int; -wire data_in_valid_int; -wire data_in_ready_int; -wire data_in_last_int; - -wire [7:0] data_out_int; -wire data_out_valid_int; -wire data_out_ready_int; -wire data_out_last_int; - -wire busy_int; -wire bus_control_int; -wire bus_active_int; -wire missed_ack_int; - -wire cmd_fifo_empty = ~cmd_valid_int; -wire cmd_fifo_full = ~cmd_ready; -wire write_fifo_empty = ~data_in_valid_int; -wire write_fifo_full = ~data_in_ready; -wire read_fifo_empty = ~data_out_valid; -wire read_fifo_full = ~data_out_ready_int; - -reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; -reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; - - -generate - -if (CMD_FIFO) begin - axis_fifo #( - .DEPTH(CMD_FIFO_DEPTH), - .DATA_WIDTH(7+5), - .KEEP_ENABLE(0), - .LAST_ENABLE(0), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - cmd_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata({cmd_address_reg, cmd_start_reg, cmd_read_reg, cmd_write_reg, cmd_write_multiple_reg, cmd_stop_reg}), - .s_axis_tkeep(0), - .s_axis_tvalid(cmd_valid_reg), - .s_axis_tready(cmd_ready), - .s_axis_tlast(1'b0), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata({cmd_address_int, cmd_start_int, cmd_read_int, cmd_write_int, cmd_write_multiple_int, cmd_stop_int}), - .m_axis_tkeep(), - .m_axis_tvalid(cmd_valid_int), - .m_axis_tready(cmd_ready_int), - .m_axis_tlast(), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign cmd_address_int = cmd_address_reg; - assign cmd_start_int = cmd_start_reg; - assign cmd_read_int = cmd_read_reg; - assign cmd_write_int = cmd_write_reg; - assign cmd_write_multiple_int = cmd_write_multiple_reg; - assign cmd_stop_int = cmd_stop_reg; - assign cmd_valid_int = cmd_valid_reg; - assign cmd_ready = cmd_ready_int; -end - -if (WRITE_FIFO) begin - axis_fifo #( - .DEPTH(WRITE_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - write_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_in_reg), - .s_axis_tkeep(0), - .s_axis_tvalid(data_in_valid_reg), - .s_axis_tready(data_in_ready), - .s_axis_tlast(data_in_last_reg), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata(data_in_int), - .m_axis_tkeep(), - .m_axis_tvalid(data_in_valid_int), - .m_axis_tready(data_in_ready_int), - .m_axis_tlast(data_in_last_int), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_in_int = data_in_reg; - assign data_in_valid = data_in_valid_reg; - assign data_in_ready = data_in_ready_int; - assign data_in_last = data_in_last_reg; -end - -if (READ_FIFO) begin - axis_fifo #( - .DEPTH(READ_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - read_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_out_int), - .s_axis_tkeep(0), - .s_axis_tvalid(data_out_valid_int), - .s_axis_tready(data_out_ready_int), - .s_axis_tlast(data_out_last_int), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(0), - // AXI output - .m_axis_tdata(data_out), - .m_axis_tkeep(), - .m_axis_tvalid(data_out_valid), - .m_axis_tready(data_out_ready_reg), - .m_axis_tlast(data_out_last), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_out = data_out_int; - assign data_out_valid = data_out_valid_int; - assign data_out_ready_int = data_out_ready_reg; - assign data_out_last = data_out_last_int; -end - -endgenerate - -always @* begin + reg [7:0] wbs_dat_o_reg = 8'd0, wbs_dat_o_next; + reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; + + reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; + reg cmd_start_reg = 1'b0, cmd_start_next; + reg cmd_read_reg = 1'b0, cmd_read_next; + reg cmd_write_reg = 1'b0, cmd_write_next; + reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; + reg cmd_stop_reg = 1'b0, cmd_stop_next; + reg cmd_valid_reg = 1'b0, cmd_valid_next; + wire cmd_ready; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + reg data_in_last_reg = 1'b0, data_in_last_next; + + wire [7:0] data_out; + wire data_out_valid; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire data_out_last; + + reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; + + reg missed_ack_reg = 1'b0, missed_ack_next; + + assign wbs_dat_o = wbs_dat_o_reg; + assign wbs_ack_o = wbs_ack_o_reg; + + wire [6:0] cmd_address_int; + wire cmd_start_int; + wire cmd_read_int; + wire cmd_write_int; + wire cmd_write_multiple_int; + wire cmd_stop_int; + wire cmd_valid_int; + wire cmd_ready_int; + + wire [7:0] data_in_int; + wire data_in_valid_int; + wire data_in_ready_int; + wire data_in_last_int; + + wire [7:0] data_out_int; + wire data_out_valid_int; + wire data_out_ready_int; + wire data_out_last_int; + + wire busy_int; + wire bus_control_int; + wire bus_active_int; + wire missed_ack_int; + + wire cmd_fifo_empty = ~cmd_valid_int; + wire cmd_fifo_full = ~cmd_ready; + wire write_fifo_empty = ~data_in_valid_int; + wire write_fifo_full = ~data_in_ready; + wire read_fifo_empty = ~data_out_valid; + wire read_fifo_full = ~data_out_ready_int; + + reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; + reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; + + + generate + + if (CMD_FIFO) begin + axis_fifo #( + .DEPTH(CMD_FIFO_DEPTH), + .DATA_WIDTH(7 + 5), + .KEEP_ENABLE(0), + .LAST_ENABLE(0), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) cmd_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata({ + cmd_address_reg, + cmd_start_reg, + cmd_read_reg, + cmd_write_reg, + cmd_write_multiple_reg, + cmd_stop_reg + }), + .s_axis_tkeep(0), + .s_axis_tvalid(cmd_valid_reg), + .s_axis_tready(cmd_ready), + .s_axis_tlast(1'b0), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata({ + cmd_address_int, + cmd_start_int, + cmd_read_int, + cmd_write_int, + cmd_write_multiple_int, + cmd_stop_int + }), + .m_axis_tkeep(), + .m_axis_tvalid(cmd_valid_int), + .m_axis_tready(cmd_ready_int), + .m_axis_tlast(), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign cmd_address_int = cmd_address_reg; + assign cmd_start_int = cmd_start_reg; + assign cmd_read_int = cmd_read_reg; + assign cmd_write_int = cmd_write_reg; + assign cmd_write_multiple_int = cmd_write_multiple_reg; + assign cmd_stop_int = cmd_stop_reg; + assign cmd_valid_int = cmd_valid_reg; + assign cmd_ready = cmd_ready_int; + end + + if (WRITE_FIFO) begin + axis_fifo #( + .DEPTH(WRITE_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) write_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_in_reg), + .s_axis_tkeep(0), + .s_axis_tvalid(data_in_valid_reg), + .s_axis_tready(data_in_ready), + .s_axis_tlast(data_in_last_reg), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata(data_in_int), + .m_axis_tkeep(), + .m_axis_tvalid(data_in_valid_int), + .m_axis_tready(data_in_ready_int), + .m_axis_tlast(data_in_last_int), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_in_int = data_in_reg; + assign data_in_valid = data_in_valid_reg; + assign data_in_ready = data_in_ready_int; + assign data_in_last = data_in_last_reg; + end + + if (READ_FIFO) begin + axis_fifo #( + .DEPTH(READ_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) read_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_out_int), + .s_axis_tkeep(0), + .s_axis_tvalid(data_out_valid_int), + .s_axis_tready(data_out_ready_int), + .s_axis_tlast(data_out_last_int), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(0), + // AXI output + .m_axis_tdata(data_out), + .m_axis_tkeep(), + .m_axis_tvalid(data_out_valid), + .m_axis_tready(data_out_ready_reg), + .m_axis_tlast(data_out_last), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_out = data_out_int; + assign data_out_valid = data_out_valid_int; + assign data_out_ready_int = data_out_ready_reg; + assign data_out_last = data_out_last_int; + end + + endgenerate + + always @* begin wbs_dat_o_next = 8'd0; wbs_ack_o_next = 1'b0; @@ -455,130 +464,130 @@ always @* begin cmd_fifo_overflow_next = cmd_fifo_overflow_reg; write_fifo_overflow_next = write_fifo_overflow_reg; - + if (wbs_cyc_i & wbs_stb_i) begin - // bus cycle - if (wbs_we_i) begin - // write cycle - case (wbs_adr_i) - 4'h0: begin - // status - if (wbs_dat_i[3]) begin - missed_ack_next = missed_ack_int; - end - end - 4'h1: begin - // FIFO status - if (wbs_dat_i[2]) begin - cmd_fifo_overflow_next = 1'b0; - end - if (wbs_dat_i[5]) begin - write_fifo_overflow_next = 1'b0; - end - end - 4'h2: begin - // command address - cmd_address_next = wbs_dat_i; - end - 4'h3: begin - // command - cmd_start_next = wbs_dat_i[0]; - cmd_read_next = wbs_dat_i[1]; - cmd_write_next = wbs_dat_i[2]; - //cmd_write_multiple_next = wbs_dat_i[3]; - cmd_stop_next = wbs_dat_i[4]; - cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_stop_next); - - cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); - end - 4'h4: begin - // data - data_in_next = wbs_dat_i; - data_in_valid_next = ~wbs_ack_o_reg; - - write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; - end - 4'h5: begin - // reserved - end - 4'h6: begin - // prescale low - if (!FIXED_PRESCALE) begin - prescale_next[7:0] = wbs_dat_i; - end - end - 4'h7: begin - // prescale high - if (!FIXED_PRESCALE) begin - prescale_next[15:8] = wbs_dat_i; - end - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end else begin - // read cycle - case (wbs_adr_i) - 4'h0: begin - // status - wbs_dat_o_next[0] = busy_int; - wbs_dat_o_next[1] = bus_control_int; - wbs_dat_o_next[2] = bus_active_int; - wbs_dat_o_next[3] = missed_ack_reg; - wbs_dat_o_next[4] = 1'b0; - wbs_dat_o_next[5] = 1'b0; - wbs_dat_o_next[6] = 1'b0; - wbs_dat_o_next[7] = 1'b0; - end - 4'h1: begin - // FIFO status - wbs_dat_o_next[0] = cmd_fifo_empty; - wbs_dat_o_next[1] = cmd_fifo_full; - wbs_dat_o_next[2] = cmd_fifo_overflow_reg; - wbs_dat_o_next[3] = write_fifo_empty; - wbs_dat_o_next[4] = write_fifo_full; - wbs_dat_o_next[5] = write_fifo_overflow_reg; - wbs_dat_o_next[6] = read_fifo_empty; - wbs_dat_o_next[7] = read_fifo_full; - end - 4'h2: begin - // command address - wbs_dat_o_next = cmd_address_reg; - end - 4'h3: begin - // command - wbs_dat_o_next[0] = cmd_start_reg; - wbs_dat_o_next[1] = cmd_read_reg; - wbs_dat_o_next[2] = cmd_write_reg; - wbs_dat_o_next[3] = cmd_write_multiple_reg; - wbs_dat_o_next[4] = cmd_stop_reg; - wbs_dat_o_next[5] = 1'b0; - wbs_dat_o_next[6] = 1'b0; - wbs_dat_o_next[7] = 1'b0; - end - 4'h4: begin - // data - wbs_dat_o_next = data_out; - data_out_ready_next = !wbs_ack_o_reg && data_out_valid; - end - 4'h5: begin - // reserved - wbs_dat_o_next = 8'd0; - end - 4'h6: begin - // prescale low - wbs_dat_o_next = prescale_reg[7:0]; - end - 4'h7: begin - // prescale high - wbs_dat_o_next = prescale_reg[15:8]; - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end + // bus cycle + if (wbs_we_i) begin + // write cycle + case (wbs_adr_i) + 4'h0: begin + // status + if (wbs_dat_i[3]) begin + missed_ack_next = missed_ack_int; + end + end + 4'h1: begin + // FIFO status + if (wbs_dat_i[2]) begin + cmd_fifo_overflow_next = 1'b0; + end + if (wbs_dat_i[5]) begin + write_fifo_overflow_next = 1'b0; + end + end + 4'h2: begin + // command address + cmd_address_next = wbs_dat_i; + end + 4'h3: begin + // command + cmd_start_next = wbs_dat_i[0]; + cmd_read_next = wbs_dat_i[1]; + cmd_write_next = wbs_dat_i[2]; + //cmd_write_multiple_next = wbs_dat_i[3]; + cmd_stop_next = wbs_dat_i[4]; + cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_stop_next); + + cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); + end + 4'h4: begin + // data + data_in_next = wbs_dat_i; + data_in_valid_next = ~wbs_ack_o_reg; + + write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; + end + 4'h5: begin + // reserved + end + 4'h6: begin + // prescale low + if (!FIXED_PRESCALE) begin + prescale_next[7:0] = wbs_dat_i; + end + end + 4'h7: begin + // prescale high + if (!FIXED_PRESCALE) begin + prescale_next[15:8] = wbs_dat_i; + end + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end else begin + // read cycle + case (wbs_adr_i) + 4'h0: begin + // status + wbs_dat_o_next[0] = busy_int; + wbs_dat_o_next[1] = bus_control_int; + wbs_dat_o_next[2] = bus_active_int; + wbs_dat_o_next[3] = missed_ack_reg; + wbs_dat_o_next[4] = 1'b0; + wbs_dat_o_next[5] = 1'b0; + wbs_dat_o_next[6] = 1'b0; + wbs_dat_o_next[7] = 1'b0; + end + 4'h1: begin + // FIFO status + wbs_dat_o_next[0] = cmd_fifo_empty; + wbs_dat_o_next[1] = cmd_fifo_full; + wbs_dat_o_next[2] = cmd_fifo_overflow_reg; + wbs_dat_o_next[3] = write_fifo_empty; + wbs_dat_o_next[4] = write_fifo_full; + wbs_dat_o_next[5] = write_fifo_overflow_reg; + wbs_dat_o_next[6] = read_fifo_empty; + wbs_dat_o_next[7] = read_fifo_full; + end + 4'h2: begin + // command address + wbs_dat_o_next = cmd_address_reg; + end + 4'h3: begin + // command + wbs_dat_o_next[0] = cmd_start_reg; + wbs_dat_o_next[1] = cmd_read_reg; + wbs_dat_o_next[2] = cmd_write_reg; + wbs_dat_o_next[3] = cmd_write_multiple_reg; + wbs_dat_o_next[4] = cmd_stop_reg; + wbs_dat_o_next[5] = 1'b0; + wbs_dat_o_next[6] = 1'b0; + wbs_dat_o_next[7] = 1'b0; + end + 4'h4: begin + // data + wbs_dat_o_next = data_out; + data_out_ready_next = !wbs_ack_o_reg && data_out_valid; + end + 4'h5: begin + // reserved + wbs_dat_o_next = 8'd0; + end + 4'h6: begin + // prescale low + wbs_dat_o_next = prescale_reg[7:0]; + end + 4'h7: begin + // prescale high + wbs_dat_o_next = prescale_reg[15:8]; + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end end -end + end -always @(posedge clk) begin + always @(posedge clk) begin wbs_dat_o_reg <= wbs_dat_o_next; wbs_ack_o_reg <= wbs_ack_o_next; @@ -604,59 +613,58 @@ always @(posedge clk) begin write_fifo_overflow_reg <= write_fifo_overflow_next; if (rst) begin - wbs_ack_o_reg <= 1'b0; - cmd_valid_reg <= 1'b0; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - prescale_reg <= DEFAULT_PRESCALE; - missed_ack_reg <= 1'b0; - cmd_fifo_overflow_reg <= 0; - write_fifo_overflow_reg <= 0; + wbs_ack_o_reg <= 1'b0; + cmd_valid_reg <= 1'b0; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + prescale_reg <= DEFAULT_PRESCALE; + missed_ack_reg <= 1'b0; + cmd_fifo_overflow_reg <= 0; + write_fifo_overflow_reg <= 0; end -end - -i2c_master -i2c_master_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .s_axis_cmd_address(cmd_address_int), - .s_axis_cmd_start(cmd_start_int), - .s_axis_cmd_read(cmd_read_int), - .s_axis_cmd_write(cmd_write_int), - .s_axis_cmd_write_multiple(cmd_write_multiple_int), - .s_axis_cmd_stop(cmd_stop_int), - .s_axis_cmd_valid(cmd_valid_int), - .s_axis_cmd_ready(cmd_ready_int), - - .s_axis_data_tdata(data_in_int), - .s_axis_data_tvalid(data_in_valid_int), - .s_axis_data_tready(data_in_ready_int), - .s_axis_data_tlast(data_in_last_int), - - .m_axis_data_tdata(data_out_int), - .m_axis_data_tvalid(data_out_valid_int), - .m_axis_data_tready(data_out_ready_int), - .m_axis_data_tlast(data_out_last_int), - - // I2C interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(busy_int), - .bus_control(bus_control_int), - .bus_active(bus_active_int), - .missed_ack(missed_ack_int), - - // Configuration - .prescale(prescale_reg), - .stop_on_idle(1'b0) -); + end + + i2c_master i2c_master_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .s_axis_cmd_address(cmd_address_int), + .s_axis_cmd_start(cmd_start_int), + .s_axis_cmd_read(cmd_read_int), + .s_axis_cmd_write(cmd_write_int), + .s_axis_cmd_write_multiple(cmd_write_multiple_int), + .s_axis_cmd_stop(cmd_stop_int), + .s_axis_cmd_valid(cmd_valid_int), + .s_axis_cmd_ready(cmd_ready_int), + + .s_axis_data_tdata (data_in_int), + .s_axis_data_tvalid(data_in_valid_int), + .s_axis_data_tready(data_in_ready_int), + .s_axis_data_tlast (data_in_last_int), + + .m_axis_data_tdata (data_out_int), + .m_axis_data_tvalid(data_out_valid_int), + .m_axis_data_tready(data_out_ready_int), + .m_axis_data_tlast (data_out_last_int), + + // I2C interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(busy_int), + .bus_control(bus_control_int), + .bus_active(bus_active_int), + .missed_ack(missed_ack_int), + + // Configuration + .prescale(prescale_reg), + .stop_on_idle(1'b0) + ); endmodule diff --git a/rtl/i2c_phy_tb.sv b/rtl/i2c_phy_tb.sv index dfa4c1b..463e063 100644 --- a/rtl/i2c_phy_tb.sv +++ b/rtl/i2c_phy_tb.sv @@ -18,8 +18,8 @@ module i2c_phy_tb; wire scl_o; reg sda_i = 1; wire sda_o; - reg sda2=1;//dummy registers - reg scl2=1; + reg sda2 = 1; //dummy registers + reg scl2 = 1; wire sda_t; wire scl_t; wire phy_busy; @@ -30,13 +30,13 @@ module i2c_phy_tb; // Clock generation always #(CLK_PERIOD / 2) clk <= ~clk; - // Tri-state buffer modeling + // Tri-state buffer modeling wire scl_wire; wire sda_wire; reg scl_i_reg_tb, sda_i_reg_tb; // Model pull-up resistors with weak pull-ups - pullup(scl_wire); + pullup (scl_wire); pullup (sda_wire); // Model open-drain outputs @@ -45,16 +45,16 @@ module i2c_phy_tb; // Sample the bus with non-blocking assignments to avoid race conditions always @(posedge clk or posedge rst) begin - if (rst) begin - scl_i_reg_tb <= 1'b1; - sda_i_reg_tb <= 1'b1; - end else begin - scl_i_reg_tb <= scl_wire; - sda_i_reg_tb <= sda_wire; - - // Assert that sda_i_reg is not X - if(sda_i_reg_tb === 1'bx) $fatal(1,"sda_i_reg is X at time %t", $time); - end + if (rst) begin + scl_i_reg_tb <= 1'b1; + sda_i_reg_tb <= 1'b1; + end else begin + scl_i_reg_tb <= scl_wire; + sda_i_reg_tb <= sda_wire; + + // Assert that sda_i_reg is not X + if (sda_i_reg_tb === 1'bx) $fatal(1, "sda_i_reg is X at time %t", $time); + end end @@ -81,7 +81,7 @@ module i2c_phy_tb; .phy_state_reg(phy_state_reg), .prescale(17'd3) ); -task initialize; + task initialize; begin rst = 1; phy_start_bit = 0; @@ -105,7 +105,7 @@ task initialize; begin wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE phy_write_bit = 1; - phy_tx_data = tx_data; + phy_tx_data = tx_data; #(CLK_PERIOD * 2); end endtask @@ -113,7 +113,7 @@ task initialize; begin wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE phy_write_bit = 0; - phy_read_bit = 1; + phy_read_bit = 1; #(CLK_PERIOD * 2); end endtask @@ -144,12 +144,11 @@ task initialize; // Read ACK //Send ACK - sda2=0; + sda2 = 0; read_operation; wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE - sda2=1;//pull sda2 back up - if (phy_rx_data_reg!=0) - $finish("Expecting ACK but found NACK: %d ", phy_rx_data_reg); + sda2 = 1; //pull sda2 back up + if (phy_rx_data_reg != 0) $finish("Expecting ACK but found NACK: %d ", phy_rx_data_reg); end endtask @@ -174,7 +173,7 @@ task initialize; read_operation; // Read byte - repeat(8) begin + repeat (8) begin read_operation; end diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index d467164..b25bb39 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -24,8 +24,8 @@ THE SOFTWARE. // Language: Verilog 2001 -`resetall -`timescale 1ns / 1ps +`resetall //comment hack verible not compatible with verilator +`timescale 1ns / 1ps //commen hack2 `default_nettype none /* diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index 8462a87..ef8266c 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -441,7 +441,7 @@ I/O pin. This would prevent devices from stretching the clock period. state_next = STATE_READ_3; end end - default:$display("default of slave triggered, do nothing"); + default: $display("default of slave triggered, do nothing"); endcase end end diff --git a/rtl/i2c_slave_axil_master.v b/rtl/i2c_slave_axil_master.v index 2668642..083a9e3 100644 --- a/rtl/i2c_slave_axil_master.v +++ b/rtl/i2c_slave_axil_master.v @@ -29,64 +29,62 @@ THE SOFTWARE. /* * I2C slave AXI lite master wrapper */ -module i2c_slave_axil_master # -( +module i2c_slave_axil_master #( parameter FILTER_LEN = 4, parameter DATA_WIDTH = 32, // width of data bus in bits parameter ADDR_WIDTH = 16, // width of address bus in bits - parameter STRB_WIDTH = (DATA_WIDTH/8) -) -( - input wire clk, - input wire rst, + parameter STRB_WIDTH = (DATA_WIDTH / 8) +) ( + input wire clk, + input wire rst, /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t, + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t, /* * AXI lite master interface */ - output wire [ADDR_WIDTH-1:0] m_axil_awaddr, - output wire [2:0] m_axil_awprot, - output wire m_axil_awvalid, - input wire m_axil_awready, - output wire [DATA_WIDTH-1:0] m_axil_wdata, - output wire [STRB_WIDTH-1:0] m_axil_wstrb, - output wire m_axil_wvalid, - input wire m_axil_wready, - input wire [1:0] m_axil_bresp, - input wire m_axil_bvalid, - output wire m_axil_bready, - output wire [ADDR_WIDTH-1:0] m_axil_araddr, - output wire [2:0] m_axil_arprot, - output wire m_axil_arvalid, - input wire m_axil_arready, - input wire [DATA_WIDTH-1:0] m_axil_rdata, - input wire [1:0] m_axil_rresp, - input wire m_axil_rvalid, - output wire m_axil_rready, + output wire [ADDR_WIDTH-1:0] m_axil_awaddr, + output wire [ 2:0] m_axil_awprot, + output wire m_axil_awvalid, + input wire m_axil_awready, + output wire [DATA_WIDTH-1:0] m_axil_wdata, + output wire [STRB_WIDTH-1:0] m_axil_wstrb, + output wire m_axil_wvalid, + input wire m_axil_wready, + input wire [ 1:0] m_axil_bresp, + input wire m_axil_bvalid, + output wire m_axil_bready, + output wire [ADDR_WIDTH-1:0] m_axil_araddr, + output wire [ 2:0] m_axil_arprot, + output wire m_axil_arvalid, + input wire m_axil_arready, + input wire [DATA_WIDTH-1:0] m_axil_rdata, + input wire [ 1:0] m_axil_rresp, + input wire m_axil_rvalid, + output wire m_axil_rready, /* * Status */ - output wire busy, - output wire bus_addressed, - output wire bus_active, + output wire busy, + output wire bus_addressed, + output wire bus_active, /* * Configuration */ - input wire enable, - input wire [6:0] device_address + input wire enable, + input wire [6:0] device_address ); -/* + /* I2C @@ -195,38 +193,38 @@ I/O pin. This would prevent devices from stretching the clock period. */ -// for interfaces that are more than one word wide, disable address lines -parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH); -// width of data port in words -parameter WORD_WIDTH = STRB_WIDTH; -// size of words -parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH; + // for interfaces that are more than one word wide, disable address lines + parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH); + // width of data port in words + parameter WORD_WIDTH = STRB_WIDTH; + // size of words + parameter WORD_SIZE = DATA_WIDTH / WORD_WIDTH; -parameter WORD_PART_ADDR_WIDTH = $clog2(WORD_SIZE/8); + parameter WORD_PART_ADDR_WIDTH = $clog2(WORD_SIZE / 8); -parameter ADDR_WIDTH_ADJ = ADDR_WIDTH+WORD_PART_ADDR_WIDTH; + parameter ADDR_WIDTH_ADJ = ADDR_WIDTH + WORD_PART_ADDR_WIDTH; -parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ+7)/8; + parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ + 7) / 8; -// bus width assertions -initial begin + // bus width assertions + initial begin if (WORD_WIDTH * WORD_SIZE != DATA_WIDTH) begin - $error("Error: AXI data width not evenly divisble"); - $finish; + $error("Error: AXI data width not evenly divisble"); + $finish; end - if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin - $error("Error: AXI word width must be even power of two"); - $finish; + if (2 ** $clog2(WORD_WIDTH) != WORD_WIDTH) begin + $error("Error: AXI word width must be even power of two"); + $finish; end - if (8*2**$clog2(WORD_SIZE/8) != WORD_SIZE) begin - $error("Error: AXI word size must be a power of two multiple of 8 bits"); - $finish; + if (8 * 2 ** $clog2(WORD_SIZE / 8) != WORD_SIZE) begin + $error("Error: AXI word size must be a power of two multiple of 8 bits"); + $finish; end -end + end -localparam [2:0] + localparam [2:0] STATE_IDLE = 3'd0, STATE_ADDRESS = 3'd1, STATE_READ_1 = 3'd2, @@ -234,47 +232,53 @@ localparam [2:0] STATE_WRITE_1 = 3'd4, STATE_WRITE_2 = 3'd5; -reg [2:0] state_reg = STATE_IDLE, state_next; - -reg [7:0] count_reg = 8'd0, count_next; -reg last_cycle_reg = 1'b0; - -reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; -reg [DATA_WIDTH-1:0] data_reg = {DATA_WIDTH{1'b0}}, data_next; - -reg m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next; -reg [STRB_WIDTH-1:0] m_axil_wstrb_reg = {STRB_WIDTH{1'b0}}, m_axil_wstrb_next; -reg m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next; -reg m_axil_bready_reg = 1'b0, m_axil_bready_next; -reg m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next; -reg m_axil_rready_reg = 1'b0, m_axil_rready_next; - -reg busy_reg = 1'b0; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; - -wire [7:0] data_out; -wire data_out_valid; -wire data_out_last; -reg data_out_ready_reg = 1'b0, data_out_ready_next; - -assign m_axil_awaddr = {addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], {ADDR_WIDTH-VALID_ADDR_WIDTH{1'b0}}}; -assign m_axil_awprot = 3'b010; -assign m_axil_awvalid = m_axil_awvalid_reg; -assign m_axil_wdata = data_reg; -assign m_axil_wstrb = m_axil_wstrb_reg; -assign m_axil_wvalid = m_axil_wvalid_reg; -assign m_axil_bready = m_axil_bready_reg; -assign m_axil_araddr = {addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], {ADDR_WIDTH-VALID_ADDR_WIDTH{1'b0}}}; -assign m_axil_arprot = 3'b010; -assign m_axil_arvalid = m_axil_arvalid_reg; -assign m_axil_rready = m_axil_rready_reg; - -assign busy = busy_reg; - -always @* begin + reg [2:0] state_reg = STATE_IDLE, state_next; + + reg [7:0] count_reg = 8'd0, count_next; + reg last_cycle_reg = 1'b0; + + reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; + reg [DATA_WIDTH-1:0] data_reg = {DATA_WIDTH{1'b0}}, data_next; + + reg m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next; + reg [STRB_WIDTH-1:0] m_axil_wstrb_reg = {STRB_WIDTH{1'b0}}, m_axil_wstrb_next; + reg m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next; + reg m_axil_bready_reg = 1'b0, m_axil_bready_next; + reg m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next; + reg m_axil_rready_reg = 1'b0, m_axil_rready_next; + + reg busy_reg = 1'b0; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + + wire [7:0] data_out; + wire data_out_valid; + wire data_out_last; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + + assign m_axil_awaddr = { + addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], + {ADDR_WIDTH - VALID_ADDR_WIDTH{1'b0}} + }; + assign m_axil_awprot = 3'b010; + assign m_axil_awvalid = m_axil_awvalid_reg; + assign m_axil_wdata = data_reg; + assign m_axil_wstrb = m_axil_wstrb_reg; + assign m_axil_wvalid = m_axil_wvalid_reg; + assign m_axil_bready = m_axil_bready_reg; + assign m_axil_araddr = { + addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], + {ADDR_WIDTH - VALID_ADDR_WIDTH{1'b0}} + }; + assign m_axil_arprot = 3'b010; + assign m_axil_arvalid = m_axil_arvalid_reg; + assign m_axil_rready = m_axil_rready_reg; + + assign busy = busy_reg; + + always @* begin state_next = STATE_IDLE; count_next = count_reg; @@ -295,145 +299,145 @@ always @* begin m_axil_rready_next = 1'b0; case (state_reg) - STATE_IDLE: begin - // idle, wait for I2C interface - - if (data_out_valid) begin - // store address and write - count_next = ADDR_WORD_WIDTH-1; - state_next = STATE_ADDRESS; - end else if (data_in_ready && !data_in_valid_reg) begin - // read - m_axil_arvalid_next = 1'b1; - m_axil_rready_next = 1'b1; - state_next = STATE_READ_1; - end + STATE_IDLE: begin + // idle, wait for I2C interface + + if (data_out_valid) begin + // store address and write + count_next = ADDR_WORD_WIDTH - 1; + state_next = STATE_ADDRESS; + end else if (data_in_ready && !data_in_valid_reg) begin + // read + m_axil_arvalid_next = 1'b1; + m_axil_rready_next = 1'b1; + state_next = STATE_READ_1; end - STATE_ADDRESS: begin - // store address - data_out_ready_next = 1'b1; - - if (data_out_ready_reg && data_out_valid) begin - // store pointers - addr_next[8*count_reg +: 8] = data_out; - count_next = count_reg - 1; - if (count_reg == 0) begin - // end of header - // set initial word offset - if (ADDR_WIDTH == VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin - count_next = 0; - end else begin - count_next = addr_next[ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH-1:0]; - end - m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; - data_next = {DATA_WIDTH{1'b0}}; - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - // start writing - state_next = STATE_WRITE_1; - end - end else begin - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_ADDRESS; - end - end + end + STATE_ADDRESS: begin + // store address + data_out_ready_next = 1'b1; + + if (data_out_ready_reg && data_out_valid) begin + // store pointers + addr_next[8*count_reg+:8] = data_out; + count_next = count_reg - 1; + if (count_reg == 0) begin + // end of header + // set initial word offset + if (ADDR_WIDTH == VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin + count_next = 0; end else begin - state_next = STATE_ADDRESS; + count_next = addr_next[ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH-1:0]; end - end - STATE_READ_1: begin - // wait for data - m_axil_rready_next = 1'b1; - - if (m_axil_rready && m_axil_rvalid) begin - // read cycle complete, store result - m_axil_rready_next = 1'b0; - data_next = m_axil_rdata; - addr_next = addr_reg + (1 << (ADDR_WIDTH-VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - state_next = STATE_READ_2; + m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; + data_next = {DATA_WIDTH{1'b0}}; + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_1; + // start writing + state_next = STATE_WRITE_1; end - end - STATE_READ_2: begin - // send data - if (data_out_valid || !bus_addressed) begin - // no longer addressed or now addressed for write, return to idle - state_next = STATE_IDLE; - end else if (data_in_ready && !data_in_valid_reg) begin - // transfer word and update pointers - data_in_next = data_reg[8*count_reg +: 8]; - data_in_valid_next = 1'b1; - count_next = count_reg + 1; - if (count_reg == (STRB_WIDTH*WORD_SIZE/8)-1) begin - // end of stored data word; return to idle - count_next = 0; - state_next = STATE_IDLE; - end else begin - state_next = STATE_READ_2; - end + end else begin + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_2; + state_next = STATE_ADDRESS; end + end + end else begin + state_next = STATE_ADDRESS; end - STATE_WRITE_1: begin - // write data - data_out_ready_next = 1'b1; - - if (data_out_ready_reg && data_out_valid) begin - // store word - data_next[8*count_reg +: 8] = data_out; - count_next = count_reg + 1; - m_axil_wstrb_next[count_reg >> ((WORD_SIZE/8)-1)] = 1'b1; - if (count_reg == (STRB_WIDTH*WORD_SIZE/8)-1 || data_out_last) begin - // have full word or at end of block, start write operation - count_next = 0; - m_axil_awvalid_next = 1'b1; - m_axil_wvalid_next = 1'b1; - m_axil_bready_next = 1'b1; - state_next = STATE_WRITE_2; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_1; - end + end + STATE_READ_1: begin + // wait for data + m_axil_rready_next = 1'b1; + + if (m_axil_rready && m_axil_rvalid) begin + // read cycle complete, store result + m_axil_rready_next = 1'b0; + data_next = m_axil_rdata; + addr_next = addr_reg + (1 << (ADDR_WIDTH - VALID_ADDR_WIDTH + WORD_PART_ADDR_WIDTH)); + state_next = STATE_READ_2; + end else begin + state_next = STATE_READ_1; + end + end + STATE_READ_2: begin + // send data + if (data_out_valid || !bus_addressed) begin + // no longer addressed or now addressed for write, return to idle + state_next = STATE_IDLE; + end else if (data_in_ready && !data_in_valid_reg) begin + // transfer word and update pointers + data_in_next = data_reg[8*count_reg+:8]; + data_in_valid_next = 1'b1; + count_next = count_reg + 1; + if (count_reg == (STRB_WIDTH * WORD_SIZE / 8) - 1) begin + // end of stored data word; return to idle + count_next = 0; + state_next = STATE_IDLE; + end else begin + state_next = STATE_READ_2; + end + end else begin + state_next = STATE_READ_2; end - STATE_WRITE_2: begin - // wait for write completion + end + STATE_WRITE_1: begin + // write data + data_out_ready_next = 1'b1; + + if (data_out_ready_reg && data_out_valid) begin + // store word + data_next[8*count_reg+:8] = data_out; + count_next = count_reg + 1; + m_axil_wstrb_next[count_reg>>((WORD_SIZE/8)-1)] = 1'b1; + if (count_reg == (STRB_WIDTH * WORD_SIZE / 8) - 1 || data_out_last) begin + // have full word or at end of block, start write operation + count_next = 0; + m_axil_awvalid_next = 1'b1; + m_axil_wvalid_next = 1'b1; m_axil_bready_next = 1'b1; - - if (m_axil_bready && m_axil_bvalid) begin - // end of write operation - data_next = {DATA_WIDTH{1'b0}}; - addr_next = addr_reg + (1 << (ADDR_WIDTH-VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - m_axil_bready_next = 1'b0; - m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; - if (last_cycle_reg) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_2; - end + state_next = STATE_WRITE_2; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_1; end + end + STATE_WRITE_2: begin + // wait for write completion + m_axil_bready_next = 1'b1; + + if (m_axil_bready && m_axil_bvalid) begin + // end of write operation + data_next = {DATA_WIDTH{1'b0}}; + addr_next = addr_reg + (1 << (ADDR_WIDTH - VALID_ADDR_WIDTH + WORD_PART_ADDR_WIDTH)); + m_axil_bready_next = 1'b0; + m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; + if (last_cycle_reg) begin + // end of transaction + state_next = STATE_IDLE; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_2; + end + end endcase -end + end -always @(posedge clk) begin + always @(posedge clk) begin state_reg <= state_next; count_reg <= count_next; if (data_out_ready_reg & data_out_valid) begin - last_cycle_reg <= data_out_last; + last_cycle_reg <= data_out_last; end addr_reg <= addr_next; @@ -454,56 +458,55 @@ always @(posedge clk) begin data_out_ready_reg <= data_out_ready_next; if (rst) begin - state_reg <= STATE_IDLE; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - m_axil_awvalid_reg <= 1'b0; - m_axil_wvalid_reg <= 1'b0; - m_axil_bready_reg <= 1'b0; - m_axil_arvalid_reg <= 1'b0; - m_axil_rready_reg <= 1'b0; - busy_reg <= 1'b0; + state_reg <= STATE_IDLE; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + m_axil_awvalid_reg <= 1'b0; + m_axil_wvalid_reg <= 1'b0; + m_axil_bready_reg <= 1'b0; + m_axil_arvalid_reg <= 1'b0; + m_axil_rready_reg <= 1'b0; + busy_reg <= 1'b0; end -end - -i2c_slave #( - .FILTER_LEN(FILTER_LEN) -) -i2c_slave_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .release_bus(1'b0), - - .s_axis_data_tdata(data_in_reg), - .s_axis_data_tvalid(data_in_valid_reg), - .s_axis_data_tready(data_in_ready), - .s_axis_data_tlast(1'b0), - - .m_axis_data_tdata(data_out), - .m_axis_data_tvalid(data_out_valid), - .m_axis_data_tready(data_out_ready_reg), - .m_axis_data_tlast(data_out_last), - - // I2C Interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(), - .bus_address(), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - - // Configuration - .enable(enable), - .device_address(device_address), - .device_address_mask(7'h7f) -); + end + + i2c_slave #( + .FILTER_LEN(FILTER_LEN) + ) i2c_slave_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .release_bus(1'b0), + + .s_axis_data_tdata (data_in_reg), + .s_axis_data_tvalid(data_in_valid_reg), + .s_axis_data_tready(data_in_ready), + .s_axis_data_tlast (1'b0), + + .m_axis_data_tdata (data_out), + .m_axis_data_tvalid(data_out_valid), + .m_axis_data_tready(data_out_ready_reg), + .m_axis_data_tlast (data_out_last), + + // I2C Interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(), + .bus_address(), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + + // Configuration + .enable(enable), + .device_address(device_address), + .device_address_mask(7'h7f) + ); endmodule diff --git a/rtl/i2c_slave_wbm.v b/rtl/i2c_slave_wbm.v index b586365..445054c 100644 --- a/rtl/i2c_slave_wbm.v +++ b/rtl/i2c_slave_wbm.v @@ -29,54 +29,52 @@ THE SOFTWARE. /* * I2C slave wishbone master wrapper */ -module i2c_slave_wbm # -( - parameter FILTER_LEN = 4, - parameter WB_DATA_WIDTH = 32, // width of data bus in bits (8, 16, 32, or 64) - parameter WB_ADDR_WIDTH = 32, // width of address bus in bits - parameter WB_SELECT_WIDTH = (WB_DATA_WIDTH/8) // width of word select bus (1, 2, 4, or 8) -) -( - input wire clk, - input wire rst, +module i2c_slave_wbm #( + parameter FILTER_LEN = 4, + parameter WB_DATA_WIDTH = 32, // width of data bus in bits (8, 16, 32, or 64) + parameter WB_ADDR_WIDTH = 32, // width of address bus in bits + parameter WB_SELECT_WIDTH = (WB_DATA_WIDTH / 8) // width of word select bus (1, 2, 4, or 8) +) ( + input wire clk, + input wire rst, /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t, + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t, /* * Wishbone interface */ - output wire [WB_ADDR_WIDTH-1:0] wb_adr_o, // ADR_O() address - input wire [WB_DATA_WIDTH-1:0] wb_dat_i, // DAT_I() data in - output wire [WB_DATA_WIDTH-1:0] wb_dat_o, // DAT_O() data out - output wire wb_we_o, // WE_O write enable output - output wire [WB_SELECT_WIDTH-1:0] wb_sel_o, // SEL_O() select output - output wire wb_stb_o, // STB_O strobe output - input wire wb_ack_i, // ACK_I acknowledge input - input wire wb_err_i, // ERR_I error input - output wire wb_cyc_o, // CYC_O cycle output + output wire [ WB_ADDR_WIDTH-1:0] wb_adr_o, // ADR_O() address + input wire [ WB_DATA_WIDTH-1:0] wb_dat_i, // DAT_I() data in + output wire [ WB_DATA_WIDTH-1:0] wb_dat_o, // DAT_O() data out + output wire wb_we_o, // WE_O write enable output + output wire [WB_SELECT_WIDTH-1:0] wb_sel_o, // SEL_O() select output + output wire wb_stb_o, // STB_O strobe output + input wire wb_ack_i, // ACK_I acknowledge input + input wire wb_err_i, // ERR_I error input + output wire wb_cyc_o, // CYC_O cycle output /* * Status */ - output wire busy, - output wire bus_addressed, - output wire bus_active, + output wire busy, + output wire bus_addressed, + output wire bus_active, /* * Configuration */ - input wire enable, - input wire [6:0] device_address + input wire enable, + input wire [6:0] device_address ); -/* + /* I2C @@ -185,38 +183,38 @@ I/O pin. This would prevent devices from stretching the clock period. */ -// for interfaces that are more than one word wide, disable address lines -parameter WB_VALID_ADDR_WIDTH = WB_ADDR_WIDTH - $clog2(WB_SELECT_WIDTH); -// width of data port in words (1, 2, 4, or 8) -parameter WB_WORD_WIDTH = WB_SELECT_WIDTH; -// size of words (8, 16, 32, or 64 bits) -parameter WB_WORD_SIZE = WB_DATA_WIDTH/WB_WORD_WIDTH; + // for interfaces that are more than one word wide, disable address lines + parameter WB_VALID_ADDR_WIDTH = WB_ADDR_WIDTH - $clog2(WB_SELECT_WIDTH); + // width of data port in words (1, 2, 4, or 8) + parameter WB_WORD_WIDTH = WB_SELECT_WIDTH; + // size of words (8, 16, 32, or 64 bits) + parameter WB_WORD_SIZE = WB_DATA_WIDTH / WB_WORD_WIDTH; -parameter WORD_PART_ADDR_WIDTH = $clog2(WB_WORD_SIZE/8); + parameter WORD_PART_ADDR_WIDTH = $clog2(WB_WORD_SIZE / 8); -parameter ADDR_WIDTH_ADJ = WB_ADDR_WIDTH+WORD_PART_ADDR_WIDTH; + parameter ADDR_WIDTH_ADJ = WB_ADDR_WIDTH + WORD_PART_ADDR_WIDTH; -parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ+7)/8; + parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ + 7) / 8; -// bus width assertions -initial begin + // bus width assertions + initial begin if (WB_WORD_WIDTH * WB_WORD_SIZE != WB_DATA_WIDTH) begin - $error("Error: WB data width not evenly divisble"); - $finish; + $error("Error: WB data width not evenly divisble"); + $finish; end - if (2**$clog2(WB_WORD_WIDTH) != WB_WORD_WIDTH) begin - $error("Error: WB word width must be even power of two"); - $finish; + if (2 ** $clog2(WB_WORD_WIDTH) != WB_WORD_WIDTH) begin + $error("Error: WB word width must be even power of two"); + $finish; end - if (8*2**$clog2(WB_WORD_SIZE/8) != WB_WORD_SIZE) begin - $error("Error: WB word size must be a power of two multiple of 8 bits"); - $finish; + if (8 * 2 ** $clog2(WB_WORD_SIZE / 8) != WB_WORD_SIZE) begin + $error("Error: WB word size must be a power of two multiple of 8 bits"); + $finish; end -end + end -localparam [2:0] + localparam [2:0] STATE_IDLE = 3'd0, STATE_ADDRESS = 3'd1, STATE_READ_1 = 3'd2, @@ -224,40 +222,43 @@ localparam [2:0] STATE_WRITE_1 = 3'd4, STATE_WRITE_2 = 3'd5; -reg [2:0] state_reg = STATE_IDLE, state_next; + reg [2:0] state_reg = STATE_IDLE, state_next; -reg [7:0] count_reg = 8'd0, count_next; -reg last_cycle_reg = 1'b0; + reg [7:0] count_reg = 8'd0, count_next; + reg last_cycle_reg = 1'b0; -reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; -reg [WB_DATA_WIDTH-1:0] data_reg = {WB_DATA_WIDTH{1'b0}}, data_next; + reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; + reg [WB_DATA_WIDTH-1:0] data_reg = {WB_DATA_WIDTH{1'b0}}, data_next; -reg wb_we_o_reg = 1'b0, wb_we_o_next; -reg [WB_SELECT_WIDTH-1:0] wb_sel_o_reg = {WB_SELECT_WIDTH{1'b0}}, wb_sel_o_next; -reg wb_stb_o_reg = 1'b0, wb_stb_o_next; -reg wb_cyc_o_reg = 1'b0, wb_cyc_o_next; + reg wb_we_o_reg = 1'b0, wb_we_o_next; + reg [WB_SELECT_WIDTH-1:0] wb_sel_o_reg = {WB_SELECT_WIDTH{1'b0}}, wb_sel_o_next; + reg wb_stb_o_reg = 1'b0, wb_stb_o_next; + reg wb_cyc_o_reg = 1'b0, wb_cyc_o_next; -reg busy_reg = 1'b0; + reg busy_reg = 1'b0; -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; -wire [7:0] data_out; -wire data_out_valid; -wire data_out_last; -reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire [7:0] data_out; + wire data_out_valid; + wire data_out_last; + reg data_out_ready_reg = 1'b0, data_out_ready_next; -assign wb_adr_o = {addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH], {WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH{1'b0}}}; -assign wb_dat_o = data_reg; -assign wb_we_o = wb_we_o_reg; -assign wb_sel_o = wb_sel_o_reg; -assign wb_stb_o = wb_stb_o_reg; -assign wb_cyc_o = wb_cyc_o_reg; + assign wb_adr_o = { + addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH], + {WB_ADDR_WIDTH - WB_VALID_ADDR_WIDTH{1'b0}} + }; + assign wb_dat_o = data_reg; + assign wb_we_o = wb_we_o_reg; + assign wb_sel_o = wb_sel_o_reg; + assign wb_stb_o = wb_stb_o_reg; + assign wb_cyc_o = wb_cyc_o_reg; -assign busy = busy_reg; + assign busy = busy_reg; -always @* begin + always @* begin state_next = STATE_IDLE; count_next = count_reg; @@ -276,152 +277,152 @@ always @* begin wb_cyc_o_next = 1'b0; case (state_reg) - STATE_IDLE: begin - // idle, wait for I2C interface - wb_we_o_next = 1'b0; - - if (data_out_valid) begin - // store address and write - count_next = ADDR_WORD_WIDTH-1; - state_next = STATE_ADDRESS; - end else if (data_in_ready & ~data_in_valid_reg) begin - // read - wb_cyc_o_next = 1'b1; - wb_stb_o_next = 1'b1; - wb_sel_o_next = {WB_SELECT_WIDTH{1'b1}}; - state_next = STATE_READ_1; - end + STATE_IDLE: begin + // idle, wait for I2C interface + wb_we_o_next = 1'b0; + + if (data_out_valid) begin + // store address and write + count_next = ADDR_WORD_WIDTH - 1; + state_next = STATE_ADDRESS; + end else if (data_in_ready & ~data_in_valid_reg) begin + // read + wb_cyc_o_next = 1'b1; + wb_stb_o_next = 1'b1; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b1}}; + state_next = STATE_READ_1; end - STATE_ADDRESS: begin - // store address - data_out_ready_next = 1'b1; - - if (data_out_ready_reg & data_out_valid) begin - // store pointers - addr_next[8*count_reg +: 8] = data_out; - count_next = count_reg - 1; - if (count_reg == 0) begin - // end of header - // set initial word offset - if (WB_ADDR_WIDTH == WB_VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin - count_next = 0; - end else begin - count_next = addr_next[ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH-1:0]; - end - wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; - data_next = {WB_DATA_WIDTH{1'b0}}; - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - // start writing - state_next = STATE_WRITE_1; - end - end else begin - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_ADDRESS; - end - end + end + STATE_ADDRESS: begin + // store address + data_out_ready_next = 1'b1; + + if (data_out_ready_reg & data_out_valid) begin + // store pointers + addr_next[8*count_reg+:8] = data_out; + count_next = count_reg - 1; + if (count_reg == 0) begin + // end of header + // set initial word offset + if (WB_ADDR_WIDTH == WB_VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin + count_next = 0; end else begin - state_next = STATE_ADDRESS; + count_next = addr_next[ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH-1:0]; end - end - STATE_READ_1: begin - // wait for ack - wb_cyc_o_next = 1'b1; - wb_stb_o_next = 1'b1; - - if (wb_ack_i || wb_err_i) begin - // read cycle complete, store result - data_next = wb_dat_i; - addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - wb_cyc_o_next = 1'b0; - wb_stb_o_next = 1'b0; - wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; - state_next = STATE_READ_2; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; + data_next = {WB_DATA_WIDTH{1'b0}}; + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_1; + // start writing + state_next = STATE_WRITE_1; end - end - STATE_READ_2: begin - // send data - if (data_out_valid | !bus_addressed) begin - // no longer addressed or now addressed for write, return to idle - state_next = STATE_IDLE; - end else if (data_in_ready & ~data_in_valid_reg) begin - // transfer word and update pointers - data_in_next = data_reg[8*count_reg +: 8]; - data_in_valid_next = 1'b1; - count_next = count_reg + 1; - if (count_reg == (WB_SELECT_WIDTH*WB_WORD_SIZE/8)-1) begin - // end of stored data word; return to idle - count_next = 0; - state_next = STATE_IDLE; - end else begin - state_next = STATE_READ_2; - end + end else begin + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_2; + state_next = STATE_ADDRESS; end + end + end else begin + state_next = STATE_ADDRESS; end - STATE_WRITE_1: begin - // write data - data_out_ready_next = 1'b1; - - if (data_out_ready_reg & data_out_valid) begin - // store word - data_next[8*count_reg +: 8] = data_out; - count_next = count_reg + 1; - wb_sel_o_next[count_reg >> ((WB_WORD_SIZE/8)-1)] = 1'b1; - if (count_reg == (WB_SELECT_WIDTH*WB_WORD_SIZE/8)-1 || data_out_last) begin - // have full word or at end of block, start write operation - count_next = 0; - wb_we_o_next = 1'b1; - wb_cyc_o_next = 1'b1; - wb_stb_o_next = 1'b1; - state_next = STATE_WRITE_2; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_1; - end + end + STATE_READ_1: begin + // wait for ack + wb_cyc_o_next = 1'b1; + wb_stb_o_next = 1'b1; + + if (wb_ack_i || wb_err_i) begin + // read cycle complete, store result + data_next = wb_dat_i; + addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); + wb_cyc_o_next = 1'b0; + wb_stb_o_next = 1'b0; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; + state_next = STATE_READ_2; + end else begin + state_next = STATE_READ_1; + end + end + STATE_READ_2: begin + // send data + if (data_out_valid | !bus_addressed) begin + // no longer addressed or now addressed for write, return to idle + state_next = STATE_IDLE; + end else if (data_in_ready & ~data_in_valid_reg) begin + // transfer word and update pointers + data_in_next = data_reg[8*count_reg+:8]; + data_in_valid_next = 1'b1; + count_next = count_reg + 1; + if (count_reg == (WB_SELECT_WIDTH * WB_WORD_SIZE / 8) - 1) begin + // end of stored data word; return to idle + count_next = 0; + state_next = STATE_IDLE; + end else begin + state_next = STATE_READ_2; + end + end else begin + state_next = STATE_READ_2; end - STATE_WRITE_2: begin - // wait for ack + end + STATE_WRITE_1: begin + // write data + data_out_ready_next = 1'b1; + + if (data_out_ready_reg & data_out_valid) begin + // store word + data_next[8*count_reg+:8] = data_out; + count_next = count_reg + 1; + wb_sel_o_next[count_reg>>((WB_WORD_SIZE/8)-1)] = 1'b1; + if (count_reg == (WB_SELECT_WIDTH * WB_WORD_SIZE / 8) - 1 || data_out_last) begin + // have full word or at end of block, start write operation + count_next = 0; + wb_we_o_next = 1'b1; wb_cyc_o_next = 1'b1; wb_stb_o_next = 1'b1; - - if (wb_ack_i || wb_err_i) begin - // end of write operation - data_next = {WB_DATA_WIDTH{1'b0}}; - addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - wb_cyc_o_next = 1'b0; - wb_stb_o_next = 1'b0; - wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; - if (last_cycle_reg) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_2; - end + state_next = STATE_WRITE_2; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_1; + end + end + STATE_WRITE_2: begin + // wait for ack + wb_cyc_o_next = 1'b1; + wb_stb_o_next = 1'b1; + + if (wb_ack_i || wb_err_i) begin + // end of write operation + data_next = {WB_DATA_WIDTH{1'b0}}; + addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); + wb_cyc_o_next = 1'b0; + wb_stb_o_next = 1'b0; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; + if (last_cycle_reg) begin + // end of transaction + state_next = STATE_IDLE; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_2; end + end endcase -end + end -always @(posedge clk) begin + always @(posedge clk) begin state_reg <= state_next; count_reg <= count_next; if (data_out_ready_reg & data_out_valid) begin - last_cycle_reg <= data_out_last; + last_cycle_reg <= data_out_last; end addr_reg <= addr_next; @@ -440,53 +441,52 @@ always @(posedge clk) begin data_out_ready_reg <= data_out_ready_next; if (rst) begin - state_reg <= STATE_IDLE; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - wb_stb_o_reg <= 1'b0; - wb_cyc_o_reg <= 1'b0; - busy_reg <= 1'b0; + state_reg <= STATE_IDLE; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + wb_stb_o_reg <= 1'b0; + wb_cyc_o_reg <= 1'b0; + busy_reg <= 1'b0; end -end - -i2c_slave #( - .FILTER_LEN(FILTER_LEN) -) -i2c_slave_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .release_bus(1'b0), - - .s_axis_data_tdata(data_in_reg), - .s_axis_data_tvalid(data_in_valid_reg), - .s_axis_data_tready(data_in_ready), - .s_axis_data_tlast(1'b0), - - .m_axis_data_tdata(data_out), - .m_axis_data_tvalid(data_out_valid), - .m_axis_data_tready(data_out_ready_reg), - .m_axis_data_tlast(data_out_last), - - // I2C Interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(), - .bus_address(), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - - // Configuration - .enable(enable), - .device_address(device_address), - .device_address_mask(7'h7f) -); + end + + i2c_slave #( + .FILTER_LEN(FILTER_LEN) + ) i2c_slave_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .release_bus(1'b0), + + .s_axis_data_tdata (data_in_reg), + .s_axis_data_tvalid(data_in_valid_reg), + .s_axis_data_tready(data_in_ready), + .s_axis_data_tlast (1'b0), + + .m_axis_data_tdata (data_out), + .m_axis_data_tvalid(data_out_valid), + .m_axis_data_tready(data_out_ready_reg), + .m_axis_data_tlast (data_out_last), + + // I2C Interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(), + .bus_address(), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + + // Configuration + .enable(enable), + .device_address(device_address), + .device_address_mask(7'h7f) + ); endmodule From 533aa0d81c2598e022e6476ce593ec44dce0f596 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 13:06:07 +0200 Subject: [PATCH 21/47] verilator bug --- rtl/i2c_master_tb.v | 188 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 148 insertions(+), 40 deletions(-) diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index 103d6fe..330d28d 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -10,7 +10,7 @@ module i2c_master_tb; // Parameters parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) - parameter ENABLE_DEVICE_3 = 1; // Set to 0 to disable device 3 + parameter ENABLE_DEVICE_3 = 0; // Set to 0 to disable device 3 parameter ENABLE_DEVICE_4 = 1; // Set to 0 to disable device 4 reg clk = 0; @@ -83,6 +83,40 @@ module i2c_master_tb; .data_latch(data_latch_3), .data_out(data_out_3) ); + + + // Task to test i2c_single_reg writing + task test_i2c_single_reg_writing; + begin + $display("Testing i2c_single_reg writing"); + i2c_start(7'h70, 0); + s_axis_data_tdata = 8'd55; + s_axis_data_tvalid = 1; + wait_for_ready(); + if (data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); + $display("Received data %d", data_out_3); + end + endtask + + // Task to test i2c_single_reg reading + task test_i2c_single_reg_reading; + begin + $display("Testing i2c_single_reg reading"); + data_latch_3 = 1; + data_in_3 = 8'd123; + m_axis_data_tready = 1; + #(CLK_PERIOD); + data_latch_3 = 0; + i2c_start(7'h70, 1); + @(posedge m_axis_data_tvalid); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'd123) $fatal(1, "We didn't get what we sent"); + end + endtask + + end else begin : device_3 + wire scl_o_3 = 1'b1; + wire sda_o_3 = 1'b1; end endgenerate @@ -95,12 +129,12 @@ module i2c_master_tb; wire scl_t_4; wire [7:0] m_axis_data_tdata_4; wire m_axis_data_tvalid_4; - wire m_axis_data_tready_4; + reg m_axis_data_tready_4; wire m_axis_data_tlast_4; - wire [7:0] s_axis_data_tdata_4; - wire s_axis_data_tvalid_4; + reg [7:0] s_axis_data_tdata_4; + reg s_axis_data_tvalid_4; wire s_axis_data_tready_4; - wire s_axis_data_tlast_4; + reg s_axis_data_tlast_4; wire busy_4; wire [6:0] bus_address_4; wire bus_addressed_4; @@ -138,7 +172,107 @@ module i2c_master_tb; .device_address(device_address_4), .device_address_mask(device_address_mask_4) ); + + task test_write_to_i2c_slave; + begin + $display("Testing writing to i2c_slave (device_4)"); + enable_4 = 1; + device_address_4 = 7'h42; // Set slave address + device_address_mask_4 = 7'h7F; // Check all bits + + i2c_start(7'h42, 0); // Start write operation + s_axis_data_tdata = 8'hAA; // Data to write + s_axis_data_tvalid = 1; + stop_on_idle = 1; + + wait_for_ready(); + + if (m_axis_data_tdata_4 !== 8'hAA) $fatal(1, "First byte mismatch"); + s_axis_data_tdata = 8'h55; // Second byte to write + s_axis_data_tvalid = 1; + s_axis_cmd_valid = 1; //still valid + s_axis_cmd_write = 1; //really write the second + + wait_for_ready(); + #(CLK_PERIOD); //for verilator + if (m_axis_data_tdata_4 !== 8'h55) begin + // It seems verilator has trouble with this + $display("instead of 55 we get %h", m_axis_data_tdata_4); + $fatal(1, "Second byte mismatch"); + end + + s_axis_cmd_valid = 0; + wait_for_ready(); + + #(CLK_PERIOD * 10); // Wait for slave to process + + $display("Write to i2c_slave successful"); + end + endtask + + // Task to test reading from i2c_slave + task test_read_from_i2c_slave; + begin + $display("Testing reading from i2c_slave (device_4)"); + enable_4 = 1; + device_address_4 = 7'h42; // Set slave address + device_address_mask_4 = 7'h7F; // Check all bits + + // Prepare data to be read + s_axis_data_tdata_4 = 8'hCC; + s_axis_data_tvalid_4 = 1; + i2c_start(7'h42, 1); // Start read operation + m_axis_data_tready = 1; + $display("i2c start was started and now waiting for m_axis_data_tvalid.."); + @(posedge m_axis_data_tvalid); + s_axis_data_tvalid_4 = 0; + if (m_axis_data_tdata !== 8'hCC) $fatal(1, "First read byte mismatch"); + + s_axis_cmd_valid = 1; //read 2 times + s_axis_cmd_read = 1; + s_axis_data_tvalid_4 = 1; + s_axis_data_tdata_4 = 8'hDD; + + @(posedge m_axis_data_tvalid); + if (m_axis_data_tdata !== 8'hDD) $fatal(1, "Second read byte mismatch"); + + s_axis_cmd_valid = 0; + wait_for_ready(); + + $display("Read from i2c_slave successful"); + end + endtask + + // Task to test bus release, incomplete (not done) + task test_bus_release; + begin + $display("Testing bus release for i2c_slave (device_4)"); + enable_4 = 1; + device_address_4 = 7'h42; // Set slave address + device_address_mask_4 = 7'h7F; // Check all bits + + i2c_start(7'h42, 0); // Start write operation + #(CLK_PERIOD * 10); + + if (!bus_active_4) $fatal(1, "Bus should be active"); + + release_bus_4 = 1; + #(CLK_PERIOD); + release_bus_4 = 0; + + #(CLK_PERIOD * 10); + + if (bus_active_4) $fatal(1, "Bus should not be active after release"); + + $display("Bus release test successful"); + end + endtask + + end else begin : device_4 + wire scl_o_4 = 1'b1; + wire sda_o_4 = 1'b1; end + endgenerate // Model pull-up resistors with weak pull-ups @@ -146,12 +280,8 @@ module i2c_master_tb; pullup (sda_wire); // Model open-drain outputs, including conditional devices - assign scl_wire = (scl_o & scl2 & - (ENABLE_DEVICE_3 ? device_3.scl_o_3 : 1'b1) & - (ENABLE_DEVICE_4 ? device_4.scl_o_4 : 1'b1)) ? 1'bz : 1'b0; - assign sda_wire = (sda_o & sda2 & - (ENABLE_DEVICE_3 ? device_3.sda_o_3 : 1'b1) & - (ENABLE_DEVICE_4 ? device_4.sda_o_4 : 1'b1)) ? 1'bz : 1'b0; + assign scl_wire = (scl_o & scl2 & device_3.scl_o_3 & device_4.scl_o_4) ? 1'bz : 1'b0; + assign sda_wire = (sda_o & sda2 & device_3.sda_o_3 & device_4.sda_o_4) ? 1'bz : 1'b0; always #(CLK_PERIOD / 2) clk <= ~clk; @@ -342,38 +472,11 @@ module i2c_master_tb; wait_for_ready(); end endtask - - // Task to test i2c_single_reg writing - task test_i2c_single_reg_writing; - begin - $display("Testing i2c_single_reg writing"); - i2c_start(7'h70, 0); - s_axis_data_tdata = 8'd55; - s_axis_data_tvalid = 1; - wait_for_ready(); - if (device_3.data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); - $display("Received data %d", device_3.data_out_3); - end - endtask - - // Task to test i2c_single_reg reading - task test_i2c_single_reg_reading; - begin - $display("Testing i2c_single_reg reading"); - device_3.data_latch_3 = 1; - device_3.data_in_3 = 8'd123; - #(CLK_PERIOD); - device_3.data_latch_3 = 0; - i2c_start(7'h70, 1); - @(posedge m_axis_data_tvalid); - $display("Received m_axis_data_tdata %d", m_axis_data_tdata); - if (m_axis_data_tdata != 8'd123) $fatal(1, "We didn't get what we sent"); - end - endtask - + // Task to test writing to i2c_slave initial begin $display("Starting I2C Master test"); initialize_testbench; + /* test_nack_handling(); stop_on_idle = 1; test_writing(); @@ -383,6 +486,11 @@ module i2c_master_tb; wait_for_ready(); test_i2c_single_reg_writing(); test_i2c_single_reg_reading(); + #1000; //stopping + */ + if (ENABLE_DEVICE_4) device_4.test_write_to_i2c_slave(); + //test_read_from_i2c_slave(); + // test_bus_release(); #1000; $finish; end From a6135c3b90b32dfdaac16734ee2d446c6d0a9458 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 14:31:54 +0200 Subject: [PATCH 22/47] Fixing issue thanks to verilator --- rtl/i2c_master_tb.v | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index 330d28d..e7962d6 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -117,6 +117,17 @@ module i2c_master_tb; end else begin : device_3 wire scl_o_3 = 1'b1; wire sda_o_3 = 1'b1; + + task test_i2c_single_reg_writing; + $display("not implemented"); + endtask + + // Task to test i2c_single_reg reading + task test_i2c_single_reg_reading; + $display("not implemented"); + endtask + + end endgenerate @@ -194,7 +205,7 @@ module i2c_master_tb; s_axis_cmd_write = 1; //really write the second wait_for_ready(); - #(CLK_PERIOD); //for verilator + #(CLK_PERIOD*120); //for verilator if (m_axis_data_tdata_4 !== 8'h55) begin // It seems verilator has trouble with this $display("instead of 55 we get %h", m_axis_data_tdata_4); @@ -271,6 +282,19 @@ module i2c_master_tb; end else begin : device_4 wire scl_o_4 = 1'b1; wire sda_o_4 = 1'b1; + reg m_axis_data_tready_4=0; + + task test_write_to_i2c_slave; + begin + $display("not implemented"); + end + endtask +task test_read_from_i2c_slave; + begin + $display("not implemented"); + end + endtask + end endgenerate @@ -476,7 +500,6 @@ module i2c_master_tb; initial begin $display("Starting I2C Master test"); initialize_testbench; - /* test_nack_handling(); stop_on_idle = 1; test_writing(); @@ -484,12 +507,13 @@ module i2c_master_tb; test_reading(); wait_for_ready(); - test_i2c_single_reg_writing(); - test_i2c_single_reg_reading(); + device_3.test_i2c_single_reg_writing(); + device_3.test_i2c_single_reg_reading(); #1000; //stopping - */ - if (ENABLE_DEVICE_4) device_4.test_write_to_i2c_slave(); - //test_read_from_i2c_slave(); + //we are always ready +device_4.m_axis_data_tready_4=1; + device_4.test_write_to_i2c_slave(); + device_4.test_read_from_i2c_slave(); // test_bus_release(); #1000; $finish; From 7d6d4c67ba4f53ef3918ad035527fb84a68ae152 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 14:35:08 +0200 Subject: [PATCH 23/47] formatting using verilog format --- tb/axil.py | 1 - tb/axis_ep.py | 1 - tb/i2c.py | 2 - tb/test_i2c.py | 1 - tb/test_i2c_init.v | 115 ++++++++--------- tb/test_i2c_master.v | 189 ++++++++++++---------------- tb/test_i2c_master_axil.v | 207 +++++++++++++----------------- tb/test_i2c_master_wbs_16.v | 149 ++++++++++------------ tb/test_i2c_master_wbs_8.v | 144 ++++++++++----------- tb/test_i2c_slave.v | 163 ++++++++++-------------- tb/test_i2c_slave_axil_master.v | 217 ++++++++++++++------------------ tb/test_i2c_slave_wbm.v | 164 +++++++++++------------- tb/wb.py | 1 - 13 files changed, 579 insertions(+), 775 deletions(-) diff --git a/tb/axil.py b/tb/axil.py index 0cce06d..850b41c 100644 --- a/tb/axil.py +++ b/tb/axil.py @@ -544,4 +544,3 @@ def read_logic(): s_axil_rvalid.next = False return instances() - diff --git a/tb/axis_ep.py b/tb/axis_ep.py index 351df0b..d03376f 100644 --- a/tb/axis_ep.py +++ b/tb/axis_ep.py @@ -519,4 +519,3 @@ def logic(): first = True return instances() - diff --git a/tb/i2c.py b/tb/i2c.py index aa7fad6..cf48fd6 100644 --- a/tb/i2c.py +++ b/tb/i2c.py @@ -506,5 +506,3 @@ def logic(): break return instances() - - diff --git a/tb/test_i2c.py b/tb/test_i2c.py index 6a77cd8..7661c9e 100755 --- a/tb/test_i2c.py +++ b/tb/test_i2c.py @@ -233,4 +233,3 @@ def test_bench(): if __name__ == '__main__': print("Running test...") test_bench() - diff --git a/tb/test_i2c_init.v b/tb/test_i2c_init.v index 9fe4b72..f26eda4 100644 --- a/tb/test_i2c_init.v +++ b/tb/test_i2c_init.v @@ -31,76 +31,59 @@ THE SOFTWARE. */ module test_i2c_init; -// Parameters - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg m_axis_cmd_ready = 0; -reg m_axis_data_tready = 0; -reg start = 0; - -// Outputs -wire [6:0] m_axis_cmd_address; -wire m_axis_cmd_start; -wire m_axis_cmd_read; -wire m_axis_cmd_write; -wire m_axis_cmd_write_multiple; -wire m_axis_cmd_stop; -wire m_axis_cmd_valid; -wire [7:0] m_axis_data_tdata; -wire m_axis_data_tvalid; -wire m_axis_data_tlast; -wire busy; - -initial begin + // Parameters + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg m_axis_cmd_ready = 0; + reg m_axis_data_tready = 0; + reg start = 0; + + // Outputs + wire [6:0] m_axis_cmd_address; + wire m_axis_cmd_start; + wire m_axis_cmd_read; + wire m_axis_cmd_write; + wire m_axis_cmd_write_multiple; + wire m_axis_cmd_stop; + wire m_axis_cmd_valid; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire busy; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - m_axis_cmd_ready, - m_axis_data_tready, - start); - $to_myhdl( - m_axis_cmd_address, - m_axis_cmd_start, - m_axis_cmd_read, - m_axis_cmd_write, - m_axis_cmd_write_multiple, - m_axis_cmd_stop, - m_axis_cmd_valid, - m_axis_data_tdata, - m_axis_data_tvalid, - m_axis_data_tlast, - busy - ); + $from_myhdl(clk, rst, current_test, m_axis_cmd_ready, m_axis_data_tready, start); + $to_myhdl(m_axis_cmd_address, m_axis_cmd_start, m_axis_cmd_read, m_axis_cmd_write, + m_axis_cmd_write_multiple, m_axis_cmd_stop, m_axis_cmd_valid, m_axis_data_tdata, + m_axis_data_tvalid, m_axis_data_tlast, busy); // dump file $dumpfile("test_i2c_init.lxt"); $dumpvars(0, test_i2c_init); -end - -i2c_init -UUT ( - .clk(clk), - .rst(rst), - .m_axis_cmd_address(m_axis_cmd_address), - .m_axis_cmd_start(m_axis_cmd_start), - .m_axis_cmd_read(m_axis_cmd_read), - .m_axis_cmd_write(m_axis_cmd_write), - .m_axis_cmd_write_multiple(m_axis_cmd_write_multiple), - .m_axis_cmd_stop(m_axis_cmd_stop), - .m_axis_cmd_valid(m_axis_cmd_valid), - .m_axis_cmd_ready(m_axis_cmd_ready), - .m_axis_data_tdata(m_axis_data_tdata), - .m_axis_data_tvalid(m_axis_data_tvalid), - .m_axis_data_tready(m_axis_data_tready), - .m_axis_data_tlast(m_axis_data_tlast), - .busy(busy), - .start(start) -); + end + + i2c_init UUT ( + .clk(clk), + .rst(rst), + .m_axis_cmd_address(m_axis_cmd_address), + .m_axis_cmd_start(m_axis_cmd_start), + .m_axis_cmd_read(m_axis_cmd_read), + .m_axis_cmd_write(m_axis_cmd_write), + .m_axis_cmd_write_multiple(m_axis_cmd_write_multiple), + .m_axis_cmd_stop(m_axis_cmd_stop), + .m_axis_cmd_valid(m_axis_cmd_valid), + .m_axis_cmd_ready(m_axis_cmd_ready), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .busy(busy), + .start(start) + ); endmodule diff --git a/tb/test_i2c_master.v b/tb/test_i2c_master.v index 2622438..3766600 100644 --- a/tb/test_i2c_master.v +++ b/tb/test_i2c_master.v @@ -31,119 +31,90 @@ THE SOFTWARE. */ module test_i2c_master; -// Parameters - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [6:0] s_axis_cmd_address = 0; -reg s_axis_cmd_start = 0; -reg s_axis_cmd_read = 0; -reg s_axis_cmd_write = 0; -reg s_axis_cmd_write_multiple = 0; -reg s_axis_cmd_stop = 0; -reg s_axis_cmd_valid = 0; -reg [7:0] s_axis_data_tdata = 0; -reg s_axis_data_tvalid = 0; -reg s_axis_data_tlast = 0; -reg m_axis_data_tready = 0; -reg scl_i = 1; -reg sda_i = 1; -reg [15:0] prescale = 0; -reg stop_on_idle = 0; - -// Outputs -wire s_axis_cmd_ready; -wire s_axis_data_tready; -wire [7:0] m_axis_data_tdata; -wire m_axis_data_tvalid; -wire m_axis_data_tlast; -wire scl_o; -wire scl_t; -wire sda_o; -wire sda_t; -wire busy; -wire bus_control; -wire bus_active; -wire missed_ack; - -initial begin + // Parameters + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [6:0] s_axis_cmd_address = 0; + reg s_axis_cmd_start = 0; + reg s_axis_cmd_read = 0; + reg s_axis_cmd_write = 0; + reg s_axis_cmd_write_multiple = 0; + reg s_axis_cmd_stop = 0; + reg s_axis_cmd_valid = 0; + reg [7:0] s_axis_data_tdata = 0; + reg s_axis_data_tvalid = 0; + reg s_axis_data_tlast = 0; + reg m_axis_data_tready = 0; + reg scl_i = 1; + reg sda_i = 1; + reg [15:0] prescale = 0; + reg stop_on_idle = 0; + + // Outputs + wire s_axis_cmd_ready; + wire s_axis_data_tready; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire scl_o; + wire scl_t; + wire sda_o; + wire sda_t; + wire busy; + wire bus_control; + wire bus_active; + wire missed_ack; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - s_axis_cmd_address, - s_axis_cmd_start, - s_axis_cmd_read, - s_axis_cmd_write, - s_axis_cmd_write_multiple, - s_axis_cmd_stop, - s_axis_cmd_valid, - s_axis_data_tdata, - s_axis_data_tvalid, - s_axis_data_tlast, - m_axis_data_tready, - scl_i, - sda_i, - prescale, - stop_on_idle - ); - $to_myhdl( - s_axis_cmd_ready, - s_axis_data_tready, - m_axis_data_tdata, - m_axis_data_tvalid, - m_axis_data_tlast, - scl_o, - scl_t, - sda_o, - sda_t, - busy, - bus_control, - bus_active, - missed_ack - ); + $from_myhdl(clk, rst, current_test, s_axis_cmd_address, s_axis_cmd_start, s_axis_cmd_read, + s_axis_cmd_write, s_axis_cmd_write_multiple, s_axis_cmd_stop, s_axis_cmd_valid, + s_axis_data_tdata, s_axis_data_tvalid, s_axis_data_tlast, m_axis_data_tready, + scl_i, sda_i, prescale, stop_on_idle); + $to_myhdl(s_axis_cmd_ready, s_axis_data_tready, m_axis_data_tdata, m_axis_data_tvalid, + m_axis_data_tlast, scl_o, scl_t, sda_o, sda_t, busy, bus_control, bus_active, + missed_ack); // dump file $dumpfile("test_i2c_master.lxt"); $dumpvars(0, test_i2c_master); -end - -i2c_master -UUT ( - .clk(clk), - .rst(rst), - .s_axis_cmd_address(s_axis_cmd_address), - .s_axis_cmd_start(s_axis_cmd_start), - .s_axis_cmd_read(s_axis_cmd_read), - .s_axis_cmd_write(s_axis_cmd_write), - .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), - .s_axis_cmd_stop(s_axis_cmd_stop), - .s_axis_cmd_valid(s_axis_cmd_valid), - .s_axis_cmd_ready(s_axis_cmd_ready), - .s_axis_data_tdata(s_axis_data_tdata), - .s_axis_data_tvalid(s_axis_data_tvalid), - .s_axis_data_tready(s_axis_data_tready), - .s_axis_data_tlast(s_axis_data_tlast), - .m_axis_data_tdata(m_axis_data_tdata), - .m_axis_data_tvalid(m_axis_data_tvalid), - .m_axis_data_tready(m_axis_data_tready), - .m_axis_data_tlast(m_axis_data_tlast), - .scl_i(scl_i), - .scl_o(scl_o), - .scl_t(scl_t), - .sda_i(sda_i), - .sda_o(sda_o), - .sda_t(sda_t), - .busy(busy), - .bus_control(bus_control), - .bus_active(bus_active), - .missed_ack(missed_ack), - .prescale(prescale), - .stop_on_idle(stop_on_idle) -); + end + + i2c_master UUT ( + .clk(clk), + .rst(rst), + .s_axis_cmd_address(s_axis_cmd_address), + .s_axis_cmd_start(s_axis_cmd_start), + .s_axis_cmd_read(s_axis_cmd_read), + .s_axis_cmd_write(s_axis_cmd_write), + .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), + .s_axis_cmd_stop(s_axis_cmd_stop), + .s_axis_cmd_valid(s_axis_cmd_valid), + .s_axis_cmd_ready(s_axis_cmd_ready), + .s_axis_data_tdata(s_axis_data_tdata), + .s_axis_data_tvalid(s_axis_data_tvalid), + .s_axis_data_tready(s_axis_data_tready), + .s_axis_data_tlast(s_axis_data_tlast), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .scl_i(scl_i), + .scl_o(scl_o), + .scl_t(scl_t), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .busy(busy), + .bus_control(bus_control), + .bus_active(bus_active), + .missed_ack(missed_ack), + .prescale(prescale), + .stop_on_idle(stop_on_idle) + ); endmodule diff --git a/tb/test_i2c_master_axil.v b/tb/test_i2c_master_axil.v index de6995d..4e8a7c6 100644 --- a/tb/test_i2c_master_axil.v +++ b/tb/test_i2c_master_axil.v @@ -31,127 +31,100 @@ THE SOFTWARE. */ module test_i2c_master_axil; -// Parameters -parameter DEFAULT_PRESCALE = 1; -parameter FIXED_PRESCALE = 0; -parameter CMD_FIFO = 1; -parameter CMD_FIFO_DEPTH = 32; -parameter WRITE_FIFO = 1; -parameter WRITE_FIFO_DEPTH = 32; -parameter READ_FIFO = 1; -parameter READ_FIFO_DEPTH = 32; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [3:0] s_axil_awaddr = 0; -reg [2:0] s_axil_awprot = 0; -reg s_axil_awvalid = 0; -reg [31:0] s_axil_wdata = 0; -reg [3:0] s_axil_wstrb = 0; -reg s_axil_wvalid = 0; -reg s_axil_bready = 0; -reg [3:0] s_axil_araddr = 0; -reg [2:0] s_axil_arprot = 0; -reg s_axil_arvalid = 0; -reg s_axil_rready = 0; -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; - -// Outputs -wire s_axil_awready; -wire s_axil_wready; -wire [1:0] s_axil_bresp; -wire s_axil_bvalid; -wire s_axil_arready; -wire [31:0] s_axil_rdata; -wire [1:0] s_axil_rresp; -wire s_axil_rvalid; -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; - -initial begin + // Parameters + parameter DEFAULT_PRESCALE = 1; + parameter FIXED_PRESCALE = 0; + parameter CMD_FIFO = 1; + parameter CMD_FIFO_DEPTH = 32; + parameter WRITE_FIFO = 1; + parameter WRITE_FIFO_DEPTH = 32; + parameter READ_FIFO = 1; + parameter READ_FIFO_DEPTH = 32; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [3:0] s_axil_awaddr = 0; + reg [2:0] s_axil_awprot = 0; + reg s_axil_awvalid = 0; + reg [31:0] s_axil_wdata = 0; + reg [3:0] s_axil_wstrb = 0; + reg s_axil_wvalid = 0; + reg s_axil_bready = 0; + reg [3:0] s_axil_araddr = 0; + reg [2:0] s_axil_arprot = 0; + reg s_axil_arvalid = 0; + reg s_axil_rready = 0; + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + + // Outputs + wire s_axil_awready; + wire s_axil_wready; + wire [1:0] s_axil_bresp; + wire s_axil_bvalid; + wire s_axil_arready; + wire [31:0] s_axil_rdata; + wire [1:0] s_axil_rresp; + wire s_axil_rvalid; + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - s_axil_awaddr, - s_axil_awprot, - s_axil_awvalid, - s_axil_wdata, - s_axil_wstrb, - s_axil_wvalid, - s_axil_bready, - s_axil_araddr, - s_axil_arprot, - s_axil_arvalid, - s_axil_rready, - i2c_scl_i, - i2c_sda_i - ); - $to_myhdl( - s_axil_awready, - s_axil_wready, - s_axil_bresp, - s_axil_bvalid, - s_axil_arready, - s_axil_rdata, - s_axil_rresp, - s_axil_rvalid, - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t - ); + $from_myhdl(clk, rst, current_test, s_axil_awaddr, s_axil_awprot, s_axil_awvalid, s_axil_wdata, + s_axil_wstrb, s_axil_wvalid, s_axil_bready, s_axil_araddr, s_axil_arprot, + s_axil_arvalid, s_axil_rready, i2c_scl_i, i2c_sda_i); + $to_myhdl(s_axil_awready, s_axil_wready, s_axil_bresp, s_axil_bvalid, s_axil_arready, + s_axil_rdata, s_axil_rresp, s_axil_rvalid, i2c_scl_o, i2c_scl_t, i2c_sda_o, + i2c_sda_t); // dump file $dumpfile("test_i2c_master_axil.lxt"); $dumpvars(0, test_i2c_master_axil); -end - -i2c_master_axil #( - .DEFAULT_PRESCALE(DEFAULT_PRESCALE), - .FIXED_PRESCALE(FIXED_PRESCALE), - .CMD_FIFO(CMD_FIFO), - .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), - .WRITE_FIFO(WRITE_FIFO), - .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), - .READ_FIFO(READ_FIFO), - .READ_FIFO_DEPTH(READ_FIFO_DEPTH) -) -UUT ( - .clk(clk), - .rst(rst), - .s_axil_awaddr(s_axil_awaddr), - .s_axil_awprot(s_axil_awprot), - .s_axil_awvalid(s_axil_awvalid), - .s_axil_awready(s_axil_awready), - .s_axil_wdata(s_axil_wdata), - .s_axil_wstrb(s_axil_wstrb), - .s_axil_wvalid(s_axil_wvalid), - .s_axil_wready(s_axil_wready), - .s_axil_bresp(s_axil_bresp), - .s_axil_bvalid(s_axil_bvalid), - .s_axil_bready(s_axil_bready), - .s_axil_araddr(s_axil_araddr), - .s_axil_arprot(s_axil_arprot), - .s_axil_arvalid(s_axil_arvalid), - .s_axil_arready(s_axil_arready), - .s_axil_rdata(s_axil_rdata), - .s_axil_rresp(s_axil_rresp), - .s_axil_rvalid(s_axil_rvalid), - .s_axil_rready(s_axil_rready), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t) -); + end + + i2c_master_axil #( + .DEFAULT_PRESCALE(DEFAULT_PRESCALE), + .FIXED_PRESCALE(FIXED_PRESCALE), + .CMD_FIFO(CMD_FIFO), + .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), + .WRITE_FIFO(WRITE_FIFO), + .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), + .READ_FIFO(READ_FIFO), + .READ_FIFO_DEPTH(READ_FIFO_DEPTH) + ) UUT ( + .clk(clk), + .rst(rst), + .s_axil_awaddr(s_axil_awaddr), + .s_axil_awprot(s_axil_awprot), + .s_axil_awvalid(s_axil_awvalid), + .s_axil_awready(s_axil_awready), + .s_axil_wdata(s_axil_wdata), + .s_axil_wstrb(s_axil_wstrb), + .s_axil_wvalid(s_axil_wvalid), + .s_axil_wready(s_axil_wready), + .s_axil_bresp(s_axil_bresp), + .s_axil_bvalid(s_axil_bvalid), + .s_axil_bready(s_axil_bready), + .s_axil_araddr(s_axil_araddr), + .s_axil_arprot(s_axil_arprot), + .s_axil_arvalid(s_axil_arvalid), + .s_axil_arready(s_axil_arready), + .s_axil_rdata(s_axil_rdata), + .s_axil_rresp(s_axil_rresp), + .s_axil_rvalid(s_axil_rvalid), + .s_axil_rready(s_axil_rready), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t) + ); endmodule diff --git a/tb/test_i2c_master_wbs_16.v b/tb/test_i2c_master_wbs_16.v index ff5573a..2f3be53 100644 --- a/tb/test_i2c_master_wbs_16.v +++ b/tb/test_i2c_master_wbs_16.v @@ -31,94 +31,75 @@ THE SOFTWARE. */ module test_i2c_master_wbs_16; -// Parameters -parameter DEFAULT_PRESCALE = 1; -parameter FIXED_PRESCALE = 0; -parameter CMD_FIFO = 1; -parameter CMD_FIFO_DEPTH = 32; -parameter WRITE_FIFO = 1; -parameter WRITE_FIFO_DEPTH = 32; -parameter READ_FIFO = 1; -parameter READ_FIFO_DEPTH = 32; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [2:0] wbs_adr_i = 0; -reg [15:0] wbs_dat_i = 0; -reg wbs_we_i = 0; -reg [1:0] wbs_sel_i = 0; -reg wbs_stb_i = 0; -reg wbs_cyc_i = 0; -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; - -// Outputs -wire [15:0] wbs_dat_o; -wire wbs_ack_o; -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; - -initial begin + // Parameters + parameter DEFAULT_PRESCALE = 1; + parameter FIXED_PRESCALE = 0; + parameter CMD_FIFO = 1; + parameter CMD_FIFO_DEPTH = 32; + parameter WRITE_FIFO = 1; + parameter WRITE_FIFO_DEPTH = 32; + parameter READ_FIFO = 1; + parameter READ_FIFO_DEPTH = 32; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [2:0] wbs_adr_i = 0; + reg [15:0] wbs_dat_i = 0; + reg wbs_we_i = 0; + reg [1:0] wbs_sel_i = 0; + reg wbs_stb_i = 0; + reg wbs_cyc_i = 0; + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + + // Outputs + wire [15:0] wbs_dat_o; + wire wbs_ack_o; + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - wbs_adr_i, - wbs_dat_i, - wbs_we_i, - wbs_sel_i, - wbs_stb_i, - wbs_cyc_i, - i2c_scl_i, - i2c_sda_i - ); - $to_myhdl( - wbs_dat_o, - wbs_ack_o, - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t - ); + $from_myhdl(clk, rst, current_test, wbs_adr_i, wbs_dat_i, wbs_we_i, wbs_sel_i, wbs_stb_i, + wbs_cyc_i, i2c_scl_i, i2c_sda_i); + $to_myhdl(wbs_dat_o, wbs_ack_o, i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t); // dump file $dumpfile("test_i2c_master_wbs_16.lxt"); $dumpvars(0, test_i2c_master_wbs_16); -end - -i2c_master_wbs_16 #( - .DEFAULT_PRESCALE(DEFAULT_PRESCALE), - .FIXED_PRESCALE(FIXED_PRESCALE), - .CMD_FIFO(CMD_FIFO), - .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), - .WRITE_FIFO(WRITE_FIFO), - .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), - .READ_FIFO(READ_FIFO), - .READ_FIFO_DEPTH(READ_FIFO_DEPTH) -) -UUT ( - .clk(clk), - .rst(rst), - .wbs_adr_i(wbs_adr_i), - .wbs_dat_i(wbs_dat_i), - .wbs_dat_o(wbs_dat_o), - .wbs_we_i(wbs_we_i), - .wbs_sel_i(wbs_sel_i), - .wbs_stb_i(wbs_stb_i), - .wbs_ack_o(wbs_ack_o), - .wbs_cyc_i(wbs_cyc_i), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t) -); + end + + i2c_master_wbs_16 #( + .DEFAULT_PRESCALE(DEFAULT_PRESCALE), + .FIXED_PRESCALE(FIXED_PRESCALE), + .CMD_FIFO(CMD_FIFO), + .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), + .WRITE_FIFO(WRITE_FIFO), + .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), + .READ_FIFO(READ_FIFO), + .READ_FIFO_DEPTH(READ_FIFO_DEPTH) + ) UUT ( + .clk(clk), + .rst(rst), + .wbs_adr_i(wbs_adr_i), + .wbs_dat_i(wbs_dat_i), + .wbs_dat_o(wbs_dat_o), + .wbs_we_i(wbs_we_i), + .wbs_sel_i(wbs_sel_i), + .wbs_stb_i(wbs_stb_i), + .wbs_ack_o(wbs_ack_o), + .wbs_cyc_i(wbs_cyc_i), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t) + ); endmodule diff --git a/tb/test_i2c_master_wbs_8.v b/tb/test_i2c_master_wbs_8.v index 7eeedbf..12a71f2 100644 --- a/tb/test_i2c_master_wbs_8.v +++ b/tb/test_i2c_master_wbs_8.v @@ -31,91 +31,73 @@ THE SOFTWARE. */ module test_i2c_master_wbs_8; -// Parameters -parameter DEFAULT_PRESCALE = 1; -parameter FIXED_PRESCALE = 0; -parameter CMD_FIFO = 1; -parameter CMD_FIFO_DEPTH = 32; -parameter WRITE_FIFO = 1; -parameter WRITE_FIFO_DEPTH = 32; -parameter READ_FIFO = 1; -parameter READ_FIFO_DEPTH = 32; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [2:0] wbs_adr_i = 0; -reg [7:0] wbs_dat_i = 0; -reg wbs_we_i = 0; -reg wbs_stb_i = 0; -reg wbs_cyc_i = 0; -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; - -// Outputs -wire [7:0] wbs_dat_o; -wire wbs_ack_o; -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; - -initial begin + // Parameters + parameter DEFAULT_PRESCALE = 1; + parameter FIXED_PRESCALE = 0; + parameter CMD_FIFO = 1; + parameter CMD_FIFO_DEPTH = 32; + parameter WRITE_FIFO = 1; + parameter WRITE_FIFO_DEPTH = 32; + parameter READ_FIFO = 1; + parameter READ_FIFO_DEPTH = 32; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [2:0] wbs_adr_i = 0; + reg [7:0] wbs_dat_i = 0; + reg wbs_we_i = 0; + reg wbs_stb_i = 0; + reg wbs_cyc_i = 0; + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + + // Outputs + wire [7:0] wbs_dat_o; + wire wbs_ack_o; + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - wbs_adr_i, - wbs_dat_i, - wbs_we_i, - wbs_stb_i, - wbs_cyc_i, - i2c_scl_i, - i2c_sda_i - ); - $to_myhdl( - wbs_dat_o, - wbs_ack_o, - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t - ); + $from_myhdl(clk, rst, current_test, wbs_adr_i, wbs_dat_i, wbs_we_i, wbs_stb_i, wbs_cyc_i, + i2c_scl_i, i2c_sda_i); + $to_myhdl(wbs_dat_o, wbs_ack_o, i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t); // dump file $dumpfile("test_i2c_master_wbs_8.lxt"); $dumpvars(0, test_i2c_master_wbs_8); -end - -i2c_master_wbs_8 #( - .DEFAULT_PRESCALE(DEFAULT_PRESCALE), - .FIXED_PRESCALE(FIXED_PRESCALE), - .CMD_FIFO(CMD_FIFO), - .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), - .WRITE_FIFO(WRITE_FIFO), - .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), - .READ_FIFO(READ_FIFO), - .READ_FIFO_DEPTH(READ_FIFO_DEPTH) -) -UUT ( - .clk(clk), - .rst(rst), - .wbs_adr_i(wbs_adr_i), - .wbs_dat_i(wbs_dat_i), - .wbs_dat_o(wbs_dat_o), - .wbs_we_i(wbs_we_i), - .wbs_stb_i(wbs_stb_i), - .wbs_ack_o(wbs_ack_o), - .wbs_cyc_i(wbs_cyc_i), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t) -); + end + + i2c_master_wbs_8 #( + .DEFAULT_PRESCALE(DEFAULT_PRESCALE), + .FIXED_PRESCALE(FIXED_PRESCALE), + .CMD_FIFO(CMD_FIFO), + .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), + .WRITE_FIFO(WRITE_FIFO), + .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), + .READ_FIFO(READ_FIFO), + .READ_FIFO_DEPTH(READ_FIFO_DEPTH) + ) UUT ( + .clk(clk), + .rst(rst), + .wbs_adr_i(wbs_adr_i), + .wbs_dat_i(wbs_dat_i), + .wbs_dat_o(wbs_dat_o), + .wbs_we_i(wbs_we_i), + .wbs_stb_i(wbs_stb_i), + .wbs_ack_o(wbs_ack_o), + .wbs_cyc_i(wbs_cyc_i), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t) + ); endmodule diff --git a/tb/test_i2c_slave.v b/tb/test_i2c_slave.v index 247ab17..4d0c725 100644 --- a/tb/test_i2c_slave.v +++ b/tb/test_i2c_slave.v @@ -31,104 +31,79 @@ THE SOFTWARE. */ module test_i2c_slave; -// Parameters -parameter FILTER_LEN = 2; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg release_bus = 0; -reg [7:0] s_axis_data_tdata = 0; -reg s_axis_data_tvalid = 0; -reg s_axis_data_tlast = 0; -reg m_axis_data_tready = 0; -reg scl_i = 1; -reg sda_i = 1; -reg enable = 0; -reg [6:0] device_address = 0; -reg [6:0] device_address_mask = 0; - -// Outputs -wire s_axis_data_tready; -wire [7:0] m_axis_data_tdata; -wire m_axis_data_tvalid; -wire m_axis_data_tlast; -wire scl_o; -wire scl_t; -wire sda_o; -wire sda_t; -wire busy; -wire [6:0] bus_address; -wire bus_addressed; -wire bus_active; - -initial begin + // Parameters + parameter FILTER_LEN = 2; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg release_bus = 0; + reg [7:0] s_axis_data_tdata = 0; + reg s_axis_data_tvalid = 0; + reg s_axis_data_tlast = 0; + reg m_axis_data_tready = 0; + reg scl_i = 1; + reg sda_i = 1; + reg enable = 0; + reg [6:0] device_address = 0; + reg [6:0] device_address_mask = 0; + + // Outputs + wire s_axis_data_tready; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire scl_o; + wire scl_t; + wire sda_o; + wire sda_t; + wire busy; + wire [6:0] bus_address; + wire bus_addressed; + wire bus_active; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - release_bus, - s_axis_data_tdata, - s_axis_data_tvalid, - s_axis_data_tlast, - m_axis_data_tready, - scl_i, - sda_i, - enable, - device_address, - device_address_mask - ); - $to_myhdl( - s_axis_data_tready, - m_axis_data_tdata, - m_axis_data_tvalid, - m_axis_data_tlast, - scl_o, - scl_t, - sda_o, - sda_t, - busy, - bus_address, - bus_addressed, - bus_active - ); + $from_myhdl(clk, rst, current_test, release_bus, s_axis_data_tdata, s_axis_data_tvalid, + s_axis_data_tlast, m_axis_data_tready, scl_i, sda_i, enable, device_address, + device_address_mask); + $to_myhdl(s_axis_data_tready, m_axis_data_tdata, m_axis_data_tvalid, m_axis_data_tlast, scl_o, + scl_t, sda_o, sda_t, busy, bus_address, bus_addressed, bus_active); // dump file $dumpfile("test_i2c_slave.lxt"); $dumpvars(0, test_i2c_slave); -end - -i2c_slave #( - .FILTER_LEN(FILTER_LEN) -) -UUT ( - .clk(clk), - .rst(rst), - .release_bus(release_bus), - .s_axis_data_tdata(s_axis_data_tdata), - .s_axis_data_tvalid(s_axis_data_tvalid), - .s_axis_data_tready(s_axis_data_tready), - .s_axis_data_tlast(s_axis_data_tlast), - .m_axis_data_tdata(m_axis_data_tdata), - .m_axis_data_tvalid(m_axis_data_tvalid), - .m_axis_data_tready(m_axis_data_tready), - .m_axis_data_tlast(m_axis_data_tlast), - .scl_i(scl_i), - .scl_o(scl_o), - .scl_t(scl_t), - .sda_i(sda_i), - .sda_o(sda_o), - .sda_t(sda_t), - .busy(busy), - .bus_address(bus_address), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - .enable(enable), - .device_address(device_address), - .device_address_mask(device_address_mask) -); + end + + i2c_slave #( + .FILTER_LEN(FILTER_LEN) + ) UUT ( + .clk(clk), + .rst(rst), + .release_bus(release_bus), + .s_axis_data_tdata(s_axis_data_tdata), + .s_axis_data_tvalid(s_axis_data_tvalid), + .s_axis_data_tready(s_axis_data_tready), + .s_axis_data_tlast(s_axis_data_tlast), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .scl_i(scl_i), + .scl_o(scl_o), + .scl_t(scl_t), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .busy(busy), + .bus_address(bus_address), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + .enable(enable), + .device_address(device_address), + .device_address_mask(device_address_mask) + ); endmodule diff --git a/tb/test_i2c_slave_axil_master.v b/tb/test_i2c_slave_axil_master.v index 73d01a9..7e9e039 100644 --- a/tb/test_i2c_slave_axil_master.v +++ b/tb/test_i2c_slave_axil_master.v @@ -31,134 +31,103 @@ THE SOFTWARE. */ module test_i2c_slave_axil_master; -// Parameters -parameter FILTER_LEN = 4; -parameter DATA_WIDTH = 32; -parameter ADDR_WIDTH = 16; -parameter STRB_WIDTH = (DATA_WIDTH/8); - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; -reg m_axil_awready = 0; -reg m_axil_wready = 0; -reg [1:0] m_axil_bresp = 0; -reg m_axil_bvalid = 0; -reg m_axil_arready = 0; -reg [DATA_WIDTH-1:0] m_axil_rdata = 0; -reg [1:0] m_axil_rresp = 0; -reg m_axil_rvalid = 0; -reg enable = 0; -reg [6:0] device_address = 0; - -// Outputs -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; -wire [ADDR_WIDTH-1:0] m_axil_awaddr; -wire [2:0] m_axil_awprot; -wire m_axil_awvalid; -wire [DATA_WIDTH-1:0] m_axil_wdata; -wire [STRB_WIDTH-1:0] m_axil_wstrb; -wire m_axil_wvalid; -wire m_axil_bready; -wire [ADDR_WIDTH-1:0] m_axil_araddr; -wire [2:0] m_axil_arprot; -wire m_axil_arvalid; -wire m_axil_rready; -wire busy; -wire bus_addressed; -wire bus_active; - -initial begin + // Parameters + parameter FILTER_LEN = 4; + parameter DATA_WIDTH = 32; + parameter ADDR_WIDTH = 16; + parameter STRB_WIDTH = (DATA_WIDTH / 8); + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + reg m_axil_awready = 0; + reg m_axil_wready = 0; + reg [1:0] m_axil_bresp = 0; + reg m_axil_bvalid = 0; + reg m_axil_arready = 0; + reg [DATA_WIDTH-1:0] m_axil_rdata = 0; + reg [1:0] m_axil_rresp = 0; + reg m_axil_rvalid = 0; + reg enable = 0; + reg [6:0] device_address = 0; + + // Outputs + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + wire [ADDR_WIDTH-1:0] m_axil_awaddr; + wire [2:0] m_axil_awprot; + wire m_axil_awvalid; + wire [DATA_WIDTH-1:0] m_axil_wdata; + wire [STRB_WIDTH-1:0] m_axil_wstrb; + wire m_axil_wvalid; + wire m_axil_bready; + wire [ADDR_WIDTH-1:0] m_axil_araddr; + wire [2:0] m_axil_arprot; + wire m_axil_arvalid; + wire m_axil_rready; + wire busy; + wire bus_addressed; + wire bus_active; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - i2c_scl_i, - i2c_sda_i, - m_axil_awready, - m_axil_wready, - m_axil_bresp, - m_axil_bvalid, - m_axil_arready, - m_axil_rdata, - m_axil_rresp, - m_axil_rvalid, - enable, - device_address - ); - $to_myhdl( - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t, - m_axil_awaddr, - m_axil_awprot, - m_axil_awvalid, - m_axil_wdata, - m_axil_wstrb, - m_axil_wvalid, - m_axil_bready, - m_axil_araddr, - m_axil_arprot, - m_axil_arvalid, - m_axil_rready, - busy, - bus_addressed, - bus_active - ); + $from_myhdl(clk, rst, current_test, i2c_scl_i, i2c_sda_i, m_axil_awready, m_axil_wready, + m_axil_bresp, m_axil_bvalid, m_axil_arready, m_axil_rdata, m_axil_rresp, + m_axil_rvalid, enable, device_address); + $to_myhdl(i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t, m_axil_awaddr, m_axil_awprot, + m_axil_awvalid, m_axil_wdata, m_axil_wstrb, m_axil_wvalid, m_axil_bready, + m_axil_araddr, m_axil_arprot, m_axil_arvalid, m_axil_rready, busy, bus_addressed, + bus_active); // dump file $dumpfile("test_i2c_slave_axil_master.lxt"); $dumpvars(0, test_i2c_slave_axil_master); -end - -i2c_slave_axil_master #( - .FILTER_LEN(FILTER_LEN), - .DATA_WIDTH(DATA_WIDTH), - .ADDR_WIDTH(ADDR_WIDTH), - .STRB_WIDTH(STRB_WIDTH) -) -UUT ( - .clk(clk), - .rst(rst), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t), - .m_axil_awaddr(m_axil_awaddr), - .m_axil_awprot(m_axil_awprot), - .m_axil_awvalid(m_axil_awvalid), - .m_axil_awready(m_axil_awready), - .m_axil_wdata(m_axil_wdata), - .m_axil_wstrb(m_axil_wstrb), - .m_axil_wvalid(m_axil_wvalid), - .m_axil_wready(m_axil_wready), - .m_axil_bresp(m_axil_bresp), - .m_axil_bvalid(m_axil_bvalid), - .m_axil_bready(m_axil_bready), - .m_axil_araddr(m_axil_araddr), - .m_axil_arprot(m_axil_arprot), - .m_axil_arvalid(m_axil_arvalid), - .m_axil_arready(m_axil_arready), - .m_axil_rdata(m_axil_rdata), - .m_axil_rresp(m_axil_rresp), - .m_axil_rvalid(m_axil_rvalid), - .m_axil_rready(m_axil_rready), - .busy(busy), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - .enable(enable), - .device_address(device_address) -); + end + + i2c_slave_axil_master #( + .FILTER_LEN(FILTER_LEN), + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH) + ) UUT ( + .clk(clk), + .rst(rst), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t), + .m_axil_awaddr(m_axil_awaddr), + .m_axil_awprot(m_axil_awprot), + .m_axil_awvalid(m_axil_awvalid), + .m_axil_awready(m_axil_awready), + .m_axil_wdata(m_axil_wdata), + .m_axil_wstrb(m_axil_wstrb), + .m_axil_wvalid(m_axil_wvalid), + .m_axil_wready(m_axil_wready), + .m_axil_bresp(m_axil_bresp), + .m_axil_bvalid(m_axil_bvalid), + .m_axil_bready(m_axil_bready), + .m_axil_araddr(m_axil_araddr), + .m_axil_arprot(m_axil_arprot), + .m_axil_arvalid(m_axil_arvalid), + .m_axil_arready(m_axil_arready), + .m_axil_rdata(m_axil_rdata), + .m_axil_rresp(m_axil_rresp), + .m_axil_rvalid(m_axil_rvalid), + .m_axil_rready(m_axil_rready), + .busy(busy), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + .enable(enable), + .device_address(device_address) + ); endmodule diff --git a/tb/test_i2c_slave_wbm.v b/tb/test_i2c_slave_wbm.v index cedbe2b..4cd60a0 100644 --- a/tb/test_i2c_slave_wbm.v +++ b/tb/test_i2c_slave_wbm.v @@ -31,104 +31,80 @@ THE SOFTWARE. */ module test_i2c_slave_wbm; -// Parameters -parameter FILTER_LEN = 4; -parameter WB_DATA_WIDTH = 32; -parameter WB_ADDR_WIDTH = 16; -parameter WB_SELECT_WIDTH = WB_DATA_WIDTH/8; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; -reg [WB_DATA_WIDTH-1:0] wb_dat_i = 0; -reg wb_ack_i = 0; -reg wb_err_i = 0; -reg enable = 0; -reg [6:0] device_address = 0; - -// Outputs -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; -wire [WB_ADDR_WIDTH-1:0] wb_adr_o; -wire [WB_DATA_WIDTH-1:0] wb_dat_o; -wire wb_we_o; -wire [WB_SELECT_WIDTH-1:0] wb_sel_o; -wire wb_stb_o; -wire wb_cyc_o; -wire busy; -wire bus_addressed; -wire bus_active; - -initial begin + // Parameters + parameter FILTER_LEN = 4; + parameter WB_DATA_WIDTH = 32; + parameter WB_ADDR_WIDTH = 16; + parameter WB_SELECT_WIDTH = WB_DATA_WIDTH / 8; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + reg [WB_DATA_WIDTH-1:0] wb_dat_i = 0; + reg wb_ack_i = 0; + reg wb_err_i = 0; + reg enable = 0; + reg [6:0] device_address = 0; + + // Outputs + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + wire [WB_ADDR_WIDTH-1:0] wb_adr_o; + wire [WB_DATA_WIDTH-1:0] wb_dat_o; + wire wb_we_o; + wire [WB_SELECT_WIDTH-1:0] wb_sel_o; + wire wb_stb_o; + wire wb_cyc_o; + wire busy; + wire bus_addressed; + wire bus_active; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - i2c_scl_i, - i2c_sda_i, - wb_dat_i, - wb_ack_i, - wb_err_i, - enable, - device_address - ); - $to_myhdl( - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t, - wb_adr_o, - wb_dat_o, - wb_we_o, - wb_sel_o, - wb_stb_o, - wb_cyc_o, - busy, - bus_addressed, - bus_active - ); + $from_myhdl(clk, rst, current_test, i2c_scl_i, i2c_sda_i, wb_dat_i, wb_ack_i, wb_err_i, enable, + device_address); + $to_myhdl(i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t, wb_adr_o, wb_dat_o, wb_we_o, wb_sel_o, + wb_stb_o, wb_cyc_o, busy, bus_addressed, bus_active); // dump file $dumpfile("test_i2c_slave_wbm.lxt"); $dumpvars(0, test_i2c_slave_wbm); -end - -i2c_slave_wbm #( - .FILTER_LEN(FILTER_LEN), - .WB_DATA_WIDTH(WB_DATA_WIDTH), - .WB_ADDR_WIDTH(WB_ADDR_WIDTH), - .WB_SELECT_WIDTH(WB_SELECT_WIDTH) -) -UUT ( - .clk(clk), - .rst(rst), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t), - .wb_adr_o(wb_adr_o), - .wb_dat_i(wb_dat_i), - .wb_dat_o(wb_dat_o), - .wb_we_o(wb_we_o), - .wb_sel_o(wb_sel_o), - .wb_stb_o(wb_stb_o), - .wb_ack_i(wb_ack_i), - .wb_err_i(wb_err_i), - .wb_cyc_o(wb_cyc_o), - .busy(busy), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - .enable(enable), - .device_address(device_address) -); + end + + i2c_slave_wbm #( + .FILTER_LEN(FILTER_LEN), + .WB_DATA_WIDTH(WB_DATA_WIDTH), + .WB_ADDR_WIDTH(WB_ADDR_WIDTH), + .WB_SELECT_WIDTH(WB_SELECT_WIDTH) + ) UUT ( + .clk(clk), + .rst(rst), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t), + .wb_adr_o(wb_adr_o), + .wb_dat_i(wb_dat_i), + .wb_dat_o(wb_dat_o), + .wb_we_o(wb_we_o), + .wb_sel_o(wb_sel_o), + .wb_stb_o(wb_stb_o), + .wb_ack_i(wb_ack_i), + .wb_err_i(wb_err_i), + .wb_cyc_o(wb_cyc_o), + .busy(busy), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + .enable(enable), + .device_address(device_address) + ); endmodule diff --git a/tb/wb.py b/tb/wb.py index b618ef8..515a266 100644 --- a/tb/wb.py +++ b/tb/wb.py @@ -438,4 +438,3 @@ def logic(): print("[%s] Read word a:0x%08x d:%s" % (name, addr, " ".join(("{:02x}".format(c) for c in bytearray(data))))) return instances() - From 7b8cd6803a2a72ba2be597b8362f3663dccdf8dd Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 14:39:20 +0200 Subject: [PATCH 24/47] forgot to format --- rtl/i2c_master_tb.v | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/rtl/i2c_master_tb.v b/rtl/i2c_master_tb.v index e7962d6..61bda4b 100644 --- a/rtl/i2c_master_tb.v +++ b/rtl/i2c_master_tb.v @@ -118,14 +118,14 @@ module i2c_master_tb; wire scl_o_3 = 1'b1; wire sda_o_3 = 1'b1; - task test_i2c_single_reg_writing; - $display("not implemented"); + task test_i2c_single_reg_writing; + $display("not implemented"); endtask // Task to test i2c_single_reg reading task test_i2c_single_reg_reading; - $display("not implemented"); - endtask + $display("not implemented"); + endtask end @@ -205,7 +205,7 @@ module i2c_master_tb; s_axis_cmd_write = 1; //really write the second wait_for_ready(); - #(CLK_PERIOD*120); //for verilator + #(CLK_PERIOD * 120); //for verilator if (m_axis_data_tdata_4 !== 8'h55) begin // It seems verilator has trouble with this $display("instead of 55 we get %h", m_axis_data_tdata_4); @@ -282,15 +282,15 @@ module i2c_master_tb; end else begin : device_4 wire scl_o_4 = 1'b1; wire sda_o_4 = 1'b1; - reg m_axis_data_tready_4=0; + reg m_axis_data_tready_4 = 0; task test_write_to_i2c_slave; - begin + begin $display("not implemented"); end endtask -task test_read_from_i2c_slave; - begin + task test_read_from_i2c_slave; + begin $display("not implemented"); end endtask @@ -511,7 +511,7 @@ task test_read_from_i2c_slave; device_3.test_i2c_single_reg_reading(); #1000; //stopping //we are always ready -device_4.m_axis_data_tready_4=1; + device_4.m_axis_data_tready_4 = 1; device_4.test_write_to_i2c_slave(); device_4.test_read_from_i2c_slave(); // test_bus_release(); From a753beb008fba8823c1e0b6491d994aafc14a976 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 30 Jun 2024 14:51:33 +0200 Subject: [PATCH 25/47] this will fix rst so it is async --- rtl/i2c_slave.v | 97 +++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index ef8266c..81a8588 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -446,68 +446,69 @@ I/O pin. This would prevent devices from stretching the clock period. end end - always @(posedge clk) begin - state_reg <= state_next; + always @(posedge clk or negedge rst) begin + if (rst) begin + state_reg <= STATE_IDLE; + s_axis_data_tready_reg <= 1'b0; + m_axis_data_tvalid_reg <= 1'b0; + scl_o_reg <= 1'b1; + sda_o_reg <= 1'b1; + busy_reg <= 1'b0; + bus_active_reg <= 1'b0; + bus_addressed_reg <= 1'b0; + end else begin - addr_reg <= addr_next; - data_reg <= data_next; - data_valid_reg <= data_valid_next; - data_out_reg_valid_reg <= data_out_reg_valid_next; - last_reg <= last_next; + state_reg <= state_next; - mode_read_reg <= mode_read_next; + addr_reg <= addr_next; + data_reg <= data_next; + data_valid_reg <= data_valid_next; + data_out_reg_valid_reg <= data_out_reg_valid_next; + last_reg <= last_next; - bit_count_reg <= bit_count_next; + mode_read_reg <= mode_read_next; - s_axis_data_tready_reg <= s_axis_data_tready_next; + bit_count_reg <= bit_count_next; - m_axis_data_tdata_reg <= m_axis_data_tdata_next; - m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; - m_axis_data_tlast_reg <= m_axis_data_tlast_next; + s_axis_data_tready_reg <= s_axis_data_tready_next; - scl_i_filter <= (scl_i_filter << 1) | {3'b000, scl_i}; - sda_i_filter <= (sda_i_filter << 1) | {3'b000, sda_i}; + m_axis_data_tdata_reg <= m_axis_data_tdata_next; + m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; + m_axis_data_tlast_reg <= m_axis_data_tlast_next; - if (scl_i_filter == {FILTER_LEN{1'b1}}) begin - scl_i_reg <= 1'b1; - end else if (scl_i_filter == {FILTER_LEN{1'b0}}) begin - scl_i_reg <= 1'b0; - end + scl_i_filter <= (scl_i_filter << 1) | {3'b000, scl_i}; + sda_i_filter <= (sda_i_filter << 1) | {3'b000, sda_i}; - if (sda_i_filter == {FILTER_LEN{1'b1}}) begin - sda_i_reg <= 1'b1; - end else if (sda_i_filter == {FILTER_LEN{1'b0}}) begin - sda_i_reg <= 1'b0; - end + if (scl_i_filter == {FILTER_LEN{1'b1}}) begin + scl_i_reg <= 1'b1; + end else if (scl_i_filter == {FILTER_LEN{1'b0}}) begin + scl_i_reg <= 1'b0; + end - scl_o_reg <= scl_o_next; - sda_o_reg <= sda_o_next; + if (sda_i_filter == {FILTER_LEN{1'b1}}) begin + sda_i_reg <= 1'b1; + end else if (sda_i_filter == {FILTER_LEN{1'b0}}) begin + sda_i_reg <= 1'b0; + end - last_scl_i_reg <= scl_i_reg; - last_sda_i_reg <= sda_i_reg; + scl_o_reg <= scl_o_next; + sda_o_reg <= sda_o_next; - busy_reg <= !(state_reg == STATE_IDLE); + last_scl_i_reg <= scl_i_reg; + last_sda_i_reg <= sda_i_reg; - if (start_bit) begin - bus_active_reg <= 1'b1; - end else if (stop_bit) begin - bus_active_reg <= 1'b0; - end else begin - bus_active_reg <= bus_active_reg; - end + busy_reg <= !(state_reg == STATE_IDLE); - bus_addressed_reg <= bus_addressed_next; + if (start_bit) begin + bus_active_reg <= 1'b1; + end else if (stop_bit) begin + bus_active_reg <= 1'b0; + end else begin + bus_active_reg <= bus_active_reg; + end + + bus_addressed_reg <= bus_addressed_next; - if (rst) begin - state_reg <= STATE_IDLE; - s_axis_data_tready_reg <= 1'b0; - m_axis_data_tvalid_reg <= 1'b0; - scl_o_reg <= 1'b1; - sda_o_reg <= 1'b1; - busy_reg <= 1'b0; - bus_active_reg <= 1'b0; - bus_addressed_reg <= 1'b0; end end - endmodule From 2545a6e08e6d57166be12773f03e294bec22cc6a Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 2 Jul 2024 07:28:24 +0200 Subject: [PATCH 26/47] adding write event add events --- rtl/i2c_master.v | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 34b1234..3d60ce5 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -54,6 +54,7 @@ module i2c_master ( output wire m_axis_data_tvalid, input wire m_axis_data_tready, output wire m_axis_data_tlast, + /* * I2C interface @@ -72,7 +73,7 @@ module i2c_master ( output wire bus_control, output wire bus_active, output wire missed_ack, - + output wire value_has_been_written,//triggers on last value /* * Configuration */ @@ -247,6 +248,7 @@ I/O pin. This would prevent devices from stretching the clock period. reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; + reg value_has_been_written_reg =0'b0; reg scl_i_reg = 1'b1; reg sda_i_reg = 1'b1; @@ -263,7 +265,7 @@ I/O pin. This would prevent devices from stretching the clock period. wire phy_busy; //reg bus_control_reg = 1'b0, bus_control_next; reg missed_ack_reg = 1'b0, missed_ack_next; - +assign value_has_been_written = value_has_been_written_reg; assign s_axis_cmd_ready = s_axis_cmd_ready_reg; assign s_axis_data_tready = s_axis_data_tready_reg; @@ -567,6 +569,7 @@ I/O pin. This would prevent devices from stretching the clock period. STATE_WRITE_3: begin // read ack bit missed_ack_next = phy_rx_data_reg; + value_has_been_written_reg=1; if (mode_write_multiple_reg && !last_reg) begin // more to write From b31fcfe4e0c07c7b810f8545b0dde8b024fd4501 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 2 Jul 2024 08:55:53 +0200 Subject: [PATCH 27/47] testbench goes on tb --- {rtl => tb}/i2c_master_tb.v | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {rtl => tb}/i2c_master_tb.v (100%) diff --git a/rtl/i2c_master_tb.v b/tb/i2c_master_tb.v similarity index 100% rename from rtl/i2c_master_tb.v rename to tb/i2c_master_tb.v From 1f52d3d62cf8c75f1db4d7764db9076111f39a1d Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 2 Jul 2024 08:58:23 +0200 Subject: [PATCH 28/47] add this from other branch --- .github/workflows/icarus.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/icarus.yml diff --git a/.github/workflows/icarus.yml b/.github/workflows/icarus.yml new file mode 100644 index 0000000..77ec4ef --- /dev/null +++ b/.github/workflows/icarus.yml @@ -0,0 +1,25 @@ +name: Icarus Verilog CI + +on: + push: + branches: [ "*" ] + pull_request: + branches: [ "*" ] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y iverilog verilator + + - name: Compile with Icarus Verilog + run: iverilog -o sim_output -y rtl tb/i2c_master_tb.v + + - name: Run simulation + run: ./sim_output From 974ae1c3bb8991b5bc9badf0614416f6e6642616 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 2 Jul 2024 09:07:07 +0200 Subject: [PATCH 29/47] fixing the test --- tb/i2c_master_tb.v | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index 61bda4b..60f58c6 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -33,6 +33,7 @@ module i2c_master_tb; reg sda_i = 1; reg [15:0] prescale = 0; reg stop_on_idle = 0; + wire s_axis_cmd_ready; wire s_axis_data_tready; @@ -47,6 +48,7 @@ module i2c_master_tb; wire bus_control; wire bus_active; wire missed_ack; + wire value_has_been_written;//never used // Wires for modeling pull-up resistors and open-drain outputs wire scl_wire; @@ -360,6 +362,7 @@ module i2c_master_tb; .bus_control(bus_control), .bus_active(bus_active), .missed_ack(missed_ack), + .value_has_been_written(value_has_been_written) .prescale(prescale), .stop_on_idle(stop_on_idle) ); From 67ad173922b4dff5af3fcab72f2494b5f2ac1fa5 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 2 Jul 2024 09:08:21 +0200 Subject: [PATCH 30/47] missing comma --- tb/i2c_master_tb.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index 60f58c6..637069b 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -362,7 +362,7 @@ module i2c_master_tb; .bus_control(bus_control), .bus_active(bus_active), .missed_ack(missed_ack), - .value_has_been_written(value_has_been_written) + .value_has_been_written(value_has_been_written), .prescale(prescale), .stop_on_idle(stop_on_idle) ); From 019a642ae2db96c2598e514fc3182c34a61322a6 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 2 Jul 2024 09:10:23 +0200 Subject: [PATCH 31/47] fix the error of 0 sized int --- rtl/i2c_master.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 3d60ce5..d6bf97e 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -248,7 +248,7 @@ I/O pin. This would prevent devices from stretching the clock period. reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; - reg value_has_been_written_reg =0'b0; + reg value_has_been_written_reg =1'b0; reg scl_i_reg = 1'b1; reg sda_i_reg = 1'b1; From e9e408a47f75f865705bd11743fadbcc8ff47c02 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Mon, 8 Jul 2024 19:32:05 +0200 Subject: [PATCH 32/47] changing testbenches, on NACK simply stop.. no need to go further... --- rtl/i2c_master.v | 76 ++++++++++++++++++++--------------- rtl/i2c_phy.v | 16 ++++---- rtl/i2c_slave.v | 4 +- tb/i2c_master_tb.v | 98 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 132 insertions(+), 62 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index d6bf97e..652eb33 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -54,7 +54,7 @@ module i2c_master ( output wire m_axis_data_tvalid, input wire m_axis_data_tready, output wire m_axis_data_tlast, - + /* * I2C interface @@ -69,16 +69,16 @@ module i2c_master ( /* * Status */ - output wire busy, - output wire bus_control, - output wire bus_active, - output wire missed_ack, - output wire value_has_been_written,//triggers on last value + output wire busy, + output wire bus_control, + output wire bus_active, + output wire missed_ack, + output wire value_has_been_written, //triggers on last value /* * Configuration */ - input wire [15:0] prescale, - input wire stop_on_idle + input wire [15:0] prescale, + input wire stop_on_idle ); /* @@ -248,7 +248,7 @@ I/O pin. This would prevent devices from stretching the clock period. reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; - reg value_has_been_written_reg =1'b0; + reg value_has_been_written_reg = 1'b0; reg scl_i_reg = 1'b1; reg sda_i_reg = 1'b1; @@ -265,7 +265,7 @@ I/O pin. This would prevent devices from stretching the clock period. wire phy_busy; //reg bus_control_reg = 1'b0, bus_control_next; reg missed_ack_reg = 1'b0, missed_ack_next; -assign value_has_been_written = value_has_been_written_reg; + assign value_has_been_written = value_has_been_written_reg; assign s_axis_cmd_ready = s_axis_cmd_ready_reg; assign s_axis_data_tready = s_axis_data_tready_reg; @@ -319,6 +319,7 @@ assign value_has_been_written = value_has_been_written_reg; m_axis_data_tdata_next = m_axis_data_tdata_reg; m_axis_data_tvalid_next = m_axis_data_tvalid_reg & ~m_axis_data_tready; m_axis_data_tlast_next = m_axis_data_tlast_reg; + value_has_been_written_reg = 1'b0; missed_ack_next = 1'b0; @@ -393,7 +394,8 @@ assign value_has_been_written = value_has_been_written_reg; end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin // stop command phy_stop_bit = 1'b1; - state_next = STATE_IDLE; + $display("from active write to idle? why?"); + state_next = STATE_IDLE; end else begin // invalid or unspecified - ignore state_next = STATE_ACTIVE_WRITE; @@ -524,17 +526,20 @@ assign value_has_been_written = value_has_been_written_reg; missed_ack_next = phy_rx_data_reg; if (missed_ack_next) begin $display("got NACK"); - end else $display("got ACK"); - - if (mode_read_reg) begin - // start read - bit_count_next = 4'd8; - data_next = 8'b0; - state_next = STATE_READ; + state_next = STATE_STOP; end else begin - // start write - s_axis_data_tready_next = 1'b1; - state_next = STATE_WRITE_1; + $display("got ACK"); + + if (mode_read_reg) begin + // start read + bit_count_next = 4'd8; + data_next = 8'b0; + state_next = STATE_READ; + end else begin + // start write + s_axis_data_tready_next = 1'b1; + state_next = STATE_WRITE_1; + end end end STATE_WRITE_1: begin @@ -569,18 +574,25 @@ assign value_has_been_written = value_has_been_written_reg; STATE_WRITE_3: begin // read ack bit missed_ack_next = phy_rx_data_reg; - value_has_been_written_reg=1; - - if (mode_write_multiple_reg && !last_reg) begin - // more to write - state_next = STATE_WRITE_1; - end else if (mode_stop_reg) begin - // last cycle and stop selected - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; + if (missed_ack_next) begin + $display("got NACK on write"); + state_next = STATE_STOP; end else begin - // otherwise, return to bus active state - state_next = STATE_ACTIVE_WRITE; + $display("got ACK on write %d", $time); + + value_has_been_written_reg = 1; //only if successful! + + if (mode_write_multiple_reg && !last_reg) begin + // more to write + state_next = STATE_WRITE_1; + end else if (mode_stop_reg) begin + // last cycle and stop selected + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end else begin + // otherwise, return to bus active state + state_next = STATE_ACTIVE_WRITE; + end end end STATE_READ: begin diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index a06922e..d9c31ac 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -51,13 +51,13 @@ module i2c_phy ( // Internal registers - reg scl_o_reg; - reg scl_i_reg; - reg sda_i_reg; - reg sda_o_reg; + reg scl_o_reg = 1; + reg scl_i_reg = 1; + reg sda_i_reg = 1; + reg sda_o_reg = 1; - reg phy_rx_data_next; + reg phy_rx_data_next = 0; reg [4:0] phy_state_next; @@ -65,10 +65,10 @@ module i2c_phy ( reg delay_scl_reg = 1'b0, delay_scl_next; reg delay_sda_reg = 1'b0, delay_sda_next; - reg scl_o_next; - reg sda_o_next; + reg scl_o_next = 1; + reg sda_o_next = 1; - reg bus_control_next; + reg bus_control_next = 0; assign scl_o = scl_o_reg; assign scl_t = scl_o_reg; diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index 81a8588..821eeb7 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -201,8 +201,8 @@ I/O pin. This would prevent devices from stretching the clock period. reg scl_i_reg = 1'b1; reg sda_i_reg = 1'b1; - reg scl_o_reg = 1'b1, scl_o_next; - reg sda_o_reg = 1'b1, sda_o_next; + reg scl_o_reg = 1'b1, scl_o_next = 1; + reg sda_o_reg = 1'b1, sda_o_next = 1; reg last_scl_i_reg = 1'b1; reg last_sda_i_reg = 1'b1; diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index 637069b..952b70f 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -10,7 +10,7 @@ module i2c_master_tb; // Parameters parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) - parameter ENABLE_DEVICE_3 = 0; // Set to 0 to disable device 3 + parameter ENABLE_DEVICE_3 = 1; // Set to 0 to disable device 3 parameter ENABLE_DEVICE_4 = 1; // Set to 0 to disable device 4 reg clk = 0; @@ -33,7 +33,7 @@ module i2c_master_tb; reg sda_i = 1; reg [15:0] prescale = 0; reg stop_on_idle = 0; - + wire s_axis_cmd_ready; wire s_axis_data_tready; @@ -48,7 +48,7 @@ module i2c_master_tb; wire bus_control; wire bus_active; wire missed_ack; - wire value_has_been_written;//never used + wire value_has_been_written; //never used // Wires for modeling pull-up resistors and open-drain outputs wire scl_wire; @@ -58,6 +58,23 @@ module i2c_master_tb; reg sda2 = 1; reg scl2 = 1; + + task wait_for_success(); + + do begin + @(posedge missed_ack or posedge value_has_been_written or posedge m_axis_data_tvalid or posedge s_axis_cmd_stop); + if (missed_ack) begin + s_axis_data_tvalid = 1; + $display("missed ack detected we retry happiliy?"); + end else if (value_has_been_written | m_axis_data_tvalid | s_axis_cmd_stop) begin + + s_axis_data_tvalid = 0; + s_axis_cmd_valid = 0; + end + end while (s_axis_data_tvalid == 1'b1); //what happens if it gets no ack at the end? + + + endtask : wait_for_success // Generate block for Device 3 generate if (ENABLE_DEVICE_3) begin : device_3 @@ -91,9 +108,12 @@ module i2c_master_tb; task test_i2c_single_reg_writing; begin $display("Testing i2c_single_reg writing"); + wait_for_ready(); i2c_start(7'h70, 0); s_axis_data_tdata = 8'd55; s_axis_data_tvalid = 1; + wait_for_success; + wait_for_ready(); if (data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); $display("Received data %d", data_out_3); @@ -110,7 +130,8 @@ module i2c_master_tb; #(CLK_PERIOD); data_latch_3 = 0; i2c_start(7'h70, 1); - @(posedge m_axis_data_tvalid); + wait_for_success; + //@(posedge m_axis_data_tvalid); $display("Received m_axis_data_tdata %d", m_axis_data_tdata); if (m_axis_data_tdata != 8'd123) $fatal(1, "We didn't get what we sent"); end @@ -119,6 +140,7 @@ module i2c_master_tb; end else begin : device_3 wire scl_o_3 = 1'b1; wire sda_o_3 = 1'b1; + reg data_out_3 = 1'b1; task test_i2c_single_reg_writing; $display("not implemented"); @@ -197,6 +219,7 @@ module i2c_master_tb; s_axis_data_tdata = 8'hAA; // Data to write s_axis_data_tvalid = 1; stop_on_idle = 1; + wait_for_success; wait_for_ready(); @@ -237,7 +260,7 @@ module i2c_master_tb; i2c_start(7'h42, 1); // Start read operation m_axis_data_tready = 1; $display("i2c start was started and now waiting for m_axis_data_tvalid.."); - @(posedge m_axis_data_tvalid); + wait_for_success; s_axis_data_tvalid_4 = 0; if (m_axis_data_tdata !== 8'hCC) $fatal(1, "First read byte mismatch"); @@ -245,8 +268,7 @@ module i2c_master_tb; s_axis_cmd_read = 1; s_axis_data_tvalid_4 = 1; s_axis_data_tdata_4 = 8'hDD; - - @(posedge m_axis_data_tvalid); + wait_for_success; if (m_axis_data_tdata !== 8'hDD) $fatal(1, "Second read byte mismatch"); s_axis_cmd_valid = 0; @@ -322,13 +344,18 @@ module i2c_master_tb; sda_i <= sda_wire; // Assert that sda_i is not X - if (sda_i === 1'bx) $fatal(1, "sda_i is X at time %t", $time); + if (sda_i === 1'bx) begin + + $display("sda4 %d", device_4.sda_o_4); + + $fatal(1, "sda_i is X at time %t", $time); + end end end initial begin // dump file - $dumpfile("i2c_master_tb.fst"); + $dumpfile("i2c_master_tb.vcd"); $dumpvars(0, i2c_master_tb); end @@ -398,18 +425,20 @@ module i2c_master_tb; input is_read; begin s_axis_cmd_address = address; - s_axis_cmd_start = 1; + //s_axis_cmd_start = 1; s_axis_cmd_read = is_read; s_axis_cmd_write = !is_read; s_axis_cmd_valid = 1; - @(negedge sda_wire); - @(negedge scl_wire); //start condition done! + //cant enforce anyway - s_axis_cmd_start = 0; - s_axis_cmd_read = 0; - s_axis_cmd_write = 0; - s_axis_cmd_valid = 0; + //@(negedge sda_wire); + //@(negedge scl_wire); //start condition done! + + //s_axis_cmd_start = 0; + //s_axis_cmd_read = 0; + //s_axis_cmd_write = 0; + //s_axis_cmd_valid = 0; end endtask @@ -464,12 +493,36 @@ module i2c_master_tb; s_axis_data_tdata = 8'b10101111; s_axis_data_tvalid = 1; repeat (7) @(negedge scl_o); + s_axis_cmd_valid = 0; send_ack(); @(negedge scl_o); //send_byte(8'b01111111); wait_for_ready(); end endtask + // Task to test writing + task test_valid_weird; + begin + $display("Testing something."); + i2c_start(7'h70, 0); + $display("send address?"); + @(posedge s_axis_data_tready); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + @(negedge s_axis_data_tready) + //repeat (2) @(posedge clk); + s_axis_data_tvalid = 0; + $display("if setting valid false it will not work?"); + @(posedge value_has_been_written); + $display("success %b", device_3.data_out_3); + //repeat (7) @(negedge scl_o); + //send_ack(); + //@(negedge scl_o); + //send_byte(8'b01111111); + wait_for_ready(); + end + endtask + // Task to test reading task test_reading; @@ -478,7 +531,7 @@ module i2c_master_tb; s_axis_data_tdata = 8'b10101111; s_axis_data_tvalid = 1; i2c_start(7'b0000001, 1); - repeat (7) @(negedge scl_o); + repeat (8) @(negedge scl_o); s_axis_cmd_valid = 0; send_ack(); send_byte(8'b01111111); @@ -486,7 +539,8 @@ module i2c_master_tb; s_axis_cmd_valid = 1; m_axis_data_tready = 1; @(negedge scl_o); - if (sda_wire) $fatal(1, "Got NACK from master"); + + if (sda_wire) #1000 $fatal(1, "Got NACK from master"); $display("Received m_axis_data_tdata %d", m_axis_data_tdata); if (m_axis_data_tdata != 8'b01111111) $fatal(1, "We didn't get what we sent"); #(CLK_PERIOD); @@ -503,14 +557,17 @@ module i2c_master_tb; initial begin $display("Starting I2C Master test"); initialize_testbench; - test_nack_handling(); stop_on_idle = 1; + device_3.test_i2c_single_reg_writing(); + test_nack_handling(); //killing time for dev3 it needs time to initialize + device_3.test_i2c_single_reg_writing(); + //test_valid_weird(); test_writing(); + #1000; //stopping test_reading(); wait_for_ready(); - device_3.test_i2c_single_reg_writing(); device_3.test_i2c_single_reg_reading(); #1000; //stopping //we are always ready @@ -518,6 +575,7 @@ module i2c_master_tb; device_4.test_write_to_i2c_slave(); device_4.test_read_from_i2c_slave(); // test_bus_release(); + #1000; $finish; end From 4f0ac9affaec030808037a0ce276acc169f1e892 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Mon, 8 Jul 2024 20:06:54 +0200 Subject: [PATCH 33/47] let's stick to verilog for now --- tb/i2c_master_tb.v | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index 952b70f..f1ec350 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -58,23 +58,23 @@ module i2c_master_tb; reg sda2 = 1; reg scl2 = 1; - - task wait_for_success(); - - do begin +task wait_for_success; + reg continue_waiting; + begin + continue_waiting = 1; + while (continue_waiting) begin @(posedge missed_ack or posedge value_has_been_written or posedge m_axis_data_tvalid or posedge s_axis_cmd_stop); if (missed_ack) begin s_axis_data_tvalid = 1; - $display("missed ack detected we retry happiliy?"); + $display("missed ack detected we retry happily?"); end else if (value_has_been_written | m_axis_data_tvalid | s_axis_cmd_stop) begin - s_axis_data_tvalid = 0; s_axis_cmd_valid = 0; + continue_waiting = 0; end - end while (s_axis_data_tvalid == 1'b1); //what happens if it gets no ack at the end? - - - endtask : wait_for_success + end + end +endtask // Generate block for Device 3 generate if (ENABLE_DEVICE_3) begin : device_3 From 9b24b7de0fca3869c97b2fcc3ee56b346eaa5624 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 9 Jul 2024 09:06:03 +0200 Subject: [PATCH 34/47] changing logic a little bit --- tb/i2c_master_tb.v | 51 +++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index f1ec350..3f04fb4 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -58,23 +58,23 @@ module i2c_master_tb; reg sda2 = 1; reg scl2 = 1; -task wait_for_success; - reg continue_waiting; - begin - continue_waiting = 1; - while (continue_waiting) begin - @(posedge missed_ack or posedge value_has_been_written or posedge m_axis_data_tvalid or posedge s_axis_cmd_stop); - if (missed_ack) begin - s_axis_data_tvalid = 1; - $display("missed ack detected we retry happily?"); - end else if (value_has_been_written | m_axis_data_tvalid | s_axis_cmd_stop) begin - s_axis_data_tvalid = 0; - s_axis_cmd_valid = 0; - continue_waiting = 0; + task wait_for_success; + reg continue_waiting; + begin + continue_waiting = 1; + while (continue_waiting) begin + @(posedge missed_ack or posedge value_has_been_written or posedge m_axis_data_tvalid or posedge s_axis_cmd_stop); + if (missed_ack) begin + s_axis_data_tvalid = 1; + $display("missed ack detected we retry happily?"); + end else if (value_has_been_written | m_axis_data_tvalid | s_axis_cmd_stop) begin + s_axis_data_tvalid = 0; + s_axis_cmd_valid = 0; + continue_waiting = 0; + end end end - end -endtask + endtask // Generate block for Device 3 generate if (ENABLE_DEVICE_3) begin : device_3 @@ -509,12 +509,18 @@ endtask @(posedge s_axis_data_tready); s_axis_data_tdata = 8'b10101111; s_axis_data_tvalid = 1; - @(negedge s_axis_data_tready) - //repeat (2) @(posedge clk); - s_axis_data_tvalid = 0; - $display("if setting valid false it will not work?"); - @(posedge value_has_been_written); + wait_for_success; + $display("success %b", device_3.data_out_3); + //wait 1000 cycles + #1000; + s_axis_cmd_valid = 1; + s_axis_data_tdata = 8'd2; + s_axis_data_tvalid = 1; + wait_for_success; $display("success %b", device_3.data_out_3); + #1000; + stop_on_idle = 1; + //repeat (7) @(negedge scl_o); //send_ack(); //@(negedge scl_o); @@ -555,13 +561,16 @@ endtask endtask // Task to test writing to i2c_slave initial begin + /*new goal: send 1, then decide wether to stop or send 2. both options + * must be allowed*/ $display("Starting I2C Master test"); initialize_testbench; stop_on_idle = 1; device_3.test_i2c_single_reg_writing(); test_nack_handling(); //killing time for dev3 it needs time to initialize device_3.test_i2c_single_reg_writing(); - //test_valid_weird(); + stop_on_idle = 0; + test_valid_weird(); test_writing(); #1000; //stopping From 3541490b6f5cee63a48624f251cfacecefc3f318 Mon Sep 17 00:00:00 2001 From: "Kreijstal (aider)" Date: Tue, 9 Jul 2024 10:23:12 +0200 Subject: [PATCH 35/47] Initialize module registers with default values. --- rtl/i2c_single_reg.v | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index b25bb39..e286f75 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -66,25 +66,25 @@ module i2c_single_reg #( STATE_READ_2 = 5'd6, STATE_READ_3 = 5'd7; - reg [4:0] state_reg; + reg [4:0] state_reg = STATE_IDLE; - reg [7:0] data_reg; - reg [7:0] shift_reg; + reg [7:0] data_reg = 8'd0; + reg [7:0] shift_reg = 8'd0; - reg mode_read_reg; + reg mode_read_reg = 1'b0; - reg [3:0] bit_count_reg; + reg [3:0] bit_count_reg = 4'd0; - reg [FILTER_LEN-1:0] scl_i_filter_reg; - reg [FILTER_LEN-1:0] sda_i_filter_reg; + reg [FILTER_LEN-1:0] scl_i_filter_reg = {FILTER_LEN{1'b0}}; + reg [FILTER_LEN-1:0] sda_i_filter_reg = {FILTER_LEN{1'b0}}; - reg scl_i_reg; - reg sda_i_reg; + reg scl_i_reg = 1'b0; + reg sda_i_reg = 1'b0; - reg sda_o_reg; + reg sda_o_reg = 1'b1; - reg last_scl_i_reg; - reg last_sda_i_reg; + reg last_scl_i_reg = 1'b0; + reg last_sda_i_reg = 1'b0; assign scl_o = 1'b1; assign scl_t = 1'b1; From 83d7df92d40a522c939ff92712ac3291d1ad911e Mon Sep 17 00:00:00 2001 From: "Kreijstal (aider)" Date: Tue, 9 Jul 2024 10:25:09 +0200 Subject: [PATCH 36/47] Initialized all state, address, data, mode, bit count, and signal registers with default values in i2c_slave module. --- rtl/i2c_slave.v | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index 821eeb7..63a4f6b 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -177,39 +177,39 @@ I/O pin. This would prevent devices from stretching the clock period. STATE_READ_2 = 5'd6, STATE_READ_3 = 5'd7; - reg [4:0] state_reg = STATE_IDLE, state_next; + reg [4:0] state_reg = STATE_IDLE, state_next = STATE_IDLE; - reg [6:0] addr_reg = 7'd0, addr_next; - reg [7:0] data_reg = 8'd0, data_next; - reg data_valid_reg = 1'b0, data_valid_next; - reg data_out_reg_valid_reg = 1'b0, data_out_reg_valid_next; - reg last_reg = 1'b0, last_next; + reg [6:0] addr_reg = 7'd0, addr_next = 7'd0; + reg [7:0] data_reg = 8'd0, data_next = 8'd0; + reg data_valid_reg = 1'b0, data_valid_next = 1'b0; + reg data_out_reg_valid_reg = 1'b0, data_out_reg_valid_next = 1'b0; + reg last_reg = 1'b0, last_next = 1'b0; - reg mode_read_reg = 1'b0, mode_read_next; + reg mode_read_reg = 1'b0, mode_read_next = 1'b0; - reg [3:0] bit_count_reg = 4'd0, bit_count_next; + reg [3:0] bit_count_reg = 4'd0, bit_count_next = 4'd0; - reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; + reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next = 1'b0; - reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; - reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; - reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; + reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next = 8'd0; + reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next = 1'b0; + reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next = 1'b0; - reg [FILTER_LEN-1:0] scl_i_filter = {FILTER_LEN{1'b1}}; - reg [FILTER_LEN-1:0] sda_i_filter = {FILTER_LEN{1'b1}}; + reg [FILTER_LEN-1:0] scl_i_filter = {FILTER_LEN{1'b1}}, scl_i_filter_next = {FILTER_LEN{1'b1}}; + reg [FILTER_LEN-1:0] sda_i_filter = {FILTER_LEN{1'b1}}, sda_i_filter_next = {FILTER_LEN{1'b1}}; - reg scl_i_reg = 1'b1; - reg sda_i_reg = 1'b1; + reg scl_i_reg = 1'b1, scl_i_next = 1'b1; + reg sda_i_reg = 1'b1, sda_i_next = 1'b1; - reg scl_o_reg = 1'b1, scl_o_next = 1; - reg sda_o_reg = 1'b1, sda_o_next = 1; + reg scl_o_reg = 1'b1, scl_o_next = 1'b1; + reg sda_o_reg = 1'b1, sda_o_next = 1'b1; - reg last_scl_i_reg = 1'b1; - reg last_sda_i_reg = 1'b1; + reg last_scl_i_reg = 1'b1, last_scl_i_next = 1'b1; + reg last_sda_i_reg = 1'b1, last_sda_i_next = 1'b1; - reg busy_reg = 1'b0; - reg bus_active_reg = 1'b0; - reg bus_addressed_reg = 1'b0, bus_addressed_next; + reg busy_reg = 1'b0, busy_next = 1'b0; + reg bus_active_reg = 1'b0, bus_active_next = 1'b0; + reg bus_addressed_reg = 1'b0, bus_addressed_next = 1'b0; // Signal declarations reg scl_posedge; From 338ce599fd32e1f3602b53da88972602fd9fbf7b Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 9 Jul 2024 10:25:51 +0200 Subject: [PATCH 37/47] changing testbench --- tb/i2c_master_tb.v | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index 3f04fb4..2554485 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -108,7 +108,7 @@ module i2c_master_tb; task test_i2c_single_reg_writing; begin $display("Testing i2c_single_reg writing"); - wait_for_ready(); + //wait_for_ready(); i2c_start(7'h70, 0); s_axis_data_tdata = 8'd55; s_axis_data_tvalid = 1; @@ -501,9 +501,9 @@ module i2c_master_tb; end endtask // Task to test writing - task test_valid_weird; + task test_write_weird; begin - $display("Testing something."); + $display("Testing something write weird."); i2c_start(7'h70, 0); $display("send address?"); @(posedge s_axis_data_tready); @@ -529,6 +529,32 @@ module i2c_master_tb; end endtask + task test_read_weird; + begin + stop_on_idle = 0; + $display("Testing something read weird."); + i2c_start(7'h70, 1); + m_axis_data_tready = 1; + wait_for_success; + m_axis_data_tready = 0; + $display("success %b", m_axis_data_tdata); + //wait 1000 cycles + #1000; + s_axis_cmd_valid = 1; + m_axis_data_tready = 1; + wait_for_success; + $display("success %b", m_axis_data_tdata); + #1000; + stop_on_idle = 1; + + //repeat (7) @(negedge scl_o); + //send_ack(); + //@(negedge scl_o); + //send_byte(8'b01111111); + wait_for_ready(); + end + endtask + // Task to test reading task test_reading; @@ -561,16 +587,17 @@ module i2c_master_tb; endtask // Task to test writing to i2c_slave initial begin - /*new goal: send 1, then decide wether to stop or send 2. both options + /*new goal: read 1, then decide wether to stop or read 2. both options * must be allowed*/ $display("Starting I2C Master test"); initialize_testbench; stop_on_idle = 1; device_3.test_i2c_single_reg_writing(); test_nack_handling(); //killing time for dev3 it needs time to initialize + test_read_weird(); device_3.test_i2c_single_reg_writing(); stop_on_idle = 0; - test_valid_weird(); + test_write_weird(); test_writing(); #1000; //stopping From 79bd7f099d11c81d0c19f267fa0954a34b28af9d Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 9 Jul 2024 12:50:00 +0200 Subject: [PATCH 38/47] fixing bug --- rtl/i2c_phy.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index d9c31ac..be21068 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -315,7 +315,7 @@ module i2c_phy ( end - always @(posedge clk or negedge rst) begin + always @(posedge clk or posedge rst) begin if (rst) begin phy_rx_data_reg <= 1'b0; From bf545bc28a33b37f6de955b139a23ea53e338d75 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Tue, 9 Jul 2024 12:53:05 +0200 Subject: [PATCH 39/47] fix master --- rtl/i2c_master.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 652eb33..d53311d 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -654,7 +654,7 @@ I/O pin. This would prevent devices from stretching the clock period. ); - always @(posedge clk or negedge rst) begin + always @(posedge clk or posedge rst) begin if (rst) begin state_reg <= STATE_IDLE; s_axis_cmd_ready_reg <= 1'b0; From 6968834c9f61ff3e76a94135f029dd840bbef7a1 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Fri, 12 Jul 2024 22:29:44 +0200 Subject: [PATCH 40/47] adding parameter debug --- rtl/i2c_single_reg.v | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index e286f75..94c65a3 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -33,7 +33,8 @@ THE SOFTWARE. */ module i2c_single_reg #( parameter FILTER_LEN = 4, - parameter DEV_ADDR = 7'h70 + parameter DEV_ADDR = 7'h70, + parameter DEBUG = 0 ) ( input wire clk, input wire rst, @@ -137,7 +138,10 @@ module i2c_single_reg #( end else begin // check address mode_read_reg <= sda_i_reg; + if(DEBUG) + $display("i2c single reg: received address %h",shift_reg[6:0]); if (shift_reg[6:0] == DEV_ADDR) begin + // it's a match, send ACK state_reg <= STATE_ACK; end else begin @@ -186,6 +190,7 @@ module i2c_single_reg #( state_reg <= STATE_WRITE_2; end else begin data_reg <= {shift_reg[6:0], sda_i_reg}; + if (DEBUG) $display("i2c single reg: Received data: %h",{shift_reg[6:0], sda_i_reg}); state_reg <= STATE_ACK; end end else begin @@ -234,7 +239,10 @@ module i2c_single_reg #( state_reg <= STATE_READ_3; end end - default: $display("default output of i2c_single_reg triggered atm this does nothing"); + default: begin + if (DEBUG) + $display("default output of i2c_single_reg triggered atm this does nothing"); + end endcase end From 14a86484047c85dff717f845b02e8ae00999fa17 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Fri, 12 Jul 2024 22:45:49 +0200 Subject: [PATCH 41/47] explicit debug statement --- tb/i2c_master_tb.v | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index 2554485..87a5d3c 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -88,7 +88,8 @@ module i2c_master_tb; i2c_single_reg #( .FILTER_LEN(4), - .DEV_ADDR (7'h70) + .DEV_ADDR (7'h70), + .DEBUG(1) ) i2c_reg ( .clk(clk), .rst(rst), From 72fc6bc4522f2f14e53b1f2f5d21160ada6a93c5 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 13 Jul 2024 10:53:53 +0200 Subject: [PATCH 42/47] negative reset --- rtl/i2c_master.v | 8 ++++---- rtl/i2c_phy.v | 6 +++--- rtl/i2c_phy_tb.sv | 10 +++++----- rtl/i2c_single_reg.v | 6 +++--- rtl/i2c_slave.v | 6 +++--- tb/i2c_master_tb.v | 8 +++++--- 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index d53311d..be0936f 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -31,7 +31,7 @@ THE SOFTWARE. */ module i2c_master ( input wire clk, - input wire rst, + input wire rst_n, /* * Host interface @@ -633,7 +633,7 @@ I/O pin. This would prevent devices from stretching the clock period. i2c_phy phy_instance ( .clk(clk), - .rst(rst), + .rst_n, .phy_start_bit(phy_start_bit), .phy_stop_bit(phy_stop_bit), .phy_write_bit(phy_write_bit), @@ -654,8 +654,8 @@ I/O pin. This would prevent devices from stretching the clock period. ); - always @(posedge clk or posedge rst) begin - if (rst) begin + always @(posedge clk or negedge rst_n) begin + if (~rst_n) begin state_reg <= STATE_IDLE; s_axis_cmd_ready_reg <= 1'b0; s_axis_data_tready_reg <= 1'b0; diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v index be21068..b92b18c 100644 --- a/rtl/i2c_phy.v +++ b/rtl/i2c_phy.v @@ -2,7 +2,7 @@ `timescale 1ns / 1ps module i2c_phy ( input wire clk, - input wire rst, + input wire rst_n, // Control signals input wire phy_start_bit, @@ -315,9 +315,9 @@ module i2c_phy ( end - always @(posedge clk or posedge rst) begin + always @(posedge clk or negedge rst_n) begin - if (rst) begin + if (~rst_n) begin phy_rx_data_reg <= 1'b0; phy_state_reg <= PHY_STATE_IDLE; delay_reg <= 17'd0; diff --git a/rtl/i2c_phy_tb.sv b/rtl/i2c_phy_tb.sv index 463e063..651018e 100644 --- a/rtl/i2c_phy_tb.sv +++ b/rtl/i2c_phy_tb.sv @@ -7,7 +7,7 @@ module i2c_phy_tb; // Signals reg clk = 0; - reg rst = 0; + reg rst = 1; reg phy_start_bit = 0; reg phy_stop_bit = 0; reg phy_write_bit = 0; @@ -62,7 +62,7 @@ module i2c_phy_tb; // Instantiate the i2c_phy module i2c_phy uut ( .clk(clk), - .rst(rst), + .rst(rst_n), .phy_start_bit(phy_start_bit), .phy_stop_bit(phy_stop_bit), .phy_write_bit(phy_write_bit), @@ -83,7 +83,7 @@ module i2c_phy_tb; ); task initialize; begin - rst = 1; + rst = 0; phy_start_bit = 0; phy_stop_bit = 0; phy_write_bit = 0; @@ -95,10 +95,10 @@ module i2c_phy_tb; task reset; begin - rst = 1; - #(CLK_PERIOD * 5); rst = 0; #(CLK_PERIOD * 5); + rst = 1; + #(CLK_PERIOD * 5); end endtask task write_operation(input tx_data); diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index 94c65a3..b2401f3 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -37,7 +37,7 @@ module i2c_single_reg #( parameter DEBUG = 0 ) ( input wire clk, - input wire rst, + input wire rst_n, /* * I2C interface @@ -102,8 +102,8 @@ module i2c_single_reg #( wire start_bit = sda_negedge && scl_i_reg; wire stop_bit = sda_posedge && scl_i_reg; - always @(posedge clk or negedge rst) begin - if (rst) begin + always @(posedge clk or negedge rst_n) begin + if (~rst_n) begin state_reg <= STATE_IDLE; sda_o_reg <= 1'b1; end else begin diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index 63a4f6b..40db57f 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -33,7 +33,7 @@ module i2c_slave #( parameter FILTER_LEN = 4 ) ( input wire clk, - input wire rst, + input wire rst_n, /* * Host interface @@ -446,8 +446,8 @@ I/O pin. This would prevent devices from stretching the clock period. end end - always @(posedge clk or negedge rst) begin - if (rst) begin + always @(posedge clk or negedge rst_n) begin + if (~rst_n) begin state_reg <= STATE_IDLE; s_axis_data_tready_reg <= 1'b0; m_axis_data_tvalid_reg <= 1'b0; diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v index 87a5d3c..5690f9f 100644 --- a/tb/i2c_master_tb.v +++ b/tb/i2c_master_tb.v @@ -15,6 +15,8 @@ module i2c_master_tb; reg clk = 0; reg rst = 0; + wire rst_n; + assign rst_n=~rst; reg [7:0] current_test = 0; // I2C master signals @@ -92,7 +94,7 @@ module i2c_master_tb; .DEBUG(1) ) i2c_reg ( .clk(clk), - .rst(rst), + .rst_n, .scl_i(scl_wire), .scl_o(scl_o_3), .scl_t(scl_t_3), @@ -184,7 +186,7 @@ module i2c_master_tb; .FILTER_LEN(4) ) i2c_slave_inst ( .clk(clk), - .rst(rst), + .rst_n, .release_bus(release_bus_4), .s_axis_data_tdata(s_axis_data_tdata_4), .s_axis_data_tvalid(s_axis_data_tvalid_4), @@ -363,7 +365,7 @@ module i2c_master_tb; i2c_master UUT ( .clk(clk), - .rst(rst), + .rst_n, .s_axis_cmd_address(s_axis_cmd_address), .s_axis_cmd_start(s_axis_cmd_start), .s_axis_cmd_read(s_axis_cmd_read), From 7688744a67bd3828c4701bdd65f68334ae487cff Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sat, 13 Jul 2024 22:11:45 +0200 Subject: [PATCH 43/47] make conditionally verbose, otherwise, too verbose! --- rtl/i2c_master.v | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index be0936f..8ba7e7e 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -29,7 +29,9 @@ THE SOFTWARE. /* * I2C master */ -module i2c_master ( +module i2c_master #( + parameter DEBUG = 0 +)( input wire clk, input wire rst_n, @@ -394,7 +396,7 @@ I/O pin. This would prevent devices from stretching the clock period. end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin // stop command phy_stop_bit = 1'b1; - $display("from active write to idle? why?"); + if (DEBUG) $display("from active write to idle? why?"); state_next = STATE_IDLE; end else begin // invalid or unspecified - ignore @@ -433,7 +435,7 @@ I/O pin. This would prevent devices from stretching the clock period. // address or mode mismatch or forced start - repeated start // write nack for previous read - $display("mode mismatch forced restart, write nack"); + if (DEBUG) $display("mode mismatch forced restart, write nack"); phy_write_bit = 1'b1; phy_tx_data = 1'b1; // repeated start bit @@ -441,7 +443,7 @@ I/O pin. This would prevent devices from stretching the clock period. end else begin // address and mode match - $display("sending ack and continue with next read"); + if (DEBUG) play("sending ack and continue with next read"); // write ack for previous read phy_write_bit = 1'b1; phy_tx_data = 1'b0; @@ -459,7 +461,7 @@ I/O pin. This would prevent devices from stretching the clock period. // send stop bit state_next = STATE_STOP; end else begin - $display("active read: invalid or unspecified - ignore.. ?"); + if (DEBUG) $display("active read: invalid or unspecified - ignore.. ?"); // invalid or unspecified - ignore state_next = STATE_ACTIVE_READ; end @@ -471,7 +473,7 @@ I/O pin. This would prevent devices from stretching the clock period. phy_write_bit = 1'b1; phy_tx_data = 1'b1; // send stop bit - $display("got last bit and received, so stopping"); + if (DEBUG) $display("got last bit and received, so stopping"); state_next = STATE_STOP; end else begin @@ -525,10 +527,10 @@ I/O pin. This would prevent devices from stretching the clock period. // read ack bit missed_ack_next = phy_rx_data_reg; if (missed_ack_next) begin - $display("got NACK"); + if (DEBUG) $display("got NACK"); state_next = STATE_STOP; end else begin - $display("got ACK"); + if (DEBUG) $display("got ACK"); if (mode_read_reg) begin // start read @@ -575,10 +577,10 @@ I/O pin. This would prevent devices from stretching the clock period. // read ack bit missed_ack_next = phy_rx_data_reg; if (missed_ack_next) begin - $display("got NACK on write"); + if (DEBUG) $display("got NACK on write"); state_next = STATE_STOP; end else begin - $display("got ACK on write %d", $time); + if (DEBUG) $display("got ACK on write %d", $time); value_has_been_written_reg = 1; //only if successful! @@ -626,7 +628,7 @@ I/O pin. This would prevent devices from stretching the clock period. phy_stop_bit = 1'b1; state_next = STATE_IDLE; end - default: $display("I don't think case default should get triggered"); + default: if (DEBUG) $display("I don't think case default should get triggered"); endcase end end From 13bfbdc434fd7f328ab16c3c687857fedf78e5ee Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Sun, 14 Jul 2024 01:20:56 +0200 Subject: [PATCH 44/47] verilog does not support implicit params for synth --- rtl/i2c_master.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 8ba7e7e..3ef6953 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -635,7 +635,7 @@ I/O pin. This would prevent devices from stretching the clock period. i2c_phy phy_instance ( .clk(clk), - .rst_n, + .rst_n(rst_n), .phy_start_bit(phy_start_bit), .phy_stop_bit(phy_stop_bit), .phy_write_bit(phy_write_bit), From 205279053592c4b5e11137b4e2e4911ed2be5127 Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Mon, 15 Jul 2024 14:51:02 +0200 Subject: [PATCH 45/47] fixing 1 display --- rtl/i2c_master.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 3ef6953..062f8d5 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -443,7 +443,7 @@ I/O pin. This would prevent devices from stretching the clock period. end else begin // address and mode match - if (DEBUG) play("sending ack and continue with next read"); + if (DEBUG) $display("sending ack and continue with next read"); // write ack for previous read phy_write_bit = 1'b1; phy_tx_data = 1'b0; From 3f8294552d0794ae829540622d0cd7f78692dedd Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Mon, 15 Jul 2024 14:52:43 +0200 Subject: [PATCH 46/47] move from one place to the next --- {rtl => tb}/i2c_phy_tb.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {rtl => tb}/i2c_phy_tb.sv (97%) diff --git a/rtl/i2c_phy_tb.sv b/tb/i2c_phy_tb.sv similarity index 97% rename from rtl/i2c_phy_tb.sv rename to tb/i2c_phy_tb.sv index 651018e..218625d 100644 --- a/rtl/i2c_phy_tb.sv +++ b/tb/i2c_phy_tb.sv @@ -148,7 +148,7 @@ module i2c_phy_tb; read_operation; wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE sda2 = 1; //pull sda2 back up - if (phy_rx_data_reg != 0) $finish("Expecting ACK but found NACK: %d ", phy_rx_data_reg); + if (phy_rx_data_reg != 0) $finish(1,"Expecting ACK but found NACK: %d ", phy_rx_data_reg); end endtask From 3fef99fd1c35f9488f1640f1cb5a198ef0ecf98b Mon Sep 17 00:00:00 2001 From: Kreijstal Date: Mon, 15 Jul 2024 14:53:10 +0200 Subject: [PATCH 47/47] format using verilible --- rtl/i2c_master.v | 2 +- rtl/i2c_single_reg.v | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 062f8d5..7a542f0 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -31,7 +31,7 @@ THE SOFTWARE. */ module i2c_master #( parameter DEBUG = 0 -)( +) ( input wire clk, input wire rst_n, diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index b2401f3..9b5a620 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -33,7 +33,7 @@ THE SOFTWARE. */ module i2c_single_reg #( parameter FILTER_LEN = 4, - parameter DEV_ADDR = 7'h70, + parameter DEV_ADDR = 7'h70, parameter DEBUG = 0 ) ( input wire clk, @@ -138,10 +138,9 @@ module i2c_single_reg #( end else begin // check address mode_read_reg <= sda_i_reg; - if(DEBUG) - $display("i2c single reg: received address %h",shift_reg[6:0]); + if (DEBUG) $display("i2c single reg: received address %h", shift_reg[6:0]); if (shift_reg[6:0] == DEV_ADDR) begin - + // it's a match, send ACK state_reg <= STATE_ACK; end else begin @@ -189,8 +188,9 @@ module i2c_single_reg #( bit_count_reg <= bit_count_reg - 1; state_reg <= STATE_WRITE_2; end else begin - data_reg <= {shift_reg[6:0], sda_i_reg}; - if (DEBUG) $display("i2c single reg: Received data: %h",{shift_reg[6:0], sda_i_reg}); + data_reg <= {shift_reg[6:0], sda_i_reg}; + if (DEBUG) + $display("i2c single reg: Received data: %h", {shift_reg[6:0], sda_i_reg}); state_reg <= STATE_ACK; end end else begin @@ -239,9 +239,8 @@ module i2c_single_reg #( state_reg <= STATE_READ_3; end end - default: begin - if (DEBUG) - $display("default output of i2c_single_reg triggered atm this does nothing"); + default: begin + if (DEBUG) $display("default output of i2c_single_reg triggered atm this does nothing"); end endcase end