[tlul] Add payload checker and generator on device side only. - Incomplete until host side is done - Windowed accesses also need further tweaking Signed-off-by: Timothy Chen <timothytim@google.com> [tlul] Enhance host / device checks Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/Makefile b/hw/Makefile index 94719e5..c497acc 100644 --- a/hw/Makefile +++ b/hw/Makefile
@@ -26,6 +26,7 @@ lc_ctrl \ nmi_gen \ otp_ctrl \ + pattgen \ pinmux \ pwrmgr \ rstmgr \
diff --git a/hw/ip/prim/prim_secded.core b/hw/ip/prim/prim_secded.core index 2fea1c0..87a248e 100644 --- a/hw/ip/prim/prim_secded.core +++ b/hw/ip/prim/prim_secded.core
@@ -14,6 +14,8 @@ - rtl/prim_secded_28_22_enc.sv - rtl/prim_secded_39_32_dec.sv - rtl/prim_secded_39_32_enc.sv + - rtl/prim_secded_64_57_dec.sv + - rtl/prim_secded_64_57_enc.sv - rtl/prim_secded_72_64_dec.sv - rtl/prim_secded_72_64_enc.sv - rtl/prim_secded_hamming_22_16_dec.sv
diff --git a/hw/ip/prim/rtl/prim_secded_64_57_dec.sv b/hw/ip/prim/rtl/prim_secded_64_57_dec.sv new file mode 100644 index 0000000..6ed256a --- /dev/null +++ b/hw/ip/prim/rtl/prim_secded_64_57_dec.sv
@@ -0,0 +1,88 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Decoder generated by +// util/design/secded_gen.py -m 7 -k 57 -s 2871209727 -c hsiao + +module prim_secded_64_57_dec ( + input [63:0] in, + output logic [56:0] d_o, + output logic [6:0] syndrome_o, + output logic [1:0] err_o +); + + + // Syndrome calculation + assign syndrome_o[0] = ^(in & 64'h0303FFF800007FFF); + assign syndrome_o[1] = ^(in & 64'h057C1FF801FF801F); + assign syndrome_o[2] = ^(in & 64'h09BDE1F87E0781E1); + assign syndrome_o[3] = ^(in & 64'h11DEEE3B8E388E22); + assign syndrome_o[4] = ^(in & 64'h21EF76CDB2C93244); + assign syndrome_o[5] = ^(in & 64'h41F7BB56D5525488); + assign syndrome_o[6] = ^(in & 64'h81FBDDA769A46910); + + // Corrected output calculation + assign d_o[0] = (syndrome_o == 7'h7) ^ in[0]; + assign d_o[1] = (syndrome_o == 7'hb) ^ in[1]; + assign d_o[2] = (syndrome_o == 7'h13) ^ in[2]; + assign d_o[3] = (syndrome_o == 7'h23) ^ in[3]; + assign d_o[4] = (syndrome_o == 7'h43) ^ in[4]; + assign d_o[5] = (syndrome_o == 7'hd) ^ in[5]; + assign d_o[6] = (syndrome_o == 7'h15) ^ in[6]; + assign d_o[7] = (syndrome_o == 7'h25) ^ in[7]; + assign d_o[8] = (syndrome_o == 7'h45) ^ in[8]; + assign d_o[9] = (syndrome_o == 7'h19) ^ in[9]; + assign d_o[10] = (syndrome_o == 7'h29) ^ in[10]; + assign d_o[11] = (syndrome_o == 7'h49) ^ in[11]; + assign d_o[12] = (syndrome_o == 7'h31) ^ in[12]; + assign d_o[13] = (syndrome_o == 7'h51) ^ in[13]; + assign d_o[14] = (syndrome_o == 7'h61) ^ in[14]; + assign d_o[15] = (syndrome_o == 7'he) ^ in[15]; + assign d_o[16] = (syndrome_o == 7'h16) ^ in[16]; + assign d_o[17] = (syndrome_o == 7'h26) ^ in[17]; + assign d_o[18] = (syndrome_o == 7'h46) ^ in[18]; + assign d_o[19] = (syndrome_o == 7'h1a) ^ in[19]; + assign d_o[20] = (syndrome_o == 7'h2a) ^ in[20]; + assign d_o[21] = (syndrome_o == 7'h4a) ^ in[21]; + assign d_o[22] = (syndrome_o == 7'h32) ^ in[22]; + assign d_o[23] = (syndrome_o == 7'h52) ^ in[23]; + assign d_o[24] = (syndrome_o == 7'h62) ^ in[24]; + assign d_o[25] = (syndrome_o == 7'h1c) ^ in[25]; + assign d_o[26] = (syndrome_o == 7'h2c) ^ in[26]; + assign d_o[27] = (syndrome_o == 7'h4c) ^ in[27]; + assign d_o[28] = (syndrome_o == 7'h34) ^ in[28]; + assign d_o[29] = (syndrome_o == 7'h54) ^ in[29]; + assign d_o[30] = (syndrome_o == 7'h64) ^ in[30]; + assign d_o[31] = (syndrome_o == 7'h38) ^ in[31]; + assign d_o[32] = (syndrome_o == 7'h58) ^ in[32]; + assign d_o[33] = (syndrome_o == 7'h68) ^ in[33]; + assign d_o[34] = (syndrome_o == 7'h70) ^ in[34]; + assign d_o[35] = (syndrome_o == 7'h1f) ^ in[35]; + assign d_o[36] = (syndrome_o == 7'h2f) ^ in[36]; + assign d_o[37] = (syndrome_o == 7'h4f) ^ in[37]; + assign d_o[38] = (syndrome_o == 7'h37) ^ in[38]; + assign d_o[39] = (syndrome_o == 7'h57) ^ in[39]; + assign d_o[40] = (syndrome_o == 7'h67) ^ in[40]; + assign d_o[41] = (syndrome_o == 7'h3b) ^ in[41]; + assign d_o[42] = (syndrome_o == 7'h5b) ^ in[42]; + assign d_o[43] = (syndrome_o == 7'h6b) ^ in[43]; + assign d_o[44] = (syndrome_o == 7'h73) ^ in[44]; + assign d_o[45] = (syndrome_o == 7'h3d) ^ in[45]; + assign d_o[46] = (syndrome_o == 7'h5d) ^ in[46]; + assign d_o[47] = (syndrome_o == 7'h6d) ^ in[47]; + assign d_o[48] = (syndrome_o == 7'h75) ^ in[48]; + assign d_o[49] = (syndrome_o == 7'h79) ^ in[49]; + assign d_o[50] = (syndrome_o == 7'h3e) ^ in[50]; + assign d_o[51] = (syndrome_o == 7'h5e) ^ in[51]; + assign d_o[52] = (syndrome_o == 7'h6e) ^ in[52]; + assign d_o[53] = (syndrome_o == 7'h76) ^ in[53]; + assign d_o[54] = (syndrome_o == 7'h7a) ^ in[54]; + assign d_o[55] = (syndrome_o == 7'h7c) ^ in[55]; + assign d_o[56] = (syndrome_o == 7'h7f) ^ in[56]; + + // err_o calc. bit0: single error, bit1: double error + assign err_o[0] = ^syndrome_o; + assign err_o[1] = ~err_o[0] & (|syndrome_o); + +endmodule : prim_secded_64_57_dec
diff --git a/hw/ip/prim/rtl/prim_secded_64_57_enc.sv b/hw/ip/prim/rtl/prim_secded_64_57_enc.sv new file mode 100644 index 0000000..f0f85f8 --- /dev/null +++ b/hw/ip/prim/rtl/prim_secded_64_57_enc.sv
@@ -0,0 +1,24 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// SECDED Encoder generated by +// util/design/secded_gen.py -m 7 -k 57 -s 2871209727 -c hsiao + +module prim_secded_64_57_enc ( + input [56:0] in, + output logic [63:0] out +); + + always_comb begin : p_encode + out = 64'(in); + out[57] = ^(out & 64'h0103FFF800007FFF); + out[58] = ^(out & 64'h017C1FF801FF801F); + out[59] = ^(out & 64'h01BDE1F87E0781E1); + out[60] = ^(out & 64'h01DEEE3B8E388E22); + out[61] = ^(out & 64'h01EF76CDB2C93244); + out[62] = ^(out & 64'h01F7BB56D5525488); + out[63] = ^(out & 64'h01FBDDA769A46910); + end + +endmodule : prim_secded_64_57_enc
diff --git a/hw/ip/tlul/adapter_reg.core b/hw/ip/tlul/adapter_reg.core index 4a92858..1e65ca6 100644 --- a/hw/ip/tlul/adapter_reg.core +++ b/hw/ip/tlul/adapter_reg.core
@@ -10,6 +10,7 @@ depend: - lowrisc:prim:all - lowrisc:tlul:common + - lowrisc:tlul:payload_chk files: - rtl/tlul_adapter_reg.sv file_type: systemVerilogSource
diff --git a/hw/ip/tlul/payload_chk.core b/hw/ip/tlul/payload_chk.core new file mode 100644 index 0000000..0a06045 --- /dev/null +++ b/hw/ip/tlul/payload_chk.core
@@ -0,0 +1,61 @@ +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:payload_chk:0.1" +description: "TL-UL to Register interface adapter" + +filesets: + files_rtl: + depend: + - lowrisc:prim:all + - lowrisc:prim:secded + - lowrisc:tlul:common + files: + - rtl/tlul_payload_chk.sv + - rtl/tlul_gen_payload_chk.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + - lowrisc:lint:comportable + +parameters: + SYNTHESIS: + datatype: bool + paramtype: vlogdefine + + +targets: + default: &default_target + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl + toplevel: tlul_payload_chk + + lint: + <<: *default_target + default_tool: verilator + parameters: + - SYNTHESIS=true + tools: + verilator: + mode: lint-only + verilator_options: + - "-Wall"
diff --git a/hw/ip/tlul/rtl/tlul_adapter_host.sv b/hw/ip/tlul/rtl/tlul_adapter_host.sv index 9248a09..b57f0f9 100644 --- a/hw/ip/tlul/rtl/tlul_adapter_host.sv +++ b/hw/ip/tlul/rtl/tlul_adapter_host.sv
@@ -46,6 +46,8 @@ logic [top_pkg::TL_AIW-1:0] tl_source; logic [top_pkg::TL_DBW-1:0] tl_be; + tl_h2d_t tl_out; + tl_a_user_t tl_user; if (MAX_REQS == 1) begin : g_single_req assign tl_source = '0; @@ -83,7 +85,7 @@ // bits set. For writes the supplied be_i is used as the mask. assign tl_be = ~we_i ? {top_pkg::TL_DBW{1'b1}} : be_i; - assign tl_o = '{ + assign tl_out = '{ a_valid: req_i, a_opcode: (~we_i) ? Get : (&be_i) ? PutFullData : @@ -94,11 +96,33 @@ a_source: tl_source, a_address: {addr_i[31:WordSize], {WordSize{1'b0}}}, a_data: wdata_i, - a_user: '{parity_en: '0, parity: '0, tl_type: type_i}, - + a_user: '{default: '0, chk_en: CheckDis, chk_data: '0, tl_type: type_i}, d_ready: 1'b1 }; + logic [H2DCmdMaxWidth-1:0] unused_cmd; + logic [H2DCmdChkWidth-1:0] chk_cmd; + + prim_secded_64_57_enc u_enc ( + .in(H2DCmdMaxWidth'(extract_h2d_cmd_chk(tl_out))), + .out({chk_cmd, unused_cmd}) + ); + + assign tl_user = '{ + default: '0, + tl_type: type_i, + chk_en: CheckEn, + chk_cmd: chk_cmd, + chk_data: '0 + }; + + // override user bits. + always_comb begin + tl_o = tl_out; + tl_o.a_user = tl_user; + end + + assign gnt_o = tl_i.a_ready; assign valid_o = tl_i.d_valid;
diff --git a/hw/ip/tlul/rtl/tlul_adapter_reg.sv b/hw/ip/tlul/rtl/tlul_adapter_reg.sv index 08a730d..bda0119 100644 --- a/hw/ip/tlul/rtl/tlul_adapter_reg.sv +++ b/hw/ip/tlul/rtl/tlul_adapter_reg.sv
@@ -113,9 +113,8 @@ //////////////////// assign err_internal = addr_align_err | malformed_meta_err | tl_err ; - // malformed_meta_err - // Raised if not supported feature is turned on or user signal has malformed - assign malformed_meta_err = (tl_i.a_user.parity_en == 1'b1); + // Don't allow unsupported values. + assign malformed_meta_err = tl_a_user_chk(tl_i.a_user); // addr_align_err // Raised if addr isn't aligned with the size
diff --git a/hw/ip/tlul/rtl/tlul_adapter_sram.sv b/hw/ip/tlul/rtl/tlul_adapter_sram.sv index 2c5e377..666e556 100644 --- a/hw/ip/tlul/rtl/tlul_adapter_sram.sv +++ b/hw/ip/tlul/rtl/tlul_adapter_sram.sv
@@ -145,7 +145,7 @@ d_sink : 1'b0, d_data : (d_valid && rspfifo_rvalid && reqfifo_rdata.op == OpRead) ? rspfifo_rdata.data : '0, - d_user : '0, + d_user : TL_D_USER_DEFAULT, d_error : d_valid && d_error, a_ready : (gnt_i | error_internal) & reqfifo_wready & sramreqfifo_wready
diff --git a/hw/ip/tlul/rtl/tlul_gen_payload_chk.sv b/hw/ip/tlul/rtl/tlul_gen_payload_chk.sv new file mode 100644 index 0000000..aec7da1 --- /dev/null +++ b/hw/ip/tlul/rtl/tlul_gen_payload_chk.sv
@@ -0,0 +1,38 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +/** + * Tile-Link UL payload checker generator + */ + +module tlul_gen_payload_chk import tlul_pkg::*; ( + // TL-UL interface + input tl_d2h_t tl_i, + output tl_d2h_t tl_o +); + + tl_d2h_rsp_chk_t rsp; + logic [D2HRspMaxWidth-1:0] unused_payload; + logic [D2HRspChkWidth-1:0] chk; + assign rsp = extract_d2h_rsp_chk(tl_i); + + prim_secded_64_57_enc u_gen ( + .in(D2HRspMaxWidth'(rsp)), + .out({chk, unused_payload}) + ); + + always_comb begin + tl_o = tl_i; + if (tl_i.d_user.chk_en == CheckDis) begin + tl_o.d_user.chk_en = CheckEn; + tl_o.d_user.chk_rsp = chk; + end + end + + + `ASSERT_INIT(PayLoadWidthCheck, $bits(tl_d2h_rsp_chk_t) <= D2HRspMaxWidth) + +endmodule // tlul_payload_chk
diff --git a/hw/ip/tlul/rtl/tlul_payload_chk.sv b/hw/ip/tlul/rtl/tlul_payload_chk.sv new file mode 100644 index 0000000..91ce7ec --- /dev/null +++ b/hw/ip/tlul/rtl/tlul_payload_chk.sv
@@ -0,0 +1,39 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +/** + * Tile-Link UL payload checker + */ + +module tlul_payload_chk import tlul_pkg::*; ( + // TL-UL interface + input tl_h2d_t tl_i, + + // error output + output logic err_o +); + + logic [1:0] err; + tl_h2d_cmd_chk_t cmd; + assign cmd = extract_h2d_cmd_chk(tl_i); + + prim_secded_64_57_dec u_chk ( + .in({tl_i.a_user.chk_cmd, H2DCmdMaxWidth'(cmd)}), + .d_o(), + .syndrome_o(), + .err_o(err) + ); + + // TODO: The chk_en qualification here should be removed long term under a + // compile time option. + assign err_o = (tl_i.a_user.chk_en == CheckDis) ? 1'b0 : |err; + + logic unused_tl; + assign unused_tl = |tl_i; + + `ASSERT_INIT(PayLoadWidthCheck, $bits(tl_h2d_cmd_chk_t) <= H2DCmdMaxWidth) + +endmodule // tlul_payload_chk
diff --git a/hw/ip/tlul/rtl/tlul_pkg.sv b/hw/ip/tlul/rtl/tlul_pkg.sv index 46c66ba..0c40799 100644 --- a/hw/ip/tlul/rtl/tlul_pkg.sv +++ b/hw/ip/tlul/rtl/tlul_pkg.sv
@@ -37,12 +37,45 @@ DataType = 2'b10 } tl_type_e; + // Even though it is codified this way, all values + // NOT CheckDis is considered CheckEn + typedef enum logic [1:0] { + CheckDis = 2'b01, + CheckEn = 2'b10 + } tl_chk_en_e; + + parameter int H2DCmdMaxWidth = 57; + parameter int H2DCmdChkWidth = 7; + parameter int D2HRspMaxWidth = 57; + parameter int D2HRspChkWidth = 7; + + //parameter int H2DPayLoadFullWidth = H2DPayLoadMaxWidth + H2DPayLoadChkWidth; + parameter int DataMaxWidth = 32; + parameter int DataChkWidth = 7; + typedef struct packed { - tl_type_e tl_type; - logic parity_en; - logic [7:0] parity; // Use only lower TL_DBW bit + logic [2:0] rsvd1; // Reserved for future use + tl_type_e tl_type; + tl_chk_en_e chk_en; + logic [H2DCmdChkWidth-1:0] chk_cmd; + logic [DataChkWidth-1:0] chk_data; } tl_a_user_t; + parameter tl_a_user_t TL_A_USER_DEFAULT = '{ + rsvd1: '0, + tl_type: DataType, + // This value is temporary + chk_en: CheckDis, + chk_cmd: '0, + chk_data: '0 + }; + + typedef struct packed { + logic [top_pkg::TL_AW-1:0] addr; + tl_a_op_e opcode; + logic [top_pkg::TL_DBW-1:0] mask; + } tl_h2d_cmd_chk_t; + typedef struct packed { logic a_valid; tl_a_op_e a_opcode; @@ -65,6 +98,18 @@ }; typedef struct packed { + logic [4:0] rsvd1; // Reserved for future use + tl_chk_en_e chk_en; + logic [D2HRspChkWidth-1:0] chk_rsp; + } tl_d_user_t; + + parameter tl_d_user_t TL_D_USER_DEFAULT = '{ + rsvd1: '0, + chk_en: CheckDis, + chk_rsp: '0 + }; + + typedef struct packed { logic d_valid; tl_d_op_e d_opcode; logic [2:0] d_param; @@ -72,15 +117,57 @@ 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; - logic [top_pkg::TL_DUW-1:0] d_user; + 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; + logic [top_pkg::TL_AIW-1:0] source; + logic error; + } tl_d2h_rsp_chk_t; + localparam tl_d2h_t TL_D2H_DEFAULT = '{ a_ready: 1'b1, d_opcode: tl_d_op_e'('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}) | + ~(user.chk_en inside {CheckDis, CheckEn}); + return malformed_err; + endfunction // tl_a_user_chk + + // extract variables used for command checking + function automatic tl_h2d_cmd_chk_t extract_h2d_cmd_chk(tl_h2d_t tl); + tl_h2d_cmd_chk_t payload; + logic unused_tlul; + unused_tlul = ^tl; + payload.addr = tl.a_address; + payload.opcode = tl.a_opcode; + payload.mask = tl.a_mask; + return payload; + endfunction // extract_h2d_payload + + // extract variables used for response checking + function automatic tl_d2h_rsp_chk_t extract_d2h_rsp_chk(tl_d2h_t tl); + tl_d2h_rsp_chk_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_chk + endpackage
diff --git a/util/reggen/reg_top.sv.tpl b/util/reggen/reg_top.sv.tpl index e29c1f8..5f37a67 100644 --- a/util/reggen/reg_top.sv.tpl +++ b/util/reggen/reg_top.sv.tpl
@@ -64,9 +64,23 @@ tlul_pkg::tl_h2d_t tl_reg_h2d; tlul_pkg::tl_d2h_t tl_reg_d2h; + // incoming payload check + logic chk_err; + tlul_payload_chk u_chk ( + .tl_i, + .err_o(chk_err) + ); + + // outgoing payload generation + tlul_pkg::tl_d2h_t tl_o_pre; + tlul_gen_payload_chk u_gen_chk ( + .tl_i(tl_o_pre), + .tl_o + ); + % if num_wins == 0: assign tl_reg_h2d = tl_i; - assign tl_o = tl_reg_d2h; + assign tl_o_pre = tl_reg_d2h; % else: tlul_pkg::tl_h2d_t tl_socket_h2d [${num_dsp}]; tlul_pkg::tl_d2h_t tl_socket_d2h [${num_dsp}]; @@ -97,7 +111,7 @@ .clk_i, .rst_ni, .tl_h_i (tl_i), - .tl_h_o (tl_o), + .tl_h_o (tl_o_pre), .tl_d_o (tl_socket_h2d), .tl_d_i (tl_socket_d2h), .dev_select_i (reg_steer) @@ -122,6 +136,9 @@ reg_steer = ${i}; end % endfor + if (chk_err) begin + reg_steer = ${num_dsp-1}; + end end % endif @@ -145,7 +162,7 @@ ); assign reg_rdata = reg_rdata_next ; - assign reg_error = (devmode_i & addrmiss) | wr_err ; + assign reg_error = (devmode_i & addrmiss) | wr_err | chk_err; // Define SW related signals // Format: <reg>_<field>_{wd|we|qs}