| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| |
| package tlul_pkg; |
| |
| // this can be either PPC or BINTREE |
| // there is no functional difference, but timing and area behavior is different |
| // between the two instances. PPC can result in smaller implementations when timing |
| // is not critical, whereas BINTREE is favorable when timing pressure is high (but this |
| // may also result in a larger implementation). on FPGA targets, BINTREE is favorable |
| // both in terms of area and timing. |
| parameter ArbiterImpl = "PPC"; |
| |
| typedef enum logic [2:0] { |
| PutFullData = 3'h 0, |
| PutPartialData = 3'h 1, |
| Get = 3'h 4 |
| } tl_a_op_e; |
| |
| typedef enum logic [2:0] { |
| AccessAck = 3'h 0, |
| AccessAckData = 3'h 1 |
| } tl_d_op_e; |
| |
| typedef enum logic [2:0] { |
| InstrEn = 3'b101, |
| InstrDis = 3'b010 |
| } tl_instr_en_e; |
| |
| // used for intermodule connections |
| typedef tl_instr_en_e tl_instr_en_t; |
| |
| typedef enum logic [1:0] { |
| InstrType = 2'b01, |
| DataType = 2'b10 |
| } tl_type_e; |
| |
| parameter int H2DCmdMaxWidth = 57; |
| parameter int H2DCmdIntgWidth = 7; |
| parameter int H2DCmdFullWidth = H2DCmdMaxWidth + H2DCmdIntgWidth; |
| parameter int D2HRspMaxWidth = 57; |
| parameter int D2HRspIntgWidth = 7; |
| parameter int D2HRspFullWidth = D2HRspMaxWidth + D2HRspIntgWidth; |
| parameter int DataMaxWidth = 32; |
| parameter int DataIntgWidth = 7; |
| parameter int DataFullWidth = DataMaxWidth + DataIntgWidth; |
| |
| typedef struct packed { |
| logic [4:0] rsvd; |
| tl_type_e tl_type; |
| logic [H2DCmdIntgWidth-1:0] cmd_intg; |
| logic [DataIntgWidth-1:0] data_intg; |
| } tl_a_user_t; |
| |
| parameter tl_a_user_t TL_A_USER_DEFAULT = '{ |
| rsvd: '0, |
| tl_type: DataType, |
| cmd_intg: '0, |
| data_intg: '0 |
| }; |
| |
| typedef struct packed { |
| tl_type_e tl_type; |
| logic [top_pkg::TL_AW-1:0] addr; |
| tl_a_op_e opcode; |
| logic [top_pkg::TL_DBW-1:0] mask; |
| } tl_h2d_cmd_intg_t; |
| |
| typedef struct packed { |
| logic a_valid; |
| tl_a_op_e a_opcode; |
| logic [2:0] a_param; |
| logic [top_pkg::TL_SZW-1:0] a_size; |
| logic [top_pkg::TL_AIW-1:0] a_source; |
| logic [top_pkg::TL_AW-1:0] a_address; |
| logic [top_pkg::TL_DBW-1:0] a_mask; |
| logic [top_pkg::TL_DW-1:0] a_data; |
| tl_a_user_t a_user; |
| |
| logic d_ready; |
| } tl_h2d_t; |
| |
| localparam tl_h2d_t TL_H2D_DEFAULT = '{ |
| d_ready: 1'b1, |
| a_opcode: tl_a_op_e'('0), |
| a_user: tl_a_user_t'('0), |
| default: '0 |
| }; |
| |
| typedef struct packed { |
| logic [D2HRspIntgWidth-1:0] rsp_intg; |
| logic [DataIntgWidth-1:0] data_intg; |
| } tl_d_user_t; |
| |
| parameter tl_d_user_t TL_D_USER_DEFAULT = '{ |
| rsp_intg: '0, |
| data_intg: '0 |
| }; |
| |
| typedef struct packed { |
| logic d_valid; |
| tl_d_op_e d_opcode; |
| logic [2:0] d_param; |
| logic [top_pkg::TL_SZW-1:0] d_size; // Bouncing back a_size |
| logic [top_pkg::TL_AIW-1:0] d_source; |
| logic [top_pkg::TL_DIW-1:0] d_sink; |
| logic [top_pkg::TL_DW-1:0] d_data; |
| tl_d_user_t d_user; |
| logic d_error; |
| |
| logic a_ready; |
| |
| } tl_d2h_t; |
| |
| typedef struct packed { |
| tl_d_op_e opcode; |
| logic [top_pkg::TL_SZW-1:0] size; |
| // Temporarily removed because source changes throughout the fabric |
| // and thus cannot be used for end-to-end checking. |
| // A different PR will propose a work-around (a hoaky one) to see if |
| // it gets the job done. |
| //logic [top_pkg::TL_AIW-1:0] source; |
| logic error; |
| } tl_d2h_rsp_intg_t; |
| |
| localparam tl_d2h_t TL_D2H_DEFAULT = '{ |
| a_ready: 1'b1, |
| d_opcode: tl_d_op_e'('0), |
| d_user: tl_d_user_t'(0), |
| default: '0 |
| }; |
| |
| // Check user for unsupported values |
| function automatic logic tl_a_user_chk(tl_a_user_t user); |
| logic malformed_err; |
| logic unused_user; |
| unused_user = |user; |
| malformed_err = ~(user.tl_type inside {InstrType, DataType}); |
| return malformed_err; |
| endfunction // tl_a_user_chk |
| |
| // extract variables used for command checking |
| function automatic tl_h2d_cmd_intg_t extract_h2d_cmd_intg(tl_h2d_t tl); |
| tl_h2d_cmd_intg_t payload; |
| logic unused_tlul; |
| unused_tlul = ^tl; |
| payload.addr = tl.a_address; |
| payload.opcode = tl.a_opcode; |
| payload.mask = tl.a_mask; |
| payload.tl_type = tl.a_user.tl_type; |
| return payload; |
| endfunction // extract_h2d_payload |
| |
| // extract variables used for response checking |
| function automatic tl_d2h_rsp_intg_t extract_d2h_rsp_intg(tl_d2h_t tl); |
| tl_d2h_rsp_intg_t payload; |
| logic unused_tlul; |
| unused_tlul = ^tl; |
| payload.opcode = tl.d_opcode; |
| payload.size = tl.d_size; |
| //payload.source = tl.d_source; |
| payload.error = tl.d_error; |
| return payload; |
| endfunction // extract_d2h_rsp_intg |
| |
| // calculate ecc for command checking |
| function automatic logic [H2DCmdIntgWidth-1:0] get_cmd_intg(tl_h2d_t tl); |
| logic [H2DCmdIntgWidth-1:0] cmd_intg; |
| logic [H2DCmdMaxWidth-1:0] unused_cmd_payload; |
| tl_h2d_cmd_intg_t cmd; |
| cmd = extract_h2d_cmd_intg(tl); |
| {cmd_intg, unused_cmd_payload} = prim_secded_pkg::prim_secded_64_57_enc(H2DCmdMaxWidth'(cmd)); |
| return cmd_intg; |
| endfunction // get_cmd_intg |
| |
| // calculate ecc for data checking |
| function automatic logic [DataIntgWidth-1:0] get_data_intg(logic [top_pkg::TL_DW-1:0] data); |
| logic [DataIntgWidth-1:0] data_intg; |
| logic [top_pkg::TL_DW-1:0] unused_data; |
| {data_intg, unused_data} = prim_secded_pkg::prim_secded_39_32_enc(data); |
| return data_intg; |
| endfunction // get_data_intg |
| |
| endpackage |