[i2c, rtl] Target features addition

1. Interrupt when host fails to complete a transaction
2. Clock stretching by target after a complete transaction (read and/or write)
3. Automatic clock stretching by target when ACQ FIFO is full

Signed-off-by: Igor Kouznetsov <igor.kouznetsov@wdc.com>
diff --git a/hw/ip/i2c/data/i2c.hjson b/hw/ip/i2c/data/i2c.hjson
index a12bf0f..b02c775 100644
--- a/hw/ip/i2c/data/i2c.hjson
+++ b/hw/ip/i2c/data/i2c.hjson
@@ -58,6 +58,9 @@
     { name: "ack_stop"
       desc: "raised if STOP is received after ACK (host sends both signals)."
     }
+    { name: "host_timeout"
+      desc: "raised if the host stops sending the clock during an ongoing transaction."
+    }
   ]
 
   // REGISTER definition
@@ -493,5 +496,36 @@
         { bits: "7:0" }
       ]
     }
+    { name: "STRETCH_CTRL"
+      desc: "I2C target clock stretching control"
+      swaccess: "rw"
+      hwaccess: "hro"
+      fields: [
+        { bits: "0"
+          name: "ENABLEADDR"
+          desc: "Enable clock stretching after address matching completes"
+        }
+        { bits: "1"
+          name: "ENABLETX"
+          desc: "Enable clock stretching after ongoing transmit (read) transaction completes"
+        }
+        { bits: "2"
+          name: "ENABLEACQ"
+          desc: "Enable clock stretching after ongoing acquire (write) transaction completes"
+        }
+        { bits: "3"
+          name: "STOP"
+          desc: "Stop clock stretching and resume normal operation"
+        }
+      ]
+    }
+    { name: "HOST_TIMEOUT_CTRL"
+      desc: "I2C host clock generation timeout value (in units of input clock frequency)"
+      swaccess: "rw"
+      hwaccess: "hro"
+      fields: [
+        { bits: "31:0" }
+      ]
+    }
   ]
 }
diff --git a/hw/ip/i2c/rtl/i2c.sv b/hw/ip/i2c/rtl/i2c.sv
index c24a22e..1b42210 100644
--- a/hw/ip/i2c/rtl/i2c.sv
+++ b/hw/ip/i2c/rtl/i2c.sv
@@ -37,7 +37,8 @@
   output logic              intr_tx_nonempty_o,
   output logic              intr_tx_overflow_o,
   output logic              intr_acq_overflow_o,
-  output logic              intr_ack_stop_o
+  output logic              intr_ack_stop_o,
+  output logic              intr_host_timeout_o
 );
 
   import i2c_reg_pkg::*;
@@ -83,7 +84,8 @@
     .intr_tx_nonempty_o,
     .intr_tx_overflow_o,
     .intr_acq_overflow_o,
-    .intr_ack_stop_o
+    .intr_ack_stop_o,
+    .intr_host_timeout_o
   );
 
   // For I2C, in standard, fast and fast-plus modes, outputs simulated as open-drain outputs.
@@ -117,5 +119,6 @@
   `ASSERT_KNOWN(IntrTxOflwKnownO_A, intr_tx_overflow_o)
   `ASSERT_KNOWN(IntrAcqOflwKnownO_A, intr_acq_overflow_o)
   `ASSERT_KNOWN(IntrAckStopKnownO_A, intr_ack_stop_o)
+  `ASSERT_KNOWN(IntrHostTimeoutKnownO_A, intr_host_timeout_o)
 
 endmodule
diff --git a/hw/ip/i2c/rtl/i2c_core.sv b/hw/ip/i2c/rtl/i2c_core.sv
index 32a6e97..ec3092a 100644
--- a/hw/ip/i2c/rtl/i2c_core.sv
+++ b/hw/ip/i2c/rtl/i2c_core.sv
@@ -30,7 +30,8 @@
   output logic                     intr_tx_nonempty_o,
   output logic                     intr_tx_overflow_o,
   output logic                     intr_acq_overflow_o,
-  output logic                     intr_ack_stop_o
+  output logic                     intr_ack_stop_o,
+  output logic                     intr_host_timeout_o
 );
 
   logic [15:0] thigh;
@@ -45,6 +46,11 @@
   logic [15:0] t_buf;
   logic [30:0] stretch_timeout;
   logic        timeout_enable;
+  logic        stretch_en_addr;
+  logic        stretch_en_tx;
+  logic        stretch_en_acq;
+  logic        stretch_stop;
+  logic [31:0] host_timeout;
 
   logic scl_out_fsm;
   logic sda_out_fsm;
@@ -64,6 +70,7 @@
   logic event_tx_overflow;
   logic event_acq_overflow;
   logic event_ack_stop;
