| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 | // | 
 | // Provides termination for a TL interface. | 
 | module tlul_sink import tlul_pkg::*; ( | 
 |   input logic clk_i, | 
 |   input logic rst_ni, | 
 |  | 
 |   input  tlul_pkg::tl_h2d_t tl_i, | 
 |   output tlul_pkg::tl_d2h_t tl_o | 
 | ); | 
 |   logic a_ack, d_ack; | 
 |   logic rd_req, wr_req; | 
 |   logic pending; | 
 |  | 
 |   localparam int IDW = $bits(tl_i.a_source); | 
 |   localparam int SZW = $bits(tl_i.a_size); | 
 |  | 
 |   logic [IDW-1:0] d_source_q; | 
 |   logic [SZW-1:0] d_size_q; | 
 |   tl_d_op_e       d_opcode_q; | 
 |   logic           d_error_q; | 
 |  | 
 |   logic addr_align_err;     // Size and alignment | 
 |   logic wr_mask_err;        // Write mask always all 1s. | 
 |   logic malformed_meta_err; // User signal format error or unsupported | 
 |   logic tl_err;             // Common TL-UL error checker | 
 |  | 
 |   assign a_ack   = tl_i.a_valid & tl_o.a_ready; | 
 |   assign d_ack   = tl_o.d_valid & tl_i.d_ready; | 
 |   assign wr_req  = a_ack & ((tl_i.a_opcode == PutFullData) | (tl_i.a_opcode == PutPartialData)); | 
 |   assign rd_req  = a_ack & (tl_i.a_opcode == Get); | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni)    pending <= 1'b0; | 
 |     else if (a_ack) pending <= 1'b1; | 
 |     else if (d_ack) pending <= 1'b0; | 
 |   end | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       d_source_q <= '0; | 
 |       d_size_q <= '0; | 
 |       d_opcode_q <= AccessAck; | 
 |       d_error_q <= 1'b0; | 
 |     end else if (a_ack) begin | 
 |       d_source_q <= tl_i.a_source; | 
 |       d_size_q <= tl_i.a_size; | 
 |       d_opcode_q <= rd_req ? AccessAckData : AccessAck; | 
 |       d_error_q <= (addr_align_err | wr_mask_err | malformed_meta_err | tl_err); | 
 |     end | 
 |   end | 
 |  | 
 |   //////////////////// | 
 |   // Error Handling // | 
 |   //////////////////// | 
 |   // Accept only word aligned address. | 
 |   assign addr_align_err = wr_req ? (|tl_i.a_address[1:0]) : 1'b0; | 
 |  | 
 |   // Write mask should be all 1s. | 
 |   assign wr_mask_err = wr_req ? ~(&tl_i.a_mask) : 1'b0; | 
 |  | 
 |   // Don't allow unsupported values. | 
 |   assign malformed_meta_err = tl_a_user_chk(tl_i.a_user); | 
 |  | 
 |   // tl_err : separate checker | 
 |   tlul_err u_err ( | 
 |     .clk_i, | 
 |     .rst_ni, | 
 |     .tl_i, | 
 |     .err_o (tl_err) | 
 |   ); | 
 |  | 
 |   ////////////////// | 
 |   // Final Output // | 
 |   ////////////////// | 
 |   tlul_pkg::tl_d2h_t tl_o_pre; | 
 |   assign tl_o_pre = '{ | 
 |     a_ready:  ~pending, | 
 |     d_valid:  pending, | 
 |     d_opcode: d_opcode_q, | 
 |     d_param:  '0, | 
 |     d_size:   d_size_q, | 
 |     d_source: d_source_q, | 
 |     d_sink:   '0, | 
 |     d_data:   '0, | 
 |     d_user:   '0, | 
 |     d_error:  d_error_q | 
 |   }; | 
 |  | 
 |   tlul_rsp_intg_gen u_gen ( | 
 |     .tl_i(tl_o_pre), | 
 |     .tl_o | 
 |   ); | 
 |  | 
 | endmodule |