[util/reggen] Rework TL-UL to Register interaface

- Added tlul_adapter_reg.sv for converting TL-UL to reg_if
- Reduced one clock delay between the requests (#98)
- Re-created register top for all IPs
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv
index 6224ac4..8ed6772 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv
@@ -25,27 +25,22 @@
   import flash_ctrl_reg_pkg::* ;
 
   localparam AW = 7;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -98,47 +93,37 @@
     end
   end
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -154,26 +139,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -2668,9 +2633,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -2937,7 +2902,6 @@
   assign fifo_lvl_rd_wd = reg_wdata[12:8];
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -3093,41 +3057,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/ip/gpio/rtl/gpio_reg_top.sv b/hw/ip/gpio/rtl/gpio_reg_top.sv
index e70b9c5..4c5a9c1 100644
--- a/hw/ip/gpio/rtl/gpio_reg_top.sv
+++ b/hw/ip/gpio/rtl/gpio_reg_top.sv
@@ -20,27 +20,22 @@
   import gpio_reg_pkg::* ;
 
   localparam AW = 6;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
   assign tl_reg_h2d = tl_i;
   assign tl_o       = tl_reg_d2h;
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -604,9 +569,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -676,7 +641,6 @@
   assign ctrl_en_input_filter_wd = reg_wdata[31:0];
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -750,41 +714,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/ip/hmac/rtl/hmac_reg_top.sv b/hw/ip/hmac/rtl/hmac_reg_top.sv
index 1a37c98..eb83373 100644
--- a/hw/ip/hmac/rtl/hmac_reg_top.sv
+++ b/hw/ip/hmac/rtl/hmac_reg_top.sv
@@ -25,27 +25,22 @@
   import hmac_reg_pkg::* ;
 
   localparam AW = 12;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -94,47 +89,37 @@
     end
   end
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -150,26 +135,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -1012,9 +977,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -1108,7 +1073,6 @@
 
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -1227,41 +1191,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv b/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
index c392527..a91f3dd 100644
--- a/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
+++ b/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
@@ -20,27 +20,22 @@
   import rv_plic_reg_pkg::* ;
 
   localparam AW = 9;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
   assign tl_reg_h2d = tl_i;
   assign tl_o       = tl_reg_d2h;
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -3910,9 +3875,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -4249,7 +4214,6 @@
   assign msip0_wd = reg_wdata[0];
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -4504,41 +4468,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv b/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
index 96d65c8..6e37a4f 100644
--- a/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
+++ b/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
@@ -20,27 +20,22 @@
   import rv_timer_reg_pkg::* ;
 
   localparam AW = 9;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
   assign tl_reg_h2d = tl_i;
   assign tl_o       = tl_reg_d2h;
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -435,9 +400,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -474,7 +439,6 @@
   assign intr_test0_wd = reg_wdata[0];
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -521,41 +485,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/ip/spi_device/rtl/spi_device_reg_top.sv b/hw/ip/spi_device/rtl/spi_device_reg_top.sv
index c53da41..aa7d859 100644
--- a/hw/ip/spi_device/rtl/spi_device_reg_top.sv
+++ b/hw/ip/spi_device/rtl/spi_device_reg_top.sv
@@ -25,27 +25,22 @@
   import spi_device_reg_pkg::* ;
 
   localparam AW = 12;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -94,47 +89,37 @@
     end
   end
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -150,26 +135,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -1184,9 +1149,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -1296,7 +1261,6 @@
   assign txf_addr_limit_wd = reg_wdata[31:16];
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -1380,41 +1344,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/ip/tlul/adapter_reg.core b/hw/ip/tlul/adapter_reg.core
new file mode 100644
index 0000000..7c7ee71
--- /dev/null
+++ b/hw/ip/tlul/adapter_reg.core
@@ -0,0 +1,21 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:tlul:adapter_reg:0.1"
+description: "TL-UL to Register interface adapter"
+
+filesets:
+  files_rtl:
+    depend:
+      - lowrisc:prim:all
+      - lowrisc:tlul:common
+    files:
+      - rtl/tlul_adapter_reg.sv
+    file_type: systemVerilogSource
+
+targets:
+  default: &default_target
+    filesets:
+      - files_rtl
+    toplevel: tlul_adapter_reg
diff --git a/hw/ip/tlul/rtl/tlul_adapter_reg.sv b/hw/ip/tlul/rtl/tlul_adapter_reg.sv
new file mode 100644
index 0000000..1790c1c
--- /dev/null
+++ b/hw/ip/tlul/rtl/tlul_adapter_reg.sv
@@ -0,0 +1,98 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * Tile-Link UL adapter for Register interface
+ */
+
+module tlul_adapter_reg import tlul_pkg::*; #(
+  parameter  int RegAw = 8,
+  parameter  int RegDw = 32, // Shall be matched with TL_DW
+  localparam int RegBw = RegDw/8
+) (
+  input clk_i,
+  input rst_ni,
+
+  // TL-UL interface
+  input  tl_h2d_t tl_i,
+  output tl_d2h_t tl_o,
+
+  // Register interface
+  output logic             re_o,
+  output logic             we_o,
+  output logic [RegAw-1:0] addr_o,
+  output logic [RegDw-1:0] wdata_o,
+  output logic [RegBw-1:0] be_o,
+  input        [RegDw-1:0] rdata_i,
+  input                    error_i
+);
+
+  localparam int IW  = $bits(tl_i.a_source);
+  localparam int SZW = $bits(tl_i.a_size);
+
+  logic outstanding;    // Indicates current request is pending
+  logic a_ack, d_ack;
+
+  logic [RegDw-1:0] rdata;
+  logic             error;
+
+  logic [IW-1:0]  reqid;
+  logic [SZW-1:0] reqsz;
+  tl_d_op_e       rspop;
+
+  assign a_ack   = tl_i.a_valid & tl_o.a_ready;
+  assign d_ack   = tl_o.d_valid & tl_i.d_ready;
+  // Request signal
+  assign we_o    = a_ack & ((tl_i.a_opcode == PutFullData) | (tl_i.a_opcode == PutPartialData));
+  assign re_o    = a_ack & (tl_i.a_opcode == Get);
+  assign addr_o  = tl_i.a_address[RegAw-1:0];
+  assign wdata_o = tl_i.a_data;
+  assign be_o    = tl_i.a_mask;
+
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni)    outstanding <= 1'b0;
+    else if (a_ack) outstanding <= 1'b1;
+    else if (d_ack) outstanding <= 1'b0;
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      reqid <= '0;
+      reqsz <= '0;
+      rspop <= AccessAck;
+    end else if (a_ack) begin
+      reqid <= tl_i.a_source;
+      reqsz <= tl_i.a_size;
+      rspop <= (re_o) ? AccessAckData : AccessAck ;
+    end
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      rdata  <= '0;
+      error <= 1'b0;
+    end else if (a_ack) begin
+      rdata <= rdata_i;
+      error <= error_i | (tl_i.a_user.parity_en == 1'b1);
+    end
+  end
+
+  assign tl_o = '{
+    a_ready:  ~outstanding,
+    d_valid:  outstanding,
+    d_opcode: rspop,
+    d_param:  '0,
+    d_size:   reqsz,
+    d_source: reqid,
+    d_sink:   '0,
+    d_data:   rdata,
+    d_user:  '0,
+    d_error: error
+  };
+
+
+  `ASSERT_INIT(MatchedWidthAssert, RegDw == top_pkg::TL_DW)
+
+endmodule
diff --git a/hw/ip/tlul/tlul.core b/hw/ip/tlul/tlul.core
index 414f80a..0cc42e0 100644
--- a/hw/ip/tlul/tlul.core
+++ b/hw/ip/tlul/tlul.core
@@ -11,6 +11,7 @@
       - lowrisc:tlul:socket_1n
       - lowrisc:tlul:socket_m1
       - lowrisc:tlul:adapter_sram
+      - lowrisc:tlul:adapter_reg
       - lowrisc:tlul:adapter_flash
       - lowrisc:tlul:sram2tlul
 
diff --git a/hw/ip/uart/rtl/uart_reg_top.sv b/hw/ip/uart/rtl/uart_reg_top.sv
index 5d88300..570dedf 100644
--- a/hw/ip/uart/rtl/uart_reg_top.sv
+++ b/hw/ip/uart/rtl/uart_reg_top.sv
@@ -20,27 +20,22 @@
   import uart_reg_pkg::* ;
 
   localparam AW = 6;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
   assign tl_reg_h2d = tl_i;
   assign tl_o       = tl_reg_d2h;
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -1457,9 +1422,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -1612,7 +1577,6 @@
   assign timeout_ctrl_en_wd = reg_wdata[31];
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -1710,41 +1674,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/ip/usbuart/rtl/usbuart_reg_top.sv b/hw/ip/usbuart/rtl/usbuart_reg_top.sv
index 9b96ec5..06be81e 100644
--- a/hw/ip/usbuart/rtl/usbuart_reg_top.sv
+++ b/hw/ip/usbuart/rtl/usbuart_reg_top.sv
@@ -20,27 +20,22 @@
   import usbuart_reg_pkg::* ;
 
   localparam AW = 6;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
   assign tl_reg_h2d = tl_i;
   assign tl_o       = tl_reg_d2h;
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -1569,9 +1534,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -1736,7 +1701,6 @@
   assign usbparam_parity_req_re = addr_hit[13] && reg_re;
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -1846,41 +1810,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/hw/top_earlgrey/rtl/rv_plic_reg_top.sv b/hw/top_earlgrey/rtl/rv_plic_reg_top.sv
index f64f327..ff7464c 100644
--- a/hw/top_earlgrey/rtl/rv_plic_reg_top.sv
+++ b/hw/top_earlgrey/rtl/rv_plic_reg_top.sv
@@ -20,27 +20,22 @@
   import rv_plic_reg_pkg::* ;
 
   localparam AW = 9;
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = 32;
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
   assign tl_reg_h2d = tl_i;
   assign tl_o       = tl_reg_d2h;
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -6219,9 +6184,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -6758,7 +6723,6 @@
   assign msip0_wd = reg_wdata[0];
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -7162,41 +7126,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
diff --git a/util/reggen/reg_top.tpl.sv b/util/reggen/reg_top.tpl.sv
index d47c927..1c71ac5 100644
--- a/util/reggen/reg_top.tpl.sv
+++ b/util/reggen/reg_top.tpl.sv
@@ -31,27 +31,22 @@
   import ${block.name}_reg_pkg::* ;
 
   localparam AW = ${block.addr_width};
-  localparam IW = $bits(tl_i.a_source);
   localparam DW = ${block.width};
   localparam DBW = DW/8;                    // Byte Width
   localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
 
   // register signals
-  logic          reg_we;
-  logic          reg_re;
-  logic [AW-1:0] reg_addr;
-  logic [DW-1:0] reg_wdata;
-  logic          reg_valid;
-  logic [DW-1:0] reg_rdata;
-  logic          tl_malformed, tl_addrmiss;
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
 
-  // Bus signals
-  tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
-  logic          reqready;
-  logic [IW-1:0] reqid;
-  logic [IW-1:0] rspid;
+  logic          malformed, addrmiss;
 
-  logic          outstanding;
+  logic [DW-1:0] reg_rdata_next;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -113,47 +108,37 @@
   end
 % endif
 
-  // TODO(eunchan): Fix it after bus interface is finalized
-  assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
-                   (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
-  assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
-                  (tl_reg_h2d.a_opcode == tlul_pkg::Get);
-  assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
-  assign reg_wdata = tl_reg_h2d.a_data;
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
 
-  assign tl_reg_d2h.d_valid  = reg_valid;
-  assign tl_reg_d2h.d_opcode = rsp_opcode;
-  assign tl_reg_d2h.d_param  = '0;
-  assign tl_reg_d2h.d_size   = FSZ;         // always Full Size
-  assign tl_reg_d2h.d_source = rspid;
-  assign tl_reg_d2h.d_sink   = '0;          // Used in TL-C
-  assign tl_reg_d2h.d_data   = reg_rdata;
-  assign tl_reg_d2h.d_user   = '0;          // Doesn't allow additional features yet
-  assign tl_reg_d2h.d_error  = tl_malformed | tl_addrmiss;
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
 
-  assign tl_reg_d2h.a_ready  = reqready;
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
 
-  assign reqid     = tl_reg_h2d.a_source;
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = malformed | addrmiss ;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      tl_malformed <= 1'b1;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
-          (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
-        tl_malformed <= 1'b1;
-      // Only allow Full Write with full mask
-      end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
-        tl_malformed <= 1'b1;
-      end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
-        tl_malformed <= 1'b1;
-      end else begin
-        tl_malformed <= 1'b0;
-      end
+  // Malformed request check only affects to the write access
+  always_comb begin : malformed_check
+    if (reg_we && (reg_be != '1)) begin
+      malformed = 1'b1;
+    end else begin
+      malformed = 1'b0;
     end
   end
+
   // TODO(eunchan): Revise Register Interface logic after REG INTF finalized
   // TODO(eunchan): Make concrete scenario
   //    1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -169,26 +154,6 @@
   // d_ready ___________________/     \______
   //
   // Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    // Not to accept new request when a request is handling
-    //   #Outstanding := 1
-    if (!rst_ni) begin
-      reqready <= 1'b0;
-    end else if (reg_we || reg_re) begin
-      reqready <= 1'b0;
-    end else if (outstanding == 1'b0) begin
-      reqready <= 1'b1;
-    end
-  end
-
-  // Request/ Response ID
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      rspid <= '0;
-    end else if (reg_we || reg_re) begin
-      rspid <= reqid;
-    end
-  end
 
   // Define SW related signals
   // Format: <reg>_<field>_{wd|we|qs}
@@ -278,9 +243,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      tl_addrmiss <= 1'b0;
+      addrmiss <= 1'b0;
     end else if (reg_re || reg_we) begin
-      tl_addrmiss <= ~|addr_hit;
+      addrmiss <= ~|addr_hit;
     end
   end
 
@@ -315,7 +280,6 @@
   % endfor
 
   // Read data return
-  logic [DW-1:0] reg_rdata_next;
   always_comb begin
     reg_rdata_next = '0;
     unique case (1'b1)
@@ -355,41 +319,11 @@
     endcase
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      reg_valid <= 1'b0;
-      reg_rdata <= '0;
-      rsp_opcode <= tlul_pkg::AccessAck;
-    end else if (reg_re || reg_we) begin
-      // Guarantee to return data in a cycle
-      reg_valid <= 1'b1;
-      if (reg_re) begin
-        reg_rdata <= reg_rdata_next;
-        rsp_opcode <= tlul_pkg::AccessAckData;
-      end else begin
-        rsp_opcode <= tlul_pkg::AccessAck;
-      end
-    end else if (tl_reg_h2d.d_ready) begin
-      reg_valid <= 1'b0;
-    end
-  end
-
-  // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      outstanding <= 1'b0;
-    end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
-      outstanding <= 1'b1;
-    end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
-      outstanding <= 1'b0;
-    end
-  end
-
   // Assertions for Register Interface
   `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
   `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
 
   `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)