+  logic event_host_timeout;
 
   logic [15:0] scl_rx_val;
   logic [15:0] sda_rx_val;
@@ -196,6 +203,11 @@
   assign t_buf           = reg2hw.timing4.t_buf.q;
   assign stretch_timeout = reg2hw.timeout_ctrl.val.q;
   assign timeout_enable  = reg2hw.timeout_ctrl.en.q;
+  assign stretch_en_addr = reg2hw.stretch_ctrl.enableaddr.q;
+  assign stretch_en_tx   = reg2hw.stretch_ctrl.enabletx.q;
+  assign stretch_en_acq  = reg2hw.stretch_ctrl.enableacq.q;
+  assign stretch_stop    = reg2hw.stretch_ctrl.stop.q;
+  assign host_timeout    = reg2hw.host_timeout_ctrl.q;
 
   assign i2c_fifo_rxrst   = reg2hw.fifo_ctrl.rxrst.q & reg2hw.fifo_ctrl.rxrst.qe;
   assign i2c_fifo_fmtrst  = reg2hw.fifo_ctrl.fmtrst.q & reg2hw.fifo_ctrl.fmtrst.qe;
@@ -384,6 +396,7 @@
     .tx_fifo_rready_o        (tx_fifo_rready),
     .tx_fifo_rdata_i         (tx_fifo_rdata),
 
+    .acq_fifo_wready_i       (acq_fifo_wready),
     .acq_fifo_wvalid_o       (acq_fifo_wvalid),
     .acq_fifo_wdata_o        (acq_fifo_wdata),
 
@@ -402,6 +415,11 @@
     .t_buf_i                 (t_buf),
     .stretch_timeout_i       (stretch_timeout),
     .timeout_enable_i        (timeout_enable),
+    .stretch_en_addr_i       (stretch_en_addr),
+    .stretch_en_tx_i         (stretch_en_tx),
+    .stretch_en_acq_i        (stretch_en_acq),
+    .stretch_stop_i          (stretch_stop),
+    .host_timeout_i          (host_timeout),
 
     .target_address0_i       (target_address0),
     .target_mask0_i          (target_mask0),
@@ -416,7 +434,8 @@
     .event_trans_complete_o  (event_trans_complete),
     .event_tx_empty_o        (event_tx_empty),
     .event_tx_nonempty_o     (event_tx_nonempty),
-    .event_ack_stop_o        (event_ack_stop)
+    .event_ack_stop_o        (event_ack_stop),
+    .event_host_timeout_o    (event_host_timeout)
   );
 
   prim_intr_hw #(.Width(1)) intr_hw_fmt_watermark (
@@ -614,4 +633,17 @@
     .intr_o                 (intr_ack_stop_o)
   );
 
+  prim_intr_hw #(.Width(1)) intr_hw_host_timeout (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (event_host_timeout),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.host_timeout.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.host_timeout.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.host_timeout.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.host_timeout.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.host_timeout.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.host_timeout.d),
+    .intr_o                 (intr_host_timeout_o)
+  );
+
 endmodule
diff --git a/hw/ip/i2c/rtl/i2c_fsm.sv b/hw/ip/i2c/rtl/i2c_fsm.sv
index 7bc7d9b..da2f3c6 100644
--- a/hw/ip/i2c/rtl/i2c_fsm.sv
+++ b/hw/ip/i2c/rtl/i2c_fsm.sv
@@ -36,6 +36,7 @@
   output logic tx_fifo_rready_o, // populates tx_fifo
   input [7:0]  tx_fifo_rdata_i,  // byte in tx_fifo to be sent to host
 
+  input  logic       acq_fifo_wready_i, // low if acq_fifo is full
   output logic       acq_fifo_wvalid_o, // high if there is valid data in acq_fifo
   output logic [9:0] acq_fifo_wdata_o,  // byte and signal in acq_fifo read from target
 
@@ -54,6 +55,11 @@
   input [15:0] t_buf_i,    // bus free time between STOP and START in clock units
   input [30:0] stretch_timeout_i,  // max time target may stretch the clock
   input        timeout_enable_i,   // assert if target stretches clock past max
+  input        stretch_en_addr_i,  // enable target stretching clock after address matching
+  input        stretch_en_tx_i,    // enable target stretching clock after transmit transaction
+  input        stretch_en_acq_i,   // enable target stretching clock after acquire transaction
+  input        stretch_stop_i,     // stop stretching clock and resume normal operation
+  input [31:0] host_timeout_i,     // max time target waits for host to pull clock down
 
   input logic [6:0] target_address0_i,
   input logic [6:0] target_mask0_i,
@@ -68,7 +74,8 @@
   output logic event_trans_complete_o,   // Transaction is complete
   output logic event_tx_empty_o,         // tx_fifo is empty but data is needed
   output logic event_tx_nonempty_o,      // tx_fifo is nonempty after stop
-  output logic event_ack_stop_o          // target received stop after ack
+  output logic event_ack_stop_o,         // target received stop after ack
+  output logic event_host_timeout_o      // host ceased sending SCL pulses during ongoing transactn
 );
 
   // I2C bus clock timing variables
@@ -107,6 +114,7 @@
   logic        address_match; // indicates one of target's addresses matches the one sent by host
   logic [7:0]  input_byte;    // register for reads from host
   logic        input_byte_clr;// clear input_byte contents
+  logic [31:0] scl_high_cnt;  // counter for continuously released scl_i
 
   // Target bit counter variables
   logic [3:0]  bit_idx;       // bit index including ack/nack
@@ -273,6 +281,17 @@
     end
   end
 
+  // Counter for continuously released SCL state
+  always_ff @ (posedge clk_i or negedge rst_ni) begin : scl_high_counter
+    if (!rst_ni) begin
+      scl_high_cnt <= 32'd0;
+    end else if (scl_i) begin
+      scl_high_cnt <= scl_high_cnt + 1'b1;
+    end else begin
+      scl_high_cnt <= 32'd0;
+    end
+  end
+
   // Deserializer for a byte read from the bus on the target side
   assign address0_match = ((input_byte[7:1] & target_mask0_i) == target_address0_i);
   assign address1_match = ((input_byte[7:1] & target_mask1_i) == target_address1_i);
@@ -310,7 +329,8 @@
         AddrRead, AddrAckWait, AddrAckSetup, AddrAckPulse, AddrAckHold,
         TransmitWait, TransmitSetup, TransmitPulse, TransmitHold, TransmitAck,
         AcquireByte, AcquireAckWait, AcquireAckSetup, AcquireAckPulse, AcquireAckHold,
-        PopTxFifo, StretchClock, AcquireSrP
+        PopTxFifo, AcquireSrP, StretchTxEmpty, StretchAcqFull, StretchAddr,
+        StretchAcquire, StretchTransmit
   } state_e;
 
   state_e state_q, state_d;
@@ -587,13 +607,6 @@
         target_idle_o = 1'b0;
         tx_fifo_rready_o = 1'b1;
       end
-      // StretchClock: target stretches the clock
-      StretchClock : begin
-        target_idle_o = 1'b0;
-        tx_fifo_rready_o = 1'b1;
-        scl_temp = 1'b0;
-        if (tx_fifo_depth_i == '0) event_tx_empty_o = 1'b1;
-      end
       // AcquireByte: target acquires a byte
       AcquireByte : begin
         target_idle_o = 1'b0;
@@ -628,6 +641,33 @@
         acq_fifo_wvalid_o = 1'b1;
         if (tx_fifo_depth_i != '0) event_tx_nonempty_o = 1'b1;
       end
+      // StretchAddr: target stretches the clock after matching an address
+      StretchAddr : begin
+        target_idle_o = 1'b0;
+        scl_temp = 1'b0;
+      end
+      // StretchAcquire: target stretches the clock after acquiring a byte
+      StretchAcquire : begin
+        target_idle_o = 1'b0;
+        scl_temp = 1'b0;
+      end
+      // StretchTransmit: target stretches the clock after transmitting a byte
+      StretchTransmit : begin
+        target_idle_o = 1'b0;
+        scl_temp = 1'b0;
+      end
+      // StretchTxEmpty: target stretches the clock when tx_fifo is empty
+      StretchTxEmpty : begin
+        target_idle_o = 1'b0;
+        tx_fifo_rready_o = 1'b1;
+        scl_temp = 1'b0;
+        if (tx_fifo_depth_i == '0) event_tx_empty_o = 1'b1;
+      end
+      // StretchAcqFull: target stretches the clock when acq_fifo is full
+      StretchAcqFull : begin
+        target_idle_o = 1'b0;
+        scl_temp = 1'b0;
+      end
       // default
       default : begin
         host_idle_o = 1'b1;
@@ -958,7 +998,8 @@
       // AddrAckWait: pause before acknowledging
       AddrAckWait : begin
         if (tcount_q == 20'd1) begin
-          state_d = AddrAckSetup;
+          if (stretch_en_addr_i) state_d = StretchAddr;
+          else state_d = AddrAckSetup;
         end
       end
       // AddrAckSetup: target pulls SDA low while SCL is low
@@ -981,8 +1022,11 @@
               state_d = TransmitWait;
               load_tcount = 1'b1;
               tcount_sel = tClockLow;
-            end else state_d = StretchClock;
-          end else state_d = AcquireByte;
+            end else state_d = StretchTxEmpty;
+          end else begin
+            if (acq_fifo_wready_i) state_d = AcquireByte;
+            else state_d = StretchAcqFull;
+          end
         end
       end
 
@@ -1019,8 +1063,10 @@
       // TransmitAck: target waits for host to ACK transmission
       TransmitAck : begin
         if (scl_i) begin
-          if (host_ack) state_d = PopTxFifo;
-          else begin
+          if (host_ack) begin
+            if (stretch_en_tx_i) state_d = StretchTransmit;
+            else state_d = PopTxFifo;
+          end else begin
             if (start_det || stop_det) state_d = AcquireSrP;
           end
         end
@@ -1031,18 +1077,7 @@
         if (!target_enable_i) begin
           state_d = Idle;
         end else if (tx_fifo_depth_i == 6'd1 && !tx_fifo_wvalid_i) begin
-          state_d = StretchClock;
-        end else begin
-          state_d = TransmitWait;
-          load_tcount = 1'b1;
-          tcount_sel = tClockLow;
-        end
-      end
-
-      // StretchClock: target stretches the clock
-      StretchClock : begin
-        if (tx_fifo_depth_i == '0) begin
-          state_d = StretchClock;
+          state_d = StretchTxEmpty;
         end else begin
           state_d = TransmitWait;
           load_tcount = 1'b1;
@@ -1062,7 +1097,8 @@
       // AcquireAckWait: pause before acknowledging
       AcquireAckWait : begin
         if (tcount_q == 20'd1) begin
-          state_d = AcquireAckSetup;
+          if (stretch_en_acq_i) state_d = StretchAcquire;
+          else state_d = AcquireAckSetup;
         end
       end
       // AcquireAckSetup: target pulls SDA low while SCL is low
@@ -1092,6 +1128,41 @@
         state_d = Idle;
       end
 
+      // StretchAddr: target stretches the clock after matching an address
+      StretchAddr : begin
+        if (!stretch_stop_i) state_d = StretchAddr;
+        else state_d = AddrAckSetup;
+      end
+
+      // StretchAcquire: target stretches the clock after acquiring a byte
+      StretchAcquire : begin
+        if (!stretch_stop_i) state_d = StretchAcquire;
+        else state_d = AcquireAckSetup;
+      end
+
+      // StretchTransmit: target stretches the clock after transmitting a byte
+      StretchTransmit : begin
+        if (!stretch_stop_i) state_d = StretchTransmit;
+        else state_d = PopTxFifo;
+      end
+
+      // StretchTxEmpty: target stretches the clock when tx_fifo is empty
+      StretchTxEmpty : begin
+        if (tx_fifo_depth_i == '0) begin
+          state_d = StretchTxEmpty;
+        end else begin
+          state_d = TransmitWait;
+          load_tcount = 1'b1;
+          tcount_sel = tClockLow;
+        end
+      end
+
+      // StretchAcqFull: target stretches the clock when acq_fifo is full
+      StretchAcqFull : begin
+        if (acq_fifo_wready_i) state_d = AcquireByte;
+        else state_d = StretchAcqFull;
+      end
+
       // default
       default : begin
         state_d = Idle;
@@ -1124,4 +1195,7 @@
   assign scl_o = scl_temp;
   assign sda_o = sda_temp;
 
+  // Host ceased sending SCL pulses during ongoing transaction
+  assign event_host_timeout_o = (!target_idle_o & (scl_high_cnt > host_timeout_i)) ? 1'b1 : 1'b0;
+
 endmodule
diff --git a/hw/ip/i2c/rtl/i2c_reg_pkg.sv b/hw/ip/i2c/rtl/i2c_reg_pkg.sv
index 5b4770a..08c0772 100644
--- a/hw/ip/i2c/rtl/i2c_reg_pkg.sv
+++ b/hw/ip/i2c/rtl/i2c_reg_pkg.sv
@@ -58,6 +58,9 @@
     struct packed {
       logic        q;
     } ack_stop;
+    struct packed {
+      logic        q;
+    } host_timeout;
   } i2c_reg2hw_intr_state_reg_t;
 
   typedef struct packed {
@@ -106,6 +109,9 @@
     struct packed {
       logic        q;
     } ack_stop;
+    struct packed {
+      logic        q;
+    } host_timeout;
   } i2c_reg2hw_intr_enable_reg_t;
 
   typedef struct packed {
@@ -169,6 +175,10 @@
       logic        q;
       logic        qe;
     } ack_stop;
+    struct packed {
+      logic        q;
+      logic        qe;
+    } host_timeout;
   } i2c_reg2hw_intr_test_reg_t;
 
   typedef struct packed {
@@ -336,6 +346,25 @@
     logic        qe;
   } i2c_reg2hw_txdata_reg_t;
 
+  typedef struct packed {
+    struct packed {
+      logic        q;
+    } enableaddr;
+    struct packed {
+      logic        q;
+    } enabletx;
+    struct packed {
+      logic        q;
+    } enableacq;
+    struct packed {
+      logic        q;
+    } stop;
+  } i2c_reg2hw_stretch_ctrl_reg_t;
+
+  typedef struct packed {
+    logic [31:0] q;
+  } i2c_reg2hw_host_timeout_ctrl_reg_t;
+
 
   typedef struct packed {
     struct packed {
@@ -398,6 +427,10 @@
       logic        d;
       logic        de;
     } ack_stop;
+    struct packed {
+      logic        d;
+      logic        de;
+    } host_timeout;
   } i2c_hw2reg_intr_state_reg_t;
 
   typedef struct packed {
@@ -475,30 +508,32 @@
   // Register to internal design logic //
   ///////////////////////////////////////
   typedef struct packed {
-    i2c_reg2hw_intr_state_reg_t intr_state; // [348:334]
-    i2c_reg2hw_intr_enable_reg_t intr_enable; // [333:319]
-    i2c_reg2hw_intr_test_reg_t intr_test; // [318:289]
-    i2c_reg2hw_ctrl_reg_t ctrl; // [288:287]
-    i2c_reg2hw_rdata_reg_t rdata; // [286:278]
-    i2c_reg2hw_fdata_reg_t fdata; // [277:259]
-    i2c_reg2hw_fifo_ctrl_reg_t fifo_ctrl; // [258:244]
-    i2c_reg2hw_ovrd_reg_t ovrd; // [243:241]
-    i2c_reg2hw_timing0_reg_t timing0; // [240:209]
-    i2c_reg2hw_timing1_reg_t timing1; // [208:177]
-    i2c_reg2hw_timing2_reg_t timing2; // [176:145]
-    i2c_reg2hw_timing3_reg_t timing3; // [144:113]
-    i2c_reg2hw_timing4_reg_t timing4; // [112:81]
-    i2c_reg2hw_timeout_ctrl_reg_t timeout_ctrl; // [80:49]
-    i2c_reg2hw_target_id_reg_t target_id; // [48:21]
-    i2c_reg2hw_acqdata_reg_t acqdata; // [20:9]
-    i2c_reg2hw_txdata_reg_t txdata; // [8:0]
+    i2c_reg2hw_intr_state_reg_t intr_state; // [388:373]
+    i2c_reg2hw_intr_enable_reg_t intr_enable; // [372:357]
+    i2c_reg2hw_intr_test_reg_t intr_test; // [356:325]
+    i2c_reg2hw_ctrl_reg_t ctrl; // [324:323]
+    i2c_reg2hw_rdata_reg_t rdata; // [322:314]
+    i2c_reg2hw_fdata_reg_t fdata; // [313:295]
+    i2c_reg2hw_fifo_ctrl_reg_t fifo_ctrl; // [294:280]
+    i2c_reg2hw_ovrd_reg_t ovrd; // [279:277]
+    i2c_reg2hw_timing0_reg_t timing0; // [276:245]
+    i2c_reg2hw_timing1_reg_t timing1; // [244:213]
+    i2c_reg2hw_timing2_reg_t timing2; // [212:181]
+    i2c_reg2hw_timing3_reg_t timing3; // [180:149]
+    i2c_reg2hw_timing4_reg_t timing4; // [148:117]
+    i2c_reg2hw_timeout_ctrl_reg_t timeout_ctrl; // [116:85]
+    i2c_reg2hw_target_id_reg_t target_id; // [84:57]
+    i2c_reg2hw_acqdata_reg_t acqdata; // [56:45]
+    i2c_reg2hw_txdata_reg_t txdata; // [44:36]
+    i2c_reg2hw_stretch_ctrl_reg_t stretch_ctrl; // [35:32]
+    i2c_reg2hw_host_timeout_ctrl_reg_t host_timeout_ctrl; // [31:0]
   } i2c_reg2hw_t;
 
   ///////////////////////////////////////
   // Internal design logic to register //
   ///////////////////////////////////////
   typedef struct packed {
-    i2c_hw2reg_intr_state_reg_t intr_state; // [113:84]
+    i2c_hw2reg_intr_state_reg_t intr_state; // [115:84]
     i2c_hw2reg_status_reg_t status; // [83:74]
     i2c_hw2reg_rdata_reg_t rdata; // [73:66]
     i2c_hw2reg_fifo_status_reg_t fifo_status; // [65:42]
@@ -527,6 +562,8 @@
   parameter logic [BlockAw-1:0] I2C_TARGET_ID_OFFSET = 7'h 44;
   parameter logic [BlockAw-1:0] I2C_ACQDATA_OFFSET = 7'h 48;
   parameter logic [BlockAw-1:0] I2C_TXDATA_OFFSET = 7'h 4c;
+  parameter logic [BlockAw-1:0] I2C_STRETCH_CTRL_OFFSET = 7'h 50;
+  parameter logic [BlockAw-1:0] I2C_HOST_TIMEOUT_CTRL_OFFSET = 7'h 54;
 
 
   // Register Index
@@ -550,11 +587,13 @@
     I2C_TIMEOUT_CTRL,
     I2C_TARGET_ID,
     I2C_ACQDATA,
-    I2C_TXDATA
+    I2C_TXDATA,
+    I2C_STRETCH_CTRL,
+    I2C_HOST_TIMEOUT_CTRL
   } i2c_id_e;
 
   // Register width information to check illegal writes
-  parameter logic [3:0] I2C_PERMIT [20] = '{
+  parameter logic [3:0] I2C_PERMIT [22] = '{
     4'b 0011, // index[ 0] I2C_INTR_STATE
     4'b 0011, // index[ 1] I2C_INTR_ENABLE
     4'b 0011, // index[ 2] I2C_INTR_TEST
@@ -574,7 +613,9 @@
     4'b 1111, // index[16] I2C_TIMEOUT_CTRL
     4'b 1111, // index[17] I2C_TARGET_ID
     4'b 0011, // index[18] I2C_ACQDATA
-    4'b 0001  // index[19] I2C_TXDATA
+    4'b 0001, // index[19] I2C_TXDATA
+    4'b 0001, // index[20] I2C_STRETCH_CTRL
+    4'b 1111  // index[21] I2C_HOST_TIMEOUT_CTRL
   };
 endpackage
 
diff --git a/hw/ip/i2c/rtl/i2c_reg_top.sv b/hw/ip/i2c/rtl/i2c_reg_top.sv
index 3bbbbcd..7a3c3fc 100644
--- a/hw/ip/i2c/rtl/i2c_reg_top.sv
+++ b/hw/ip/i2c/rtl/i2c_reg_top.sv
@@ -116,6 +116,9 @@
   logic intr_state_ack_stop_qs;
   logic intr_state_ack_stop_wd;
   logic intr_state_ack_stop_we;
+  logic intr_state_host_timeout_qs;
+  logic intr_state_host_timeout_wd;
+  logic intr_state_host_timeout_we;
   logic intr_enable_fmt_watermark_qs;
   logic intr_enable_fmt_watermark_wd;
   logic intr_enable_fmt_watermark_we;
@@ -161,6 +164,9 @@
   logic intr_enable_ack_stop_qs;
   logic intr_enable_ack_stop_wd;
   logic intr_enable_ack_stop_we;
+  logic intr_enable_host_timeout_qs;
+  logic intr_enable_host_timeout_wd;
+  logic intr_enable_host_timeout_we;
   logic intr_test_fmt_watermark_wd;
   logic intr_test_fmt_watermark_we;
   logic intr_test_rx_watermark_wd;
@@ -191,6 +197,8 @@
   logic intr_test_acq_overflow_we;
   logic intr_test_ack_stop_wd;
   logic intr_test_ack_stop_we;
+  logic intr_test_host_timeout_wd;
+  logic intr_test_host_timeout_we;
   logic ctrl_enablehost_qs;
   logic ctrl_enablehost_wd;
   logic ctrl_enablehost_we;
@@ -320,6 +328,21 @@
   logic acqdata_signal_re;
   logic [7:0] txdata_wd;
   logic txdata_we;
+  logic stretch_ctrl_enableaddr_qs;
+  logic stretch_ctrl_enableaddr_wd;
+  logic stretch_ctrl_enableaddr_we;
+  logic stretch_ctrl_enabletx_qs;
+  logic stretch_ctrl_enabletx_wd;
+  logic stretch_ctrl_enabletx_we;
+  logic stretch_ctrl_enableacq_qs;
+  logic stretch_ctrl_enableacq_wd;
+  logic stretch_ctrl_enableacq_we;
+  logic stretch_ctrl_stop_qs;
+  logic stretch_ctrl_stop_wd;
+  logic stretch_ctrl_stop_we;
+  logic [31:0] host_timeout_ctrl_qs;
+  logic [31:0] host_timeout_ctrl_wd;
+  logic host_timeout_ctrl_we;
 
   // Register instances
   // R[intr_state]: V(False)
@@ -714,6 +737,32 @@
   );
 
 
+  //   F[host_timeout]: 15:15
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W1C"),
+    .RESVAL  (1'h0)
+  ) u_intr_state_host_timeout (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (intr_state_host_timeout_we),
+    .wd     (intr_state_host_timeout_wd),
+
+    // from internal hardware
+    .de     (hw2reg.intr_state.host_timeout.de),
+    .d      (hw2reg.intr_state.host_timeout.d ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.intr_state.host_timeout.q ),
+
+    // to register interface (read)
+    .qs     (intr_state_host_timeout_qs)
+  );
+
+
   // R[intr_enable]: V(False)
 
   //   F[fmt_watermark]: 0:0
@@ -1106,6 +1155,32 @@
   );
 
 
+  //   F[host_timeout]: 15:15
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_intr_enable_host_timeout (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (intr_enable_host_timeout_we),
+    .wd     (intr_enable_host_timeout_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.intr_enable.host_timeout.q ),
+
+    // to register interface (read)
+    .qs     (intr_enable_host_timeout_qs)
+  );
+
+
   // R[intr_test]: V(True)
 
   //   F[fmt_watermark]: 0:0
@@ -1333,6 +1408,21 @@
   );
 
 
+  //   F[host_timeout]: 15:15
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_intr_test_host_timeout (
+    .re     (1'b0),
+    .we     (intr_test_host_timeout_we),
+    .wd     (intr_test_host_timeout_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.intr_test.host_timeout.qe),
+    .q      (reg2hw.intr_test.host_timeout.q ),
+    .qs     ()
+  );
+
+
   // R[ctrl]: V(False)
 
   //   F[enablehost]: 0:0
@@ -2523,9 +2613,142 @@
   );
 
 
+  // R[stretch_ctrl]: V(False)
+
+  //   F[enableaddr]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_stretch_ctrl_enableaddr (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (stretch_ctrl_enableaddr_we),
+    .wd     (stretch_ctrl_enableaddr_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.stretch_ctrl.enableaddr.q ),
+
+    // to register interface (read)
+    .qs     (stretch_ctrl_enableaddr_qs)
+  );
 
 
-  logic [19:0] addr_hit;
+  //   F[enabletx]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_stretch_ctrl_enabletx (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (stretch_ctrl_enabletx_we),
+    .wd     (stretch_ctrl_enabletx_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.stretch_ctrl.enabletx.q ),
+
+    // to register interface (read)
+    .qs     (stretch_ctrl_enabletx_qs)
+  );
+
+
+  //   F[enableacq]: 2:2
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_stretch_ctrl_enableacq (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (stretch_ctrl_enableacq_we),
+    .wd     (stretch_ctrl_enableacq_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.stretch_ctrl.enableacq.q ),
+
+    // to register interface (read)
+    .qs     (stretch_ctrl_enableacq_qs)
+  );
+
+
+  //   F[stop]: 3:3
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_stretch_ctrl_stop (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (stretch_ctrl_stop_we),
+    .wd     (stretch_ctrl_stop_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.stretch_ctrl.stop.q ),
+
+    // to register interface (read)
+    .qs     (stretch_ctrl_stop_qs)
+  );
+
+
+  // R[host_timeout_ctrl]: V(False)
+
+  prim_subreg #(
+    .DW      (32),
+    .SWACCESS("RW"),
+    .RESVAL  (32'h0)
+  ) u_host_timeout_ctrl (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (host_timeout_ctrl_we),
+    .wd     (host_timeout_ctrl_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.host_timeout_ctrl.q ),
+
+    // to register interface (read)
+    .qs     (host_timeout_ctrl_qs)
+  );
+
+
+
+
+  logic [21:0] addr_hit;
   always_comb begin
     addr_hit = '0;
     addr_hit[ 0] = (reg_addr == I2C_INTR_STATE_OFFSET);
@@ -2548,6 +2771,8 @@
     addr_hit[17] = (reg_addr == I2C_TARGET_ID_OFFSET);
     addr_hit[18] = (reg_addr == I2C_ACQDATA_OFFSET);
     addr_hit[19] = (reg_addr == I2C_TXDATA_OFFSET);
+    addr_hit[20] = (reg_addr == I2C_STRETCH_CTRL_OFFSET);
+    addr_hit[21] = (reg_addr == I2C_HOST_TIMEOUT_CTRL_OFFSET);
   end
 
   assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
@@ -2575,6 +2800,8 @@
     if (addr_hit[17] && reg_we && (I2C_PERMIT[17] != (I2C_PERMIT[17] & reg_be))) wr_err = 1'b1 ;
     if (addr_hit[18] && reg_we && (I2C_PERMIT[18] != (I2C_PERMIT[18] & reg_be))) wr_err = 1'b1 ;
     if (addr_hit[19] && reg_we && (I2C_PERMIT[19] != (I2C_PERMIT[19] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[20] && reg_we && (I2C_PERMIT[20] != (I2C_PERMIT[20] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[21] && reg_we && (I2C_PERMIT[21] != (I2C_PERMIT[21] & reg_be))) wr_err = 1'b1 ;
   end
 
   assign intr_state_fmt_watermark_we = addr_hit[0] & reg_we & ~wr_err;
@@ -2622,6 +2849,9 @@
   assign intr_state_ack_stop_we = addr_hit[0] & reg_we & ~wr_err;
   assign intr_state_ack_stop_wd = reg_wdata[14];
 
+  assign intr_state_host_timeout_we = addr_hit[0] & reg_we & ~wr_err;
+  assign intr_state_host_timeout_wd = reg_wdata[15];
+
   assign intr_enable_fmt_watermark_we = addr_hit[1] & reg_we & ~wr_err;
   assign intr_enable_fmt_watermark_wd = reg_wdata[0];
 
@@ -2667,6 +2897,9 @@
   assign intr_enable_ack_stop_we = addr_hit[1] & reg_we & ~wr_err;
   assign intr_enable_ack_stop_wd = reg_wdata[14];
 
+  assign intr_enable_host_timeout_we = addr_hit[1] & reg_we & ~wr_err;
+  assign intr_enable_host_timeout_wd = reg_wdata[15];
+
   assign intr_test_fmt_watermark_we = addr_hit[2] & reg_we & ~wr_err;
   assign intr_test_fmt_watermark_wd = reg_wdata[0];
 
@@ -2712,6 +2945,9 @@
   assign intr_test_ack_stop_we = addr_hit[2] & reg_we & ~wr_err;
   assign intr_test_ack_stop_wd = reg_wdata[14];
 
+  assign intr_test_host_timeout_we = addr_hit[2] & reg_we & ~wr_err;
+  assign intr_test_host_timeout_wd = reg_wdata[15];
+
   assign ctrl_enablehost_we = addr_hit[3] & reg_we & ~wr_err;
   assign ctrl_enablehost_wd = reg_wdata[0];
 
@@ -2852,6 +3088,21 @@
   assign txdata_we = addr_hit[19] & reg_we & ~wr_err;
   assign txdata_wd = reg_wdata[7:0];
 
+  assign stretch_ctrl_enableaddr_we = addr_hit[20] & reg_we & ~wr_err;
+  assign stretch_ctrl_enableaddr_wd = reg_wdata[0];
+
+  assign stretch_ctrl_enabletx_we = addr_hit[20] & reg_we & ~wr_err;
+  assign stretch_ctrl_enabletx_wd = reg_wdata[1];
+
+  assign stretch_ctrl_enableacq_we = addr_hit[20] & reg_we & ~wr_err;
+  assign stretch_ctrl_enableacq_wd = reg_wdata[2];
+
+  assign stretch_ctrl_stop_we = addr_hit[20] & reg_we & ~wr_err;
+  assign stretch_ctrl_stop_wd = reg_wdata[3];
+
+  assign host_timeout_ctrl_we = addr_hit[21] & reg_we & ~wr_err;
+  assign host_timeout_ctrl_wd = reg_wdata[31:0];
+
   // Read data return
   always_comb begin
     reg_rdata_next = '0;
@@ -2872,6 +3123,7 @@
         reg_rdata_next[12] = intr_state_tx_overflow_qs;
         reg_rdata_next[13] = intr_state_acq_overflow_qs;
         reg_rdata_next[14] = intr_state_ack_stop_qs;
+        reg_rdata_next[15] = intr_state_host_timeout_qs;
       end
 
       addr_hit[1]: begin
@@ -2890,6 +3142,7 @@
         reg_rdata_next[12] = intr_enable_tx_overflow_qs;
         reg_rdata_next[13] = intr_enable_acq_overflow_qs;
         reg_rdata_next[14] = intr_enable_ack_stop_qs;
+        reg_rdata_next[15] = intr_enable_host_timeout_qs;
       end
 
       addr_hit[2]: begin
@@ -2908,6 +3161,7 @@
         reg_rdata_next[12] = '0;
         reg_rdata_next[13] = '0;
         reg_rdata_next[14] = '0;
+        reg_rdata_next[15] = '0;
       end
 
       addr_hit[3]: begin
@@ -3014,6 +3268,17 @@
         reg_rdata_next[7:0] = '0;
       end
 
+      addr_hit[20]: begin
+        reg_rdata_next[0] = stretch_ctrl_enableaddr_qs;
+        reg_rdata_next[1] = stretch_ctrl_enabletx_qs;
+        reg_rdata_next[2] = stretch_ctrl_enableacq_qs;
+        reg_rdata_next[3] = stretch_ctrl_stop_qs;
+      end
+
+      addr_hit[21]: begin
+        reg_rdata_next[31:0] = host_timeout_ctrl_qs;
+      end
+
       default: begin
         reg_rdata_next = '1;
       end