refactor(fpga): Replace tlgen xbar with Chisel-based KelvinXbar This commit replaces the legacy `tlgen`-based crossbar with the new, data-driven Chisel-based `KelvinXbar` in the FPGA design. This change simplifies the build system, improves maintainability, and provides a more flexible and robust interconnect. Key changes: - Removed the `tlgen` and `post_process_xbar.py` infrastructure from the FPGA build system. - Instantiated the new `KelvinXbar` in `kelvin_soc.sv`, replacing the old crossbar and all associated width-sizers. - Updated the clocking and reset logic to support the new crossbar's asynchronous domains, placing the Ibex core on its own clock. - Removed the now-redundant Verilog implementations of the TileLink-UL primitives (FIFOs, sockets, width bridges). - Added integrity generation to the `CoreTlul` module to ensure data integrity on the TileLink bus. - Increased the FPGA clock frequency to 80MHz. Change-Id: I340658419ca5cc93acee481c16334aeb026b2e7e
diff --git a/fpga/BUILD b/fpga/BUILD index f221189..4d8dc81 100644 --- a/fpga/BUILD +++ b/fpga/BUILD
@@ -16,57 +16,10 @@ load("@lowrisc_opentitan_gh//rules:fusesoc.bzl", "fusesoc_build") load("//rules:kelvin_v2.bzl", "kelvin_v2_binary") load("//rules:utils.bzl", "cc_embed_data") -load(":rules.bzl", "tlgen_rule") package(default_visibility = ["//visibility:public"]) -_CLOCK_FREQUENCY_MHZ = "10" - -# This is the tlgen.py script itself -py_binary( - name = "tlgen_tool", - srcs = ["@lowrisc_opentitan_gh//util:tlgen.py"], - main = "@lowrisc_opentitan_gh//util:tlgen.py", - deps = [ - "@kelvin_pip_deps_hjson//:pkg", - "@lowrisc_opentitan_gh//util/tlgen", - ], -) - -tlgen_rule( - name = "tl_crossbar_generated", - topcfg = "tl_config.hjson", -) - -py_binary( - name = "post_process_xbar", - srcs = ["post_process_xbar.py"], -) - -genrule( - name = "tl_crossbar_processed", - srcs = [":tl_crossbar_generated"], - outs = [ - "tl_crossbar_processed_out", - ], - cmd = "$(execpath :post_process_xbar) " + - "--input-dir $(location :tl_crossbar_generated) " + - "--output-dir $(location tl_crossbar_processed_out) " + - "--cores kelvinv2:ip:kelvin_tlul:0.1", - tools = [":post_process_xbar"], -) - -filegroup( - name = "tl_crossbar", - srcs = [ - ":tl_crossbar_processed_out", - ], -) - -filegroup( - name = "tl_crossbar_core", - srcs = [":tl_crossbar"], -) +_CLOCK_FREQUENCY_MHZ = "80" filegroup( name = "rtl_files", @@ -75,7 +28,7 @@ "//fpga/ip/rv_core_ibex:rtl_files", "//fpga/ip/rvv_core_mini_tlul:rtl_files", "//fpga/ip/sram:rtl_files", - "//fpga/ip/tlul_width_bridge:rtl_files", + "//fpga/ip/xbar_kelvin_soc_chisel:rtl_files", "//fpga/rtl:rtl_files", ], ) @@ -144,10 +97,11 @@ KELVIN_SOC_CORES = [ "//fpga/ip/rv_core_ibex:rv_core_ibex.core", + "//fpga/ip/rvv_core_mini_tlul:rvv_core_mini_tlul.core", + "//fpga/ip/xbar_kelvin_soc_chisel:xbar_kelvin_soc_chisel.core", ":kelvin_soc.core", ":kelvin_soc_pkg.core", ":racl_pkg.core", - ":tl_crossbar_core", "@lowrisc_opentitan_gh//hw:check_tool_requirements.core", ] @@ -202,8 +156,6 @@ _PREFIX = "../../../../../../../../.." -# "../../../../../../../"bazel-out/k8-fastbuild-ST-be77d280135c/bin/fpga -# "../../../../../../../"bazel-out/k8-fastbuild-ST-be77d280135c/bin/fpga/wfi.vmem _IBEX_BOOT_ROM_VMEM = ":ibex_boot_rom.vmem" IBEX_BOOT_ROM_VMEM_PATH = "{}/$(location {})".format(_PREFIX, _IBEX_BOOT_ROM_VMEM) @@ -221,15 +173,7 @@ "--ClockFrequencyMhz=" + _CLOCK_FREQUENCY_MHZ, ], output_groups = { - # /home/atv/.cache/bazel/_bazel_atv/cb485e413f28624e05d5dee28237de6d/sandbox/ - # linux-sandbox/34/execroot/kelvin_hw/bazel-out/k8-fastbuild/bin/fpga/ - # build.build_chip_nexus_bitstream/ - # com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/impl_1/chip_nexus.bit "bitstream": ["com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/impl_1/chip_nexus.bit"], - # /home/atv/.cache/bazel/_bazel_atv/cb485e413f28624e05d5dee28237de6d/sandbox/ - # linux-sandbox/34/execroot/kelvin_hw/bazel-out/k8-fastbuild/bin/fpga/ - # build.build_chip_nexus_bitstream/ - # com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/ "logs": ["com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/"], }, systems = ["com.google.kelvin:fpga:chip_nexus:0.1"],
diff --git a/fpga/chip_nexus.core b/fpga/chip_nexus.core index 912ddaf..4d930dd 100644 --- a/fpga/chip_nexus.core +++ b/fpga/chip_nexus.core
@@ -25,7 +25,7 @@ ClockFrequencyMhz: datatype: int description: "Target clock frequency in MHz." - default: 10 + default: 80 paramtype: vlogparam MemInitFile: datatype: str
diff --git a/fpga/chip_verilator.core b/fpga/chip_verilator.core index 0971b5a..343866e 100644 --- a/fpga/chip_verilator.core +++ b/fpga/chip_verilator.core
@@ -6,7 +6,6 @@ files_rtl: depend: - com.google.kelvin:fpga:kelvin_soc:0.2 - - kelvinv2:ip:sram:0.1 - kelvinv2:ip:kelvin_tlul:0.1 - lowrisc:dv_dpi_c:uartdpi:0.1 - lowrisc:dv_dpi_sv:uartdpi:0.1 @@ -25,7 +24,7 @@ ClockFrequencyMhz: datatype: int description: "Target clock frequency in MHz." - default: 10 + default: 80 paramtype: vlogparam MemInitFile: datatype: str
diff --git a/fpga/ip/kelvin_tlul/kelvin_tlul.core b/fpga/ip/kelvin_tlul/kelvin_tlul.core index 37336d3..f189753 100644 --- a/fpga/ip/kelvin_tlul/kelvin_tlul.core +++ b/fpga/ip/kelvin_tlul/kelvin_tlul.core
@@ -9,10 +9,6 @@ files: - kelvin_tlul_pkg_128.sv - kelvin_tlul_pkg_32.sv - - tlul_fifo_async_128.sv - - tlul_fifo_sync_128.sv - - tlul_socket_1n_128.sv - - tlul_socket_m1_128.sv file_type: systemVerilogSource targets:
diff --git a/fpga/ip/kelvin_tlul/tlul_fifo_async_128.sv b/fpga/ip/kelvin_tlul/tlul_fifo_async_128.sv deleted file mode 100644 index 22894bb..0000000 --- a/fpga/ip/kelvin_tlul/tlul_fifo_async_128.sv +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// TL-UL fifo, used to add elasticity or an asynchronous clock crossing -// to an TL-UL bus. This instantiates two FIFOs, one for the request side, -// and one for the response side. - -`include "prim_assert.sv" - -module tlul_fifo_async_128 - #(parameter int unsigned ReqDepth = 4, - parameter int unsigned RspDepth = 4) - (input clk_h_i, - input rst_h_ni, - input clk_d_i, - input rst_d_ni, - input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i, - output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o, - output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o, - input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i); - - // Put everything on the request side into one FIFO - localparam int unsigned REQFIFO_WIDTH = - $bits(kelvin_tlul_pkg_128::tl_h2d_t) - 2; - - prim_fifo_async #(.Width(REQFIFO_WIDTH), - .Depth(ReqDepth), - .OutputZeroIfInvalid(1)) - reqfifo(.clk_wr_i(clk_h_i), - .rst_wr_ni(rst_h_ni), - .clk_rd_i(clk_d_i), - .rst_rd_ni(rst_d_ni), - .wvalid_i(tl_h_i.a_valid), - .wready_o(tl_h_o.a_ready), - .wdata_i({tl_h_i.a_opcode, tl_h_i.a_param, tl_h_i.a_size, - tl_h_i.a_source, tl_h_i.a_address, tl_h_i.a_mask, - tl_h_i.a_data, tl_h_i.a_user}), - .rvalid_o(tl_d_o.a_valid), - .rready_i(tl_d_i.a_ready), - .rdata_o({tl_d_o.a_opcode, tl_d_o.a_param, tl_d_o.a_size, - tl_d_o.a_source, tl_d_o.a_address, tl_d_o.a_mask, - tl_d_o.a_data, tl_d_o.a_user}), - .wdepth_o(), - .rdepth_o()); - - // Put everything on the response side into the other FIFO - - localparam int unsigned RSPFIFO_WIDTH = - $bits(kelvin_tlul_pkg_128::tl_d2h_t) - 2; - - prim_fifo_async #(.Width(RSPFIFO_WIDTH), - .Depth(RspDepth), - .OutputZeroIfInvalid(1)) - rspfifo(.clk_wr_i(clk_d_i), - .rst_wr_ni(rst_d_ni), - .clk_rd_i(clk_h_i), - .rst_rd_ni(rst_h_ni), - .wvalid_i(tl_d_i.d_valid), - .wready_o(tl_d_o.d_ready), - .wdata_i({tl_d_i.d_opcode, tl_d_i.d_param, tl_d_i.d_size, - tl_d_i.d_source, tl_d_i.d_sink, tl_d_i.d_data, - tl_d_i.d_user, tl_d_i.d_error}), - .rvalid_o(tl_h_o.d_valid), - .rready_i(tl_h_i.d_ready), - .rdata_o({tl_h_o.d_opcode, tl_h_o.d_param, tl_h_o.d_size, - tl_h_o.d_source, tl_h_o.d_sink, tl_h_o.d_data, - tl_h_o.d_user, tl_h_o.d_error}), - .wdepth_o(), - .rdepth_o()); -endmodule
diff --git a/fpga/ip/kelvin_tlul/tlul_fifo_sync_128.sv b/fpga/ip/kelvin_tlul/tlul_fifo_sync_128.sv deleted file mode 100644 index af404f1..0000000 --- a/fpga/ip/kelvin_tlul/tlul_fifo_sync_128.sv +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// TL-UL fifo, used to add elasticity or an asynchronous clock crossing -// to an TL-UL bus. This instantiates two FIFOs, one for the request side, -// and one for the response side. - -module tlul_fifo_sync_128 - #(parameter bit ReqPass = 1'b1, - parameter bit RspPass = 1'b1, - parameter int unsigned ReqDepth = 2, - parameter int unsigned RspDepth = 2, - parameter int unsigned SpareReqW = 1, - parameter int unsigned SpareRspW = 1) - (input clk_i, - input rst_ni, - input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i, - output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o, - output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o, - input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i, - input [SpareReqW - 1 : 0] spare_req_i, - output [SpareReqW - 1 : 0] spare_req_o, - input [SpareRspW - 1 : 0] spare_rsp_i, - output [SpareRspW - 1 : 0] spare_rsp_o); - import kelvin_tlul_pkg_128::*; - // Put everything on the request side into one FIFO - localparam int unsigned REQFIFO_WIDTH = $bits(kelvin_tlul_pkg_128::tl_h2d_t) - - 2 + SpareReqW; - - prim_fifo_sync #(.Width(REQFIFO_WIDTH), - .Pass(ReqPass), - .Depth(ReqDepth)) - reqfifo(.clk_i, - .rst_ni, - .clr_i(1'b0), - .wvalid_i(tl_h_i.a_valid), - .wready_o(tl_h_o.a_ready), - .wdata_i({tl_h_i.a_opcode, tl_h_i.a_param, tl_h_i.a_size, - tl_h_i.a_source, tl_h_i.a_address, tl_h_i.a_mask, - tl_h_i.a_data, tl_h_i.a_user, spare_req_i}), - .rvalid_o(tl_d_o.a_valid), - .rready_i(tl_d_i.a_ready), - .rdata_o({tl_d_o.a_opcode, tl_d_o.a_param, tl_d_o.a_size, - tl_d_o.a_source, tl_d_o.a_address, tl_d_o.a_mask, - tl_d_o.a_data, tl_d_o.a_user, spare_req_o}), - .full_o(), - .depth_o(), - .err_o()); - - // Put everything on the response side into the other FIFO - - localparam int unsigned RSPFIFO_WIDTH = $bits(kelvin_tlul_pkg_128::tl_d2h_t) - - 2 + SpareRspW; - - prim_fifo_sync #(.Width(RSPFIFO_WIDTH), - .Pass(RspPass), - .Depth(RspDepth)) - rspfifo(.clk_i, - .rst_ni, - .clr_i(1'b0), - .wvalid_i(tl_d_i.d_valid), - .wready_o(tl_d_o.d_ready), - .wdata_i({tl_d_i.d_opcode, tl_d_i.d_param, tl_d_i.d_size, - tl_d_i.d_source, tl_d_i.d_sink, - (tl_d_i.d_opcode == tlul_pkg::AccessAckData) - ? tl_d_i.d_data - : {kelvin_tlul_pkg_128::TL_DW{1'b0}}, - tl_d_i.d_user, tl_d_i.d_error, spare_rsp_i}), - .rvalid_o(tl_h_o.d_valid), - .rready_i(tl_h_i.d_ready), - .rdata_o({tl_h_o.d_opcode, tl_h_o.d_param, tl_h_o.d_size, - tl_h_o.d_source, tl_h_o.d_sink, tl_h_o.d_data, - tl_h_o.d_user, tl_h_o.d_error, spare_rsp_o}), - .full_o(), - .depth_o(), - .err_o()); -endmodule
diff --git a/fpga/ip/kelvin_tlul/tlul_socket_1n_128.sv b/fpga/ip/kelvin_tlul/tlul_socket_1n_128.sv deleted file mode 100644 index 2b333f0..0000000 --- a/fpga/ip/kelvin_tlul/tlul_socket_1n_128.sv +++ /dev/null
@@ -1,243 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// TL-UL socket 1:N module -// -// configuration settings -// device_count: 4 -// -// Verilog parameters -// HReqPass: if 1 then host requests can pass through on empty fifo, -// default 1 -// HRspPass: if 1 then host responses can pass through on empty fifo, -// default 1 -// DReqPass: (one per device_count) if 1 then device i requests can -// pass through on empty fifo, default 1 -// DRspPass: (one per device_count) if 1 then device i responses can -// pass through on empty fifo, default 1 -// HReqDepth: Depth of host request FIFO, default 2 -// HRspDepth: Depth of host response FIFO, default 2 -// DReqDepth: (one per device_count) Depth of device i request FIFO, -// default 2 -// DRspDepth: (one per device_count) Depth of device i response FIFO, -// default 2 -// ExplicitErrs: This module always returns a request error if dev_select_i -// is greater than N-1. If ExplicitErrs is set then the width -// of the dev_select_i signal will be chosen to make sure that -// this is possible. This only makes a difference if N is a -// power of 2. -// -// Requests must stall to one device until all responses from other devices -// have returned. Need to keep a counter of all outstanding requests and -// wait until that counter is zero before switching devices. -// -// This module will return a request error if the input value of 'dev_select_i' -// is not within the range 0..N-1. Thus the instantiator of the socket -// can indicate error by any illegal value of dev_select_i. 4'b1111 is -// recommended for visibility -// -// The maximum value of N is 63 - -`include "prim_assert.sv" - -module tlul_socket_1n_128 - #(parameter int unsigned N = 4, - parameter bit HReqPass = 1'b1, - parameter bit HRspPass = 1'b1, - parameter bit [N - 1 : 0] DReqPass = {N{1'b1}}, - parameter bit [N - 1 : 0] DRspPass = {N{1'b1}}, - parameter bit [3 : 0] HReqDepth = 4'h1, - parameter bit [3 : 0] HRspDepth = 4'h1, - parameter bit [N * 4 - 1 : 0] DReqDepth = {N{4'h1}}, - parameter bit [N * 4 - 1 : 0] DRspDepth = {N{4'h1}}, - parameter bit ExplicitErrs = 1'b1, - - // The width of dev_select_i. We must be able to select any of the N - // devices (i.e. values 0..N-1). If ExplicitErrs is set, we also need to - // be able to represent N. - localparam int unsigned NWD = $clog2(ExplicitErrs ? N + 1 : N)) - (input clk_i, - input rst_ni, - input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i, - output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o, - output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o[N], - input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i[N], - input [NWD - 1 : 0] dev_select_i); - - `ASSERT_INIT(maxN, N < 64) - - // Since our steering is done after potential FIFOing, we need to - // shove our device select bits into spare bits of reqfifo - - // instantiate the host fifo, create intermediate bus 't' - - // FIFO'd version of device select - logic [NWD - 1 : 0] dev_select_t; - - kelvin_tlul_pkg_128::tl_h2d_t tl_t_o; - kelvin_tlul_pkg_128::tl_d2h_t tl_t_i; - - tlul_fifo_sync_128 #(.ReqPass(HReqPass), - .RspPass(HRspPass), - .ReqDepth(HReqDepth), - .RspDepth(HRspDepth), - .SpareReqW(NWD)) - fifo_h(.clk_i, - .rst_ni, - .tl_h_i, - .tl_h_o, - .tl_d_o(tl_t_o), - .tl_d_i(tl_t_i), - .spare_req_i(dev_select_i), - .spare_req_o(dev_select_t), - .spare_rsp_i(1'b0), - .spare_rsp_o()); - - // We need to keep track of how many requests are outstanding, - // and to which device. New requests are compared to this and - // stall until that number is zero. - localparam int MaxOutstanding = - 2 ** top_pkg::TL_AIW; // Up to 256 outstanding - localparam int OutstandingW = $clog2(MaxOutstanding + 1); - logic [OutstandingW - 1 : 0] num_req_outstanding; - logic [NWD - 1 : 0] dev_select_outstanding; - logic hold_all_requests; - logic accept_t_req, accept_t_rsp; - - assign accept_t_req = tl_t_o.a_valid & tl_t_i.a_ready; - assign accept_t_rsp = tl_t_i.d_valid & tl_t_o.d_ready; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - num_req_outstanding <= '0; - dev_select_outstanding <= '0; - end else if (accept_t_req) begin - if (!accept_t_rsp) begin - num_req_outstanding <= num_req_outstanding + 1'b1; - end - dev_select_outstanding <= dev_select_t; - end else if (accept_t_rsp) begin - num_req_outstanding <= num_req_outstanding - 1'b1; - end - end - - `ASSERT(NotOverflowed_A, accept_t_req && !accept_t_rsp -> - num_req_outstanding <= MaxOutstanding) - - assign hold_all_requests = (num_req_outstanding != '0) & - (dev_select_t != dev_select_outstanding); - - // Make N copies of 't' request side with modified reqvalid, call - // them 'u[0]' .. 'u[n-1]'. - - kelvin_tlul_pkg_128::tl_h2d_t tl_u_o[N + 1]; - kelvin_tlul_pkg_128::tl_d2h_t tl_u_i[N + 1]; - - // ensure that when a device is not selected, both command - // data integrity can never match - kelvin_tlul_pkg_128::tl_a_user_t blanked_auser; - assign blanked_auser = '{ - rsvd: tl_t_o.a_user.rsvd, - instr_type: tl_t_o.a_user.instr_type, - cmd_intg: kelvin_tlul_pkg_128::get_bad_cmd_intg(tl_t_o), - data_intg: kelvin_tlul_pkg_128::get_bad_data_intg( - kelvin_tlul_pkg_128::BlankedAData) - }; - - // if a host is not selected, or if requests are held off, blank the bus - for (genvar i = 0; i < N; i++) begin : gen_u_o - logic dev_select; - assign dev_select = dev_select_t == NWD'(i) & ~hold_all_requests; - - assign tl_u_o[i].a_valid = tl_t_o.a_valid & dev_select; - assign tl_u_o[i].a_opcode = tl_t_o.a_opcode; - assign tl_u_o[i].a_param = tl_t_o.a_param; - assign tl_u_o[i].a_size = tl_t_o.a_size; - assign tl_u_o[i].a_source = tl_t_o.a_source; - assign tl_u_o[i].a_address = tl_t_o.a_address; - assign tl_u_o[i].a_mask = tl_t_o.a_mask; - assign tl_u_o[i].a_data = - dev_select ? tl_t_o.a_data : kelvin_tlul_pkg_128::BlankedAData; - assign tl_u_o[i].a_user = dev_select ? tl_t_o.a_user : blanked_auser; - - assign tl_u_o[i].d_ready = tl_t_o.d_ready; - end - - kelvin_tlul_pkg_128::tl_d2h_t tl_t_p; - - // for the returning reqready, only look at the device we're addressing - logic hfifo_reqready; - always_comb begin - hfifo_reqready = tl_u_i[N].a_ready; // default to error - for (int idx = 0; idx < N; idx++) begin - // if (dev_select_outstanding == NWD'(idx)) hfifo_reqready = - // tl_u_i[idx].a_ready; - if (dev_select_t == NWD'(idx)) hfifo_reqready = tl_u_i[idx].a_ready; - end - if (hold_all_requests) hfifo_reqready = 1'b0; - end - // Adding a_valid as a qualifier. This prevents the a_ready from having - // unknown value when the address is unknown and the Host TL-UL FIFO is bypass - // mode. - assign tl_t_i.a_ready = tl_t_o.a_valid & hfifo_reqready; - - always_comb begin - tl_t_p = tl_u_i[N]; - for (int idx = 0; idx < N; idx++) begin - if (dev_select_outstanding == NWD'(idx)) tl_t_p = tl_u_i[idx]; - end - end - assign tl_t_i.d_valid = tl_t_p.d_valid; - assign tl_t_i.d_opcode = tl_t_p.d_opcode; - assign tl_t_i.d_param = tl_t_p.d_param; - assign tl_t_i.d_size = tl_t_p.d_size; - assign tl_t_i.d_source = tl_t_p.d_source; - assign tl_t_i.d_sink = tl_t_p.d_sink; - assign tl_t_i.d_data = tl_t_p.d_data; - assign tl_t_i.d_user = tl_t_p.d_user; - assign tl_t_i.d_error = tl_t_p.d_error; - - // Instantiate all the device FIFOs - for (genvar i = 0; i < N; i++) begin : gen_dfifo - tlul_fifo_sync_128 #(.ReqPass(DReqPass[i]), - .RspPass(DRspPass[i]), - .ReqDepth(DReqDepth[i * 4 +: 4]), - .RspDepth(DRspDepth[i * 4 +: 4])) - fifo_d(.clk_i, - .rst_ni, - .tl_h_i(tl_u_o[i]), - .tl_h_o(tl_u_i[i]), - .tl_d_o(tl_d_o[i]), - .tl_d_i(tl_d_i[i]), - .spare_req_i(1'b0), - .spare_req_o(), - .spare_rsp_i(1'b0), - .spare_rsp_o()); - end - - // Instantiate the error responder. It's only needed if a value greater than - // N-1 is actually representable in NWD bits. - if ($clog2(N + 1) <= NWD) begin : gen_err_resp - assign tl_u_o[N].d_ready = tl_t_o.d_ready; - assign tl_u_o[N].a_valid = - tl_t_o.a_valid & (dev_select_t >= NWD'(N)) & ~hold_all_requests; - assign tl_u_o[N].a_opcode = tl_t_o.a_opcode; - assign tl_u_o[N].a_param = tl_t_o.a_param; - assign tl_u_o[N].a_size = tl_t_o.a_size; - assign tl_u_o[N].a_source = tl_t_o.a_source; - assign tl_u_o[N].a_address = tl_t_o.a_address; - assign tl_u_o[N].a_mask = tl_t_o.a_mask; - assign tl_u_o[N].a_data = tl_t_o.a_data; - assign tl_u_o[N].a_user = tl_t_o.a_user; - tlul_err_resp err_resp(.clk_i, - .rst_ni, - .tl_h_i(tl_u_o[N]), - .tl_h_o(tl_u_i[N])); - end else begin : gen_no_err_resp // block: gen_err_resp - assign tl_u_o[N] = '0; - assign tl_u_i[N] = '0; - logic unused_sig; - assign unused_sig = ^tl_u_o[N]; - end -endmodule
diff --git a/fpga/ip/kelvin_tlul/tlul_socket_m1_128.sv b/fpga/ip/kelvin_tlul/tlul_socket_m1_128.sv deleted file mode 100644 index cded907..0000000 --- a/fpga/ip/kelvin_tlul/tlul_socket_m1_128.sv +++ /dev/null
@@ -1,243 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// TL-UL socket M:1 module -// -// Verilog parameters -// M: Number of host ports. -// HReqPass: M bit array to allow requests to pass through the host i -// FIFO with no clock delay if the request FIFO is empty. If -// 1'b0, at least one clock cycle of latency is created. -// Default is 1'b1. -// HRspPass: Same as HReqPass but for host response FIFO. -// HReqDepth: Mx4 bit array. bit[i*4+:4] is depth of host i request FIFO. -// Depth of zero is allowed if ReqPass is true. A maximum value -// of 16 is allowed, default is 2. -// HRspDepth: Same as HReqDepth but for host response FIFO. -// DReqPass: Same as HReqPass but for device request FIFO. -// DRspPass: Same as HReqPass but for device response FIFO. -// DReqDepth: Same as HReqDepth but for device request FIFO. -// DRspDepth: Same as HReqDepth but for device response FIFO. - -`include "prim_assert.sv" - -module tlul_socket_m1_128 - #(parameter int unsigned M = 4, - parameter bit [M - 1 : 0] HReqPass = {M{1'b1}}, - parameter bit [M - 1 : 0] HRspPass = {M{1'b1}}, - parameter bit [M * 4 - 1 : 0] HReqDepth = {M{4'h1}}, - parameter bit [M * 4 - 1 : 0] HRspDepth = {M{4'h1}}, - parameter bit DReqPass = 1'b1, - parameter bit DRspPass = 1'b1, - parameter bit [3 : 0] DReqDepth = 4'h1, - parameter bit [3 : 0] DRspDepth = 4'h1) - (input clk_i, - input rst_ni, - - input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i[M], - output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o[M], - - output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o, - input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i); - - `ASSERT_INIT(maxM, M < 16) - - // Signals - // - // tl_h_i/o[0] | tl_h_i/o[1] | ... | tl_h_i/o[M-1] - // | | | - // u_hostfifo[0] u_hostfifo[1] u_hostfifo[M-1] - // | | | - // hreq_fifo_o(i) / hrsp_fifo_i(i) - // --------------------------------------- - // | request/grant/req_data | - // | | - // | PRIM_ARBITER | - // | | - // | arb_valid / arb_ready / arb_data | - // --------------------------------------- - // | - // dreq_fifo_i / drsp_fifo_o - // | - // u_devicefifo - // | - // tl_d_o/i - // - // Required ID width to distinguish between host ports - // Used in response steering - localparam int unsigned IDW = top_pkg::TL_AIW; - localparam int unsigned STIDW = $clog2(M); - - kelvin_tlul_pkg_128::tl_h2d_t hreq_fifo_o[M]; - kelvin_tlul_pkg_128::tl_d2h_t hrsp_fifo_i[M]; - - logic [M - 1 : 0] hrequest; - logic [M - 1 : 0] hgrant; - - kelvin_tlul_pkg_128::tl_h2d_t dreq_fifo_i; - kelvin_tlul_pkg_128::tl_d2h_t drsp_fifo_o; - - logic arb_valid; - logic arb_ready; - kelvin_tlul_pkg_128::tl_h2d_t arb_data; - - // Host Req/Rsp FIFO - for (genvar i = 0; i < M; i++) begin : gen_host_fifo - kelvin_tlul_pkg_128::tl_h2d_t hreq_fifo_i; - - // ID Shifting - logic [STIDW - 1 : 0] reqid_sub; - logic [IDW - 1 : 0] shifted_id; - assign reqid_sub = i; // can cause conversion error? - assign shifted_id = {tl_h_i[i].a_source[0 +: (IDW - STIDW)], reqid_sub}; - - `ASSERT(idInRange, tl_h_i[i].a_valid |-> - tl_h_i[i].a_source[IDW - 1 -: STIDW] == '0) - - // assign not connected bits to nc_* signal to make lint happy - logic [IDW - 1 : IDW - STIDW] unused_tl_h_source; - assign unused_tl_h_source = tl_h_i[i].a_source[IDW - 1 -: STIDW]; - - // Put shifted ID - assign hreq_fifo_i = '{ - a_valid: tl_h_i[i].a_valid, - a_opcode: tl_h_i[i].a_opcode, - a_param: tl_h_i[i].a_param, - a_size: tl_h_i[i].a_size, - a_source: shifted_id, - a_address: tl_h_i[i].a_address, - a_mask: tl_h_i[i].a_mask, - a_data: tl_h_i[i].a_data, - a_user: tl_h_i[i].a_user, - d_ready: tl_h_i[i].d_ready - }; - - tlul_fifo_sync_128 #(.ReqPass(HReqPass[i]), - .RspPass(HRspPass[i]), - .ReqDepth(HReqDepth[i * 4 +: 4]), - .RspDepth(HRspDepth[i * 4 +: 4]), - .SpareReqW(1)) - u_hostfifo(.clk_i, - .rst_ni, - .tl_h_i(hreq_fifo_i), - .tl_h_o(tl_h_o[i]), - .tl_d_o(hreq_fifo_o[i]), - .tl_d_i(hrsp_fifo_i[i]), - .spare_req_i(1'b0), - .spare_req_o(), - .spare_rsp_i(1'b0), - .spare_rsp_o()); - end - - // Device Req/Rsp FIFO - tlul_fifo_sync_128 #(.ReqPass(DReqPass), - .RspPass(DRspPass), - .ReqDepth(DReqDepth), - .RspDepth(DRspDepth), - .SpareReqW(1)) - u_devicefifo(.clk_i, - .rst_ni, - .tl_h_i(dreq_fifo_i), - .tl_h_o(drsp_fifo_o), - .tl_d_o(tl_d_o), - .tl_d_i(tl_d_i), - .spare_req_i(1'b0), - .spare_req_o(), - .spare_rsp_i(1'b0), - .spare_rsp_o()); - - // Request Arbiter - for (genvar i = 0; i < M; i++) begin : gen_arbreqgnt - assign hrequest[i] = hreq_fifo_o[i].a_valid; - end - - assign arb_ready = drsp_fifo_o.a_ready; - - if (kelvin_tlul_pkg_128::ArbiterImpl == "PPC") begin : gen_arb_ppc - prim_arbiter_ppc #(.N(M), - .DW($bits(kelvin_tlul_pkg_128::tl_h2d_t))) - u_reqarb(.clk_i, - .rst_ni, - .req_chk_i(1'b0), - // TL-UL allows dropping valid without ready. See #3354. - .req_i(hrequest), - .data_i(hreq_fifo_o), - .gnt_o(hgrant), - .idx_o(), - .valid_o(arb_valid), - .data_o(arb_data), - .ready_i(arb_ready)); - end else if (kelvin_tlul_pkg_128::ArbiterImpl == "BINTREE") - begin : gen_tree_arb - prim_arbiter_tree #(.N(M), - .DW($bits(kelvin_tlul_pkg_128::tl_h2d_t))) - u_reqarb(.clk_i, - .rst_ni, - .req_chk_i(1'b0), - // TL-UL allows dropping valid without ready. See #3354. - .req_i(hrequest), - .data_i(hreq_fifo_o), - .gnt_o(hgrant), - .idx_o(), - .valid_o(arb_valid), - .data_o(arb_data), - .ready_i(arb_ready)); - end else begin : gen_unknown - `ASSERT_INIT(UnknownArbImpl_A, 0) - end - - logic [M - 1 : 0] hfifo_rspvalid; - logic [M - 1 : 0] dfifo_rspready; - logic [IDW - 1 : 0] hfifo_rspid; - logic dfifo_rspready_merged; - - // arb_data --> dreq_fifo_i - // dreq_fifo_i.hd_rspready <= dfifo_rspready - - assign dfifo_rspready_merged = |dfifo_rspready; - assign dreq_fifo_i = '{ - a_valid: arb_valid, - a_opcode: arb_data.a_opcode, - a_param: arb_data.a_param, - a_size: arb_data.a_size, - a_source: arb_data.a_source, - a_address: arb_data.a_address, - a_mask: arb_data.a_mask, - a_data: arb_data.a_data, - a_user: arb_data.a_user, - - d_ready: dfifo_rspready_merged - }; - - // Response ID steering - // drsp_fifo_o --> hrsp_fifo_i[i] - - // Response ID shifting before put into host fifo - assign hfifo_rspid = {{STIDW{1'b0}}, drsp_fifo_o.d_source[IDW - 1 : STIDW]}; - for (genvar i = 0; i < M; i++) begin : gen_idrouting - assign hfifo_rspvalid[i] = - drsp_fifo_o.d_valid & (drsp_fifo_o.d_source[0 +: STIDW] == i); - assign dfifo_rspready[i] = hreq_fifo_o[i].d_ready & - (drsp_fifo_o.d_source[0 +: STIDW] == i) & - drsp_fifo_o.d_valid; - - assign hrsp_fifo_i[i] = '{ - d_valid: hfifo_rspvalid[i], - d_opcode: drsp_fifo_o.d_opcode, - d_param: drsp_fifo_o.d_param, - d_size: drsp_fifo_o.d_size, - d_source: hfifo_rspid, - d_sink: drsp_fifo_o.d_sink, - d_data: drsp_fifo_o.d_data, - d_user: drsp_fifo_o.d_user, - d_error: drsp_fifo_o.d_error, - a_ready: hgrant[i] - }; - end - - // this assertion fails when rspid[0+:STIDW] not in [0..M-1] - `ASSERT(rspIdInRange, drsp_fifo_o.d_valid |-> - drsp_fifo_o.d_source[0 +: STIDW] >= 0 && - drsp_fifo_o.d_source[0 +: STIDW] < M) -endmodule
diff --git a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.core b/fpga/ip/tlul_width_bridge/tlul_device_downsizer.core deleted file mode 100644 index 5cc6203..0000000 --- a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.core +++ /dev/null
@@ -1,32 +0,0 @@ -CAPI=2: -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: "kelvinv2:ip:tlul_device_downsizer" -description: "TL-UL Device Downsizer" - -filesets: - files_rtl: - depend: - - "lowrisc:prim:all" - - "lowrisc:tlul:headers" - - "kelvinv2:ip:kelvin_tlul:0.1" - files: - - tlul_device_downsizer.sv: { file_type: systemVerilogSource } - file_type: systemVerilogSource - -targets: - default: - filesets: - - files_rtl
diff --git a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.sv b/fpga/ip/tlul_width_bridge/tlul_device_downsizer.sv deleted file mode 100644 index 524fb6b..0000000 --- a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.sv +++ /dev/null
@@ -1,145 +0,0 @@ -// Copyright 2025 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -`include "prim_assert.sv" - -module tlul_device_downsizer - #(parameter int AddrWidth = 32) - (input clk_i, - input rst_ni, - - // Slave (Upsizer-facing) TL-UL Interface - input kelvin_tlul_pkg_128::tl_h2d_t s_tl_i, - output kelvin_tlul_pkg_128::tl_d2h_t s_tl_o, - - // Master (Crossbar-facing) TL-UL Interface - output kelvin_tlul_pkg_32::tl_h2d_t m_tl_o, - input kelvin_tlul_pkg_32::tl_d2h_t m_tl_i); - - localparam int SlaveDataWidth = 128; - localparam int MasterDataWidth = 32; - localparam int LaneWidth = MasterDataWidth / 8; - localparam int NumLanes = SlaveDataWidth / MasterDataWidth; - localparam int LaneIndexWidth = $clog2(NumLanes); - - // Response path skid buffer - kelvin_tlul_pkg_128::tl_d2h_t d_skid_reg; - logic d_skid_valid_q, d_skid_valid_d; - logic d_skid_ready; - - // Internal signals - logic [LaneIndexWidth - 1 : 0] lane_idx; - logic [LaneIndexWidth - 1 : 0] lane_idx_reg; - logic [MasterDataWidth - 1 : 0] m_a_data; - logic [MasterDataWidth / 8 - 1 : 0] m_a_mask; - logic [1 : 0] a_size_from_mask; - - // Lane index calculation from mask - always_comb begin - // Priority encode the mask to find the active lane - unique case (1'b1) - |s_tl_i.a_mask[3 : 0]: - lane_idx = 2'b00; - |s_tl_i.a_mask[7 : 4]: - lane_idx = 2'b01; - |s_tl_i.a_mask[11 : 8]: - lane_idx = 2'b10; - |s_tl_i.a_mask[15 : 12]: - lane_idx = 2'b11; - default: - lane_idx = 2'b00; // Should not happen for valid requests - endcase - end - - // Master port data and mask generation - always_comb begin - m_a_data = s_tl_i.a_data >> (lane_idx * MasterDataWidth); - m_a_mask = s_tl_i.a_mask >> (lane_idx * LaneWidth); - end - - // Calculate master port a_size from mask - always_comb begin - case ($countones(m_a_mask)) - 1: - a_size_from_mask = 2'h0; - 2: - a_size_from_mask = 2'h1; - 3, 4: - a_size_from_mask = 2'h2; - default: - a_size_from_mask = 2'h0; - endcase - end - - logic [15 : 0] dbg_s_tl_i_a_size = s_tl_i.a_size; - // Master port connections - assign m_tl_o.a_valid = s_tl_i.a_valid; - assign m_tl_o.a_opcode = s_tl_i.a_opcode; - assign m_tl_o.a_param = s_tl_i.a_param; - assign m_tl_o.a_size = - (s_tl_i.a_opcode == tlul_pkg::Get) ? 2 : a_size_from_mask; - assign m_tl_o.a_address = {s_tl_i.a_address[AddrWidth - 1 : 4], lane_idx, - 2'b00}; - assign m_tl_o.a_source = s_tl_i.a_source; - assign m_tl_o.a_data = m_a_data; - assign m_tl_o.a_mask = m_a_mask; - assign m_tl_o.a_user = s_tl_i.a_user; - assign m_tl_o.d_ready = d_skid_ready; - - // Slave port connections - assign s_tl_o.d_opcode = d_skid_reg.d_opcode; - assign s_tl_o.d_param = d_skid_reg.d_param; - assign s_tl_o.d_sink = d_skid_reg.d_sink; - assign s_tl_o.d_source = d_skid_reg.d_source; - assign s_tl_o.d_data = d_skid_reg.d_data; - assign s_tl_o.d_error = d_skid_reg.d_error; - assign s_tl_o.d_user = d_skid_reg.d_user; - assign s_tl_o.d_size = d_skid_reg.d_size; - assign s_tl_o.d_valid = d_skid_valid_q; - assign s_tl_o.a_ready = m_tl_i.a_ready; - logic d_skid_reg_size = d_skid_reg.d_size; - - // Skid buffer logic - assign d_skid_ready = !d_skid_valid_q || s_tl_i.d_ready; - - always_comb begin - d_skid_valid_d = d_skid_valid_q; - if (d_skid_ready) begin - d_skid_valid_d = m_tl_i.d_valid; - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - d_skid_valid_q <= 1'b0; - d_skid_reg <= '0; - lane_idx_reg <= '0; - end else begin - d_skid_valid_q <= d_skid_valid_d; - if (d_skid_ready && m_tl_i.d_valid) begin - d_skid_reg.d_opcode <= m_tl_i.d_opcode; - d_skid_reg.d_param <= m_tl_i.d_param; - d_skid_reg.d_sink <= m_tl_i.d_sink; - d_skid_reg.d_source <= m_tl_i.d_source; - d_skid_reg.d_data <= m_tl_i.d_data << (lane_idx_reg * MasterDataWidth); - d_skid_reg.d_error <= m_tl_i.d_error; - d_skid_reg.d_user <= m_tl_i.d_user; - d_skid_reg.d_size <= m_tl_i.d_size; - end - if (s_tl_i.a_valid && s_tl_o.a_ready) begin - lane_idx_reg <= lane_idx; - end - end - end -endmodule
diff --git a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.core b/fpga/ip/tlul_width_bridge/tlul_host_upsizer.core deleted file mode 100644 index 3c25112..0000000 --- a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.core +++ /dev/null
@@ -1,32 +0,0 @@ -CAPI=2: -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: "kelvinv2:ip:tlul_host_upsizer" -description: "TL-UL Host Upsizer" - -filesets: - files_rtl: - depend: - - "lowrisc:prim:all" - - "lowrisc:tlul:headers" - - "kelvinv2:ip:kelvin_tlul:0.1" - files: - - tlul_host_upsizer.sv: { file_type: systemVerilogSource } - file_type: systemVerilogSource - -targets: - default: - filesets: - - files_rtl
diff --git a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.sv b/fpga/ip/tlul_width_bridge/tlul_host_upsizer.sv deleted file mode 100644 index 6958dfd..0000000 --- a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.sv +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright 2025 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -`include "prim_assert.sv" - -module tlul_host_upsizer - #(parameter int AddrWidth = 32) - (input clk_i, - input rst_ni, - - // Slave (Host-facing) TL-UL Interface - input kelvin_tlul_pkg_32::tl_h2d_t s_tl_i, - output kelvin_tlul_pkg_32::tl_d2h_t s_tl_o, - - // Master (Crossbar-facing) TL-UL Interface - output kelvin_tlul_pkg_128::tl_h2d_t m_tl_o, - input kelvin_tlul_pkg_128::tl_d2h_t m_tl_i); - - localparam int SlaveDataWidth = 32; - localparam int MasterDataWidth = 128; - localparam int LaneWidth = SlaveDataWidth / 8; - localparam int NumLanes = MasterDataWidth / SlaveDataWidth; - localparam int LaneIndexWidth = $clog2(NumLanes); - - // Response path skid buffer - kelvin_tlul_pkg_32::tl_d2h_t d_skid_reg; - logic d_skid_valid_q, d_skid_valid_d; - logic d_skid_ready; - - // Internal signals - logic [LaneIndexWidth - 1 : 0] lane_idx; - logic [LaneIndexWidth - 1 : 0] lane_idx_reg; - logic [MasterDataWidth - 1 : 0] m_a_data; - logic [MasterDataWidth / 8 - 1 : 0] m_a_mask; - - // Lane index calculation - assign lane_idx = s_tl_i.a_address[LaneIndexWidth + 1 : 2]; - - // Master port data and mask generation - always_comb begin - m_a_data = '0; - m_a_mask = '0; - m_a_data[lane_idx * SlaveDataWidth +: SlaveDataWidth] = s_tl_i.a_data; - m_a_mask[lane_idx * LaneWidth +: LaneWidth] = s_tl_i.a_mask; - end - - // Master port connections - assign m_tl_o.a_valid = s_tl_i.a_valid; - assign m_tl_o.a_opcode = s_tl_i.a_opcode; - assign m_tl_o.a_param = s_tl_i.a_param; - assign m_tl_o.a_size = s_tl_i.a_size; - assign m_tl_o.a_address = { - s_tl_i.a_address[AddrWidth - 1 : LaneIndexWidth + 2], - {(LaneIndexWidth + 2){1'b0}}}; - assign m_tl_o.a_source = s_tl_i.a_source; - assign m_tl_o.a_data = m_a_data; - assign m_tl_o.a_mask = m_a_mask; - assign m_tl_o.a_user = s_tl_i.a_user; - assign m_tl_o.d_ready = d_skid_ready; - - // Slave port connections - assign s_tl_o.d_opcode = d_skid_reg.d_opcode; - assign s_tl_o.d_param = d_skid_reg.d_param; - assign s_tl_o.d_sink = d_skid_reg.d_sink; - assign s_tl_o.d_source = d_skid_reg.d_source; - assign s_tl_o.d_data = d_skid_reg.d_data; - assign s_tl_o.d_error = d_skid_reg.d_error; - assign s_tl_o.d_user = d_skid_reg.d_user; - assign s_tl_o.d_size = d_skid_reg.d_size; - assign s_tl_o.d_valid = d_skid_valid_q; - assign s_tl_o.a_ready = m_tl_i.a_ready; - - // Skid buffer logic - assign d_skid_ready = !d_skid_valid_q || s_tl_i.d_ready; - - always_comb begin - d_skid_valid_d = d_skid_valid_q; - if (d_skid_ready) begin - d_skid_valid_d = m_tl_i.d_valid; - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - d_skid_valid_q <= 1'b0; - d_skid_reg <= '0; - lane_idx_reg <= '0; - end else begin - d_skid_valid_q <= d_skid_valid_d; - if (d_skid_ready && m_tl_i.d_valid) begin - d_skid_reg.d_opcode <= m_tl_i.d_opcode; - d_skid_reg.d_param <= m_tl_i.d_param; - d_skid_reg.d_sink <= m_tl_i.d_sink; - d_skid_reg.d_source <= m_tl_i.d_source; - d_skid_reg.d_data <= m_tl_i.d_data >> (lane_idx_reg * SlaveDataWidth); - d_skid_reg.d_error <= m_tl_i.d_error; - d_skid_reg.d_user <= m_tl_i.d_user; - d_skid_reg.d_size <= m_tl_i.d_size; - end - if (s_tl_i.a_valid && s_tl_o.a_ready) begin - lane_idx_reg <= lane_idx; - end - end - end -endmodule \ No newline at end of file
diff --git a/fpga/ip/tlul_width_bridge/BUILD b/fpga/ip/xbar_kelvin_soc_chisel/BUILD similarity index 60% rename from fpga/ip/tlul_width_bridge/BUILD rename to fpga/ip/xbar_kelvin_soc_chisel/BUILD index d78f918..fe7f6ab 100644 --- a/fpga/ip/tlul_width_bridge/BUILD +++ b/fpga/ip/xbar_kelvin_soc_chisel/BUILD
@@ -14,10 +14,29 @@ package(default_visibility = ["//visibility:public"]) +genrule( + name = "kelvin_xbar", + srcs = ["//hdl/chisel/src/soc:KelvinXbar.sv"], + outs = ["KelvinXbar.sv"], + cmd = "cp $< $@", +) + +genrule( + name = "generate_core_file", + srcs = [ + "xbar_kelvin_soc_chisel.core.tpl", + ":kelvin_xbar", + ], + outs = ["xbar_kelvin_soc_chisel.core"], + cmd = "sed 's|__VERILOG_FILE__|KelvinXbar.sv|' $(location xbar_kelvin_soc_chisel.core.tpl) > $@", +) + filegroup( name = "rtl_files", srcs = glob([ "*.sv", "*.core", - ]), + ]) + [ + ":KelvinXbar.sv", + ], )
diff --git a/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core new file mode 100644 index 0000000..b469a7a --- /dev/null +++ b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core
@@ -0,0 +1,14 @@ +CAPI=2: +name: "kelvinv2:ip:xbar_kelvin_soc_chisel:0.1" +description: "Kelvin SoC Chisel-Generated Crossbar" + +filesets: + rtl: + files: + - KelvinXbar.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - rtl
diff --git a/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core.tpl b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core.tpl new file mode 100644 index 0000000..88044d9 --- /dev/null +++ b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core.tpl
@@ -0,0 +1,14 @@ +CAPI=2: +name: "kelvinv2:ip:xbar_kelvin_soc_chisel:0.1" +description: "Kelvin SoC Chisel-Generated Crossbar" + +filesets: + rtl: + files: + - __VERILOG_FILE__ + file_type: systemVerilogSource + +targets: + default: + filesets: + - rtl
diff --git a/fpga/kelvin_soc.core b/fpga/kelvin_soc.core index 3db97b4..7cfb9e2 100644 --- a/fpga/kelvin_soc.core +++ b/fpga/kelvin_soc.core
@@ -5,7 +5,7 @@ filesets: rtl: depend: - - lowrisc:ip:xbar_kelvin_soc_xbar:0.1 + - kelvinv2:ip:xbar_kelvin_soc_chisel:0.1 - com.google.kelvin:fpga:kelvin_soc_pkg:0.1 - com.google.kelvin:fpga:racl_pkg:0.1 - lowrisc:ip:uart:0.1 @@ -15,8 +15,6 @@ - lowrisc:ip:spi_device:0.1 - lowrisc:kelvin_ip:rv_core_ibex:0.1 - google:kelvin:rvv_core_mini_tlul - - kelvinv2:ip:tlul_host_upsizer - - kelvinv2:ip:tlul_device_downsizer - lowrisc:ibex:ibex_tracer - kelvinv2:ip:sram:0.1 - kelvinv2:ip:kelvin_tlul:0.1
diff --git a/fpga/main.cc b/fpga/main.cc index 3e1d352..bc5fe64 100644 --- a/fpga/main.cc +++ b/fpga/main.cc
@@ -45,7 +45,7 @@ memutil.RegisterMemoryArea("dtcm", 0x00010000, &dtcm); simctrl.RegisterExtension(&memutil); - simctrl.SetInitialResetDelay(20000); + simctrl.SetInitialResetDelay(2000); simctrl.SetResetDuration(10); std::cout << "Simulation of Kelvin SoC" << std::endl
diff --git a/fpga/post_process_xbar.py b/fpga/post_process_xbar.py deleted file mode 100644 index 20179ab..0000000 --- a/fpga/post_process_xbar.py +++ /dev/null
@@ -1,116 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""A script to post-process the output of tlgen. - -This script takes an input directory and an output directory. It copies the -contents of the input directory to the output directory, and then modifies the -generated SystemVerilog file to use the correct TileLink types. -""" - -import argparse -import os -import re -import shutil -import stat - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--input-dir", - required=True, - help="The input directory.", - ) - parser.add_argument( - "--output-dir", - required=True, - help="The output directory.", - ) - parser.add_argument( - "--cores", - nargs="+", - required=True, - help="The cores to add as dependencies.", - ) - args = parser.parse_args() - - # Copy the contents of the input directory to the output directory. - if os.path.exists(args.output_dir): - shutil.rmtree(args.output_dir) - shutil.copytree(args.input_dir, args.output_dir) - - # Find the generated SystemVerilog file. - sv_file = None - for root, _, files in os.walk(args.output_dir): - for f in files: - if f == "xbar_kelvin_soc_xbar.sv": - sv_file = os.path.join(root, f) - break - if sv_file: - break - - if sv_file is None: - raise RuntimeError("Could not find generated SystemVerilog file.") - - # Make the file writable. - os.chmod(sv_file, stat.S_IWRITE | stat.S_IREAD) - - # Read the file and perform the replacements. - with open(sv_file, "r") as f: - content = f.read() - original_content = content - content = content.replace("tlul_pkg::tl_h2d_t", - "kelvin_tlul_pkg_128::tl_h2d_t") - content = content.replace("tlul_pkg::tl_d2h_t", - "kelvin_tlul_pkg_128::tl_d2h_t") - content = content.replace("import tlul_pkg::*", - "import kelvin_tlul_pkg_128::*") - content = content.replace("tlul_socket_1n #", "tlul_socket_1n_128 #") - content = content.replace("tlul_socket_m1 #", "tlul_socket_m1_128 #") - content = content.replace("tlul_fifo_async #", "tlul_fifo_async_128 #") - - if original_content == content: - print("Warning: No replacements made.") - else: - print("Success: Replacements made.") - - with open(sv_file, "w") as f: - f.write(content) - - core_file = None - for root, _, files in os.walk(args.output_dir): - for f in files: - if f == "xbar_kelvin_soc_xbar.core": - core_file = os.path.join(root, f) - break - if core_file: - break - if core_file is None: - raise RuntimeError("Could not find generated core file.") - os.chmod(core_file, stat.S_IWRITE | stat.S_IREAD) - with open(core_file, "r") as f: - content = f.read() - original_content = content - for core in args.cores: - content = re.sub(r"(\s+)depend:", r"\1depend:\n\1 - " + core, content) - if original_content == content: - print("Warning: No replacements made (core).") - else: - print("Success: replacesments made (core).") - with open(core_file, "w") as f: - f.write(content) - - -if __name__ == "__main__": - main()
diff --git a/fpga/rtl/chip_nexus.sv b/fpga/rtl/chip_nexus.sv index 30f8dff..50dd228 100644 --- a/fpga/rtl/chip_nexus.sv +++ b/fpga/rtl/chip_nexus.sv
@@ -14,7 +14,7 @@ module chip_nexus #(parameter MemInitFile = "", - parameter int ClockFrequencyMhz = 10) + parameter int ClockFrequencyMhz = 80) (input clk_p_i, input clk_n_i, input rst_ni, @@ -28,6 +28,8 @@ logic clk; logic rst_n; + logic clk_ibex; + logic rst_ibex_n; logic clk_48MHz; logic clk_aon; @@ -50,12 +52,27 @@ .clk_main_o(clk), .clk_48MHz_o(clk_48MHz), .clk_aon_o(clk_aon), + .clk_ibex_o(clk_ibex), .rst_no(rst_n)); + // Reset synchronizer for Ibex reset. + logic rst_n_sync; + always_ff @(posedge clk_ibex or negedge rst_n) begin + if (!rst_n) begin + rst_n_sync <= 1'b0; + rst_ibex_n <= 1'b0; + end else begin + rst_n_sync <= 1'b1; + rst_ibex_n <= rst_n_sync; + end + end + kelvin_soc #(.MemInitFile(MemInitFile), .ClockFrequencyMhz(ClockFrequencyMhz)) i_kelvin_soc(.clk_i(clk), .rst_ni(rst_n), + .ibex_clk_i(clk_ibex), + .ibex_rst_ni(rst_ibex_n), .spi_clk_i(spi_clk_i), .scanmode_i(prim_mubi_pkg::MuBi4False), .uart_sideband_i(uart_sideband_i),
diff --git a/fpga/rtl/chip_verilator.sv b/fpga/rtl/chip_verilator.sv index b94ffcb..ce495ed 100644 --- a/fpga/rtl/chip_verilator.sv +++ b/fpga/rtl/chip_verilator.sv
@@ -14,7 +14,7 @@ module chip_verilator #(parameter MemInitFile = "", - parameter int ClockFrequencyMhz = 10) + parameter int ClockFrequencyMhz = 80) (input clk_i, input rst_ni, input spi_clk_i, @@ -52,6 +52,8 @@ .ClockFrequencyMhz(ClockFrequencyMhz)) i_kelvin_soc(.clk_i(clk_i), .rst_ni(rst_ni), + .ibex_clk_i(ibex_clk_i), + .ibex_rst_ni(ibex_rst_ni), .spi_clk_i(spi_clk_i), .scanmode_i(scanmode_i), .uart_sideband_i( @@ -62,4 +64,29 @@ assign uart0_tx = uart_sideband_o[0].cio_tx; assign uart1_tx = uart_sideband_o[1].cio_tx; + + // Clock divider for Ibex clock. + logic [1:0] clk_divider; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + clk_divider <= 2'b0; + end else begin + clk_divider <= clk_divider + 1; + end + end + logic ibex_clk_i; + assign ibex_clk_i = clk_divider[1]; + + // Reset synchronizer for Ibex reset. + logic ibex_rst_ni; + logic rst_n_sync; + always_ff @(posedge ibex_clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rst_n_sync <= 1'b0; + ibex_rst_ni <= 1'b0; + end else begin + rst_n_sync <= 1'b1; + ibex_rst_ni <= rst_n_sync; + end + end endmodule
diff --git a/fpga/rtl/clkgen_wrapper.sv b/fpga/rtl/clkgen_wrapper.sv index 55339ef..bcc8bcc 100644 --- a/fpga/rtl/clkgen_wrapper.sv +++ b/fpga/rtl/clkgen_wrapper.sv
@@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 module clkgen_wrapper - #(parameter int ClockFrequencyMhz = 10) + #(parameter int ClockFrequencyMhz = 80) (input clk_p_i, input clk_n_i, input rst_ni, @@ -11,6 +11,7 @@ output clk_main_o, output clk_48MHz_o, output clk_aon_o, + output clk_ibex_o, output rst_no); clkgen_xilultrascaleplus #(.ClockFrequencyMhz(ClockFrequencyMhz)) @@ -21,5 +22,6 @@ .clk_main_o(clk_main_o), .clk_48MHz_o(clk_48MHz_o), .clk_aon_o(clk_aon_o), + .clk_ibex_o(clk_ibex_o), .rst_no(rst_no)); endmodule \ No newline at end of file
diff --git a/fpga/rtl/clkgen_xilultrascaleplus.sv b/fpga/rtl/clkgen_xilultrascaleplus.sv index 9817265..bedc4a5 100644 --- a/fpga/rtl/clkgen_xilultrascaleplus.sv +++ b/fpga/rtl/clkgen_xilultrascaleplus.sv
@@ -14,7 +14,7 @@ // limitations under the License. module clkgen_xilultrascaleplus - #(parameter int ClockFrequencyMhz = 10, + #(parameter int ClockFrequencyMhz = 80, // Add BUFG if not done by downstream logic parameter bit AddClkBuf = 1) (input clk_i, @@ -24,6 +24,7 @@ output clk_main_o, output clk_48MHz_o, output clk_aon_o, + output clk_ibex_o, output rst_no); logic locked_pll; logic io_clk_buf; @@ -36,6 +37,8 @@ logic clk_48_unbuf; logic clk_aon_buf; logic clk_aon_unbuf; + logic clk_ibex_buf; + logic clk_ibex_unbuf; logic clk_ibufds_o; // Input IBUFDS conver diff-pair to single-end @@ -44,6 +47,7 @@ .O(clk_ibufds_o)); localparam real CLKOUT0_DIVIDE_F_CALC = 1200.0 / ClockFrequencyMhz; + localparam int CLKOUT2_DIVIDE_CALC = CLKOUT0_DIVIDE_F_CALC * 4; MMCME2_ADV #( .BANDWIDTH("OPTIMIZED"), @@ -58,6 +62,9 @@ .CLKOUT1_DIVIDE(25), .CLKOUT1_PHASE(0.000), .CLKOUT1_DUTY_CYCLE(0.500), + .CLKOUT2_DIVIDE(CLKOUT2_DIVIDE_CALC), + .CLKOUT2_PHASE(0.000), + .CLKOUT2_DUTY_CYCLE(0.500), // With CLKOUT4_CASCADE, CLKOUT6's divider is an input to CLKOUT4's // divider. The effective ratio is a multiplication of the two. .CLKOUT4_DIVIDE(40), @@ -72,7 +79,7 @@ .CLKOUT0B(), .CLKOUT1(clk_48_unbuf), .CLKOUT1B(), - .CLKOUT2(), + .CLKOUT2(clk_ibex_unbuf), .CLKOUT2B(), .CLKOUT3(), .CLKOUT3B(), @@ -120,10 +127,14 @@ BUFGCE clk_48_bufgce(.I(clk_48_unbuf), .O(clk_48_buf)); + + BUFGCE clk_ibex_bufgce(.I(clk_ibex_unbuf), + .O(clk_ibex_buf)); end else begin : gen_no_clk_bufs // BUFGs added by downstream modules, no need to add here assign clk_10_buf = clk_10_unbuf; assign clk_48_buf = clk_48_unbuf; + assign clk_ibex_buf = clk_ibex_unbuf; end // outputs @@ -131,6 +142,7 @@ assign clk_main_o = clk_10_buf; assign clk_48MHz_o = clk_48_buf; assign clk_aon_o = clk_aon_buf; + assign clk_ibex_o = clk_ibex_buf; // reset assign rst_no = locked_pll & rst_ni & srst_ni;
diff --git a/fpga/rtl/kelvin_soc.sv b/fpga/rtl/kelvin_soc.sv index 1c23def..479f887 100644 --- a/fpga/rtl/kelvin_soc.sv +++ b/fpga/rtl/kelvin_soc.sv
@@ -14,9 +14,11 @@ module kelvin_soc #(parameter MemInitFile = "", - parameter int ClockFrequencyMhz = 10) + parameter int ClockFrequencyMhz = 80) (input clk_i, input rst_ni, + input ibex_clk_i, + input ibex_rst_ni, input spi_clk_i, input prim_mubi_pkg::mubi4_t scanmode_i, input top_pkg::uart_sideband_i_t[1 : 0] uart_sideband_i, @@ -34,102 +36,257 @@ kelvin_tlul_pkg_32::tl_h2d_t tl_ibex_core_i_o_32; kelvin_tlul_pkg_32::tl_d2h_t tl_ibex_core_i_i_32; - kelvin_tlul_pkg_128::tl_h2d_t tl_ibex_core_i_o_xbar; - kelvin_tlul_pkg_128::tl_d2h_t tl_ibex_core_i_i_xbar; - - tlul_host_upsizer i_ibex_core_i_upsizer(.clk_i(clk_i), - .rst_ni(rst_ni), - .s_tl_i(tl_ibex_core_i_o_32), - .s_tl_o(tl_ibex_core_i_i_32), - .m_tl_o(tl_ibex_core_i_o_xbar), - .m_tl_i(tl_ibex_core_i_i_xbar)); kelvin_tlul_pkg_32::tl_h2d_t tl_rom_o_32; kelvin_tlul_pkg_32::tl_d2h_t tl_rom_i_32; - kelvin_tlul_pkg_128::tl_h2d_t tl_rom_o_xbar; - kelvin_tlul_pkg_128::tl_d2h_t tl_rom_i_xbar; - tlul_device_downsizer i_rom_downsizer(.clk_i(clk_i), - .rst_ni(rst_ni), - .s_tl_i(tl_rom_o_xbar), - .s_tl_o(tl_rom_i_xbar), - .m_tl_o(tl_rom_o_32), - .m_tl_i(tl_rom_i_32)); kelvin_tlul_pkg_32::tl_h2d_t tl_ibex_core_d_o_32; kelvin_tlul_pkg_32::tl_d2h_t tl_ibex_core_d_i_32; - kelvin_tlul_pkg_128::tl_h2d_t tl_ibex_core_d_o_xbar; - kelvin_tlul_pkg_128::tl_d2h_t tl_ibex_core_d_i_xbar; - tlul_host_upsizer i_ibex_core_d_upsizer(.clk_i(clk_i), - .rst_ni(rst_ni), - .s_tl_i(tl_ibex_core_d_o_32), - .s_tl_o(tl_ibex_core_d_i_32), - .m_tl_o(tl_ibex_core_d_o_xbar), - .m_tl_i(tl_ibex_core_d_i_xbar)); - - kelvin_tlul_pkg_128::tl_h2d_t tl_sram_o_xbar; - kelvin_tlul_pkg_128::tl_d2h_t tl_sram_i_xbar; tl_h2d_t tl_sram_o; tl_d2h_t tl_sram_i; - tlul_device_downsizer i_sram_downsizer(.clk_i(clk_i), - .rst_ni(rst_ni), - .s_tl_i(tl_sram_o_xbar), - .s_tl_o(tl_sram_i_xbar), - .m_tl_o(tl_sram_o), - .m_tl_i(tl_sram_i)); - kelvin_tlul_pkg_128::tl_h2d_t tl_uart0_o_xbar; - kelvin_tlul_pkg_128::tl_d2h_t tl_uart0_i_xbar; + tl_h2d_t tl_uart0_o; tl_d2h_t tl_uart0_i; - tlul_device_downsizer i_uart0_downsizer(.clk_i(clk_i), - .rst_ni(rst_ni), - .s_tl_i(tl_uart0_o_xbar), - .s_tl_o(tl_uart0_i_xbar), - .m_tl_o(tl_uart0_o), - .m_tl_i(tl_uart0_i)); - kelvin_tlul_pkg_128::tl_h2d_t tl_uart1_o_xbar; - kelvin_tlul_pkg_128::tl_d2h_t tl_uart1_i_xbar; + tl_h2d_t tl_uart1_o; tl_d2h_t tl_uart1_i; - tlul_device_downsizer i_uart1_downsizer(.clk_i(clk_i), - .rst_ni(rst_ni), - .s_tl_i(tl_uart1_o_xbar), - .s_tl_o(tl_uart1_i_xbar), - .m_tl_o(tl_uart1_o), - .m_tl_i(tl_uart1_i)); - kelvin_tlul_pkg_128::tl_h2d_t tl_spi0_o_xbar; - kelvin_tlul_pkg_128::tl_d2h_t tl_spi0_i_xbar; + tl_h2d_t tl_spi0_o; tl_d2h_t tl_spi0_i; - tlul_device_downsizer i_spi0_downsizer(.clk_i(clk_i), - .rst_ni(rst_ni), - .s_tl_i(tl_spi0_o_xbar), - .s_tl_o(tl_spi0_i_xbar), - .m_tl_o(tl_spi0_o), - .m_tl_i(tl_spi0_i)); - xbar_kelvin_soc_xbar i_xbar(.clk_i(clk_i), - .rst_ni(rst_ni), - .spi_clk_i(spi_clk_i), - .scanmode_i(scanmode_i), - .tl_kelvin_core_i(tl_kelvin_core_i), - .tl_kelvin_core_o(tl_kelvin_core_o), - .tl_ibex_core_i_o(tl_ibex_core_i_i_xbar), - .tl_ibex_core_i_i(tl_ibex_core_i_o_xbar), - .tl_ibex_core_d_o(tl_ibex_core_d_i_xbar), - .tl_ibex_core_d_i(tl_ibex_core_d_o_xbar), - .tl_kelvin_device_o(tl_kelvin_device_o), - .tl_kelvin_device_i(tl_kelvin_device_i), - .tl_rom_o(tl_rom_o_xbar), - .tl_rom_i(tl_rom_i_xbar), - .tl_sram_o(tl_sram_o_xbar), - .tl_sram_i(tl_sram_i_xbar), - .tl_uart0_o(tl_uart0_o_xbar), - .tl_uart0_i(tl_uart0_i_xbar), - .tl_uart1_o(tl_uart1_o_xbar), - .tl_uart1_i(tl_uart1_i_xbar), - .tl_spi0_o(tl_spi0_o_xbar), - .tl_spi0_i(tl_spi0_i_xbar)); + KelvinXbar i_xbar( + .io_clk_i(clk_i), + .io_rst_ni(rst_ni), + .io_async_ports_devices_0_clock(spi_clk_i), + .io_async_ports_devices_0_reset(rst_ni), + .io_async_ports_hosts_0_clock(ibex_clk_i), + .io_async_ports_hosts_0_reset(ibex_rst_ni), + + // Host connections + .io_hosts_0_a_valid(tl_kelvin_core_i.a_valid), + .io_hosts_0_a_bits_opcode(tl_kelvin_core_i.a_opcode), + .io_hosts_0_a_bits_param(tl_kelvin_core_i.a_param), + .io_hosts_0_a_bits_size(tl_kelvin_core_i.a_size), + .io_hosts_0_a_bits_source(tl_kelvin_core_i.a_source), + .io_hosts_0_a_bits_address(tl_kelvin_core_i.a_address), + .io_hosts_0_a_bits_mask(tl_kelvin_core_i.a_mask), + .io_hosts_0_a_bits_data(tl_kelvin_core_i.a_data), + .io_hosts_0_a_bits_user_rsvd(tl_kelvin_core_i.a_user.rsvd), + .io_hosts_0_a_bits_user_instr_type(tl_kelvin_core_i.a_user.instr_type), + .io_hosts_0_a_bits_user_cmd_intg(tl_kelvin_core_i.a_user.cmd_intg), + .io_hosts_0_a_bits_user_data_intg(tl_kelvin_core_i.a_user.data_intg), + .io_hosts_0_d_ready(tl_kelvin_core_i.d_ready), + .io_hosts_1_a_valid(tl_ibex_core_i_o_32.a_valid), + .io_hosts_1_a_bits_opcode(tl_ibex_core_i_o_32.a_opcode), + .io_hosts_1_a_bits_param(tl_ibex_core_i_o_32.a_param), + .io_hosts_1_a_bits_size(tl_ibex_core_i_o_32.a_size), + .io_hosts_1_a_bits_source(tl_ibex_core_i_o_32.a_source), + .io_hosts_1_a_bits_address(tl_ibex_core_i_o_32.a_address), + .io_hosts_1_a_bits_mask(tl_ibex_core_i_o_32.a_mask), + .io_hosts_1_a_bits_data(tl_ibex_core_i_o_32.a_data), + .io_hosts_1_a_bits_user_rsvd(tl_ibex_core_i_o_32.a_user.rsvd), + .io_hosts_1_a_bits_user_instr_type(tl_ibex_core_i_o_32.a_user.instr_type), + .io_hosts_1_a_bits_user_cmd_intg(tl_ibex_core_i_o_32.a_user.cmd_intg), + .io_hosts_1_a_bits_user_data_intg(tl_ibex_core_i_o_32.a_user.data_intg), + .io_hosts_1_d_ready(tl_ibex_core_i_o_32.d_ready), + .io_hosts_2_a_valid(tl_ibex_core_d_o_32.a_valid), + .io_hosts_2_a_bits_opcode(tl_ibex_core_d_o_32.a_opcode), + .io_hosts_2_a_bits_param(tl_ibex_core_d_o_32.a_param), + .io_hosts_2_a_bits_size(tl_ibex_core_d_o_32.a_size), + .io_hosts_2_a_bits_source(tl_ibex_core_d_o_32.a_source), + .io_hosts_2_a_bits_address(tl_ibex_core_d_o_32.a_address), + .io_hosts_2_a_bits_mask(tl_ibex_core_d_o_32.a_mask), + .io_hosts_2_a_bits_data(tl_ibex_core_d_o_32.a_data), + .io_hosts_2_a_bits_user_rsvd(tl_ibex_core_d_o_32.a_user.rsvd), + .io_hosts_2_a_bits_user_instr_type(tl_ibex_core_d_o_32.a_user.instr_type), + .io_hosts_2_a_bits_user_cmd_intg(tl_ibex_core_d_o_32.a_user.cmd_intg), + .io_hosts_2_a_bits_user_data_intg(tl_ibex_core_d_o_32.a_user.data_intg), + .io_hosts_2_d_ready(tl_ibex_core_d_o_32.d_ready), + + // Host response connections + .io_hosts_0_a_ready(tl_kelvin_core_o.a_ready), + .io_hosts_0_d_valid(tl_kelvin_core_o.d_valid), + .io_hosts_0_d_bits_opcode(tl_kelvin_core_o.d_opcode), + .io_hosts_0_d_bits_param(tl_kelvin_core_o.d_param), + .io_hosts_0_d_bits_size(tl_kelvin_core_o.d_size), + .io_hosts_0_d_bits_source(tl_kelvin_core_o.d_source), + .io_hosts_0_d_bits_sink(tl_kelvin_core_o.d_sink), + .io_hosts_0_d_bits_data(tl_kelvin_core_o.d_data), + .io_hosts_0_d_bits_error(tl_kelvin_core_o.d_error), + .io_hosts_0_d_bits_user_rsp_intg(tl_kelvin_core_o.d_user.rsp_intg), + .io_hosts_0_d_bits_user_data_intg(tl_kelvin_core_o.d_user.data_intg), + .io_hosts_1_a_ready(tl_ibex_core_i_i_32.a_ready), + .io_hosts_1_d_valid(tl_ibex_core_i_i_32.d_valid), + .io_hosts_1_d_bits_opcode(tl_ibex_core_i_i_32.d_opcode), + .io_hosts_1_d_bits_param(tl_ibex_core_i_i_32.d_param), + .io_hosts_1_d_bits_size(tl_ibex_core_i_i_32.d_size), + .io_hosts_1_d_bits_source(tl_ibex_core_i_i_32.d_source), + .io_hosts_1_d_bits_sink(tl_ibex_core_i_i_32.d_sink), + .io_hosts_1_d_bits_data(tl_ibex_core_i_i_32.d_data), + .io_hosts_1_d_bits_error(tl_ibex_core_i_i_32.d_error), + .io_hosts_1_d_bits_user_rsp_intg(tl_ibex_core_i_i_32.d_user.rsp_intg), + .io_hosts_1_d_bits_user_data_intg(tl_ibex_core_i_i_32.d_user.data_intg), + .io_hosts_2_a_ready(tl_ibex_core_d_i_32.a_ready), + .io_hosts_2_d_valid(tl_ibex_core_d_i_32.d_valid), + .io_hosts_2_d_bits_opcode(tl_ibex_core_d_i_32.d_opcode), + .io_hosts_2_d_bits_param(tl_ibex_core_d_i_32.d_param), + .io_hosts_2_d_bits_size(tl_ibex_core_d_i_32.d_size), + .io_hosts_2_d_bits_source(tl_ibex_core_d_i_32.d_source), + .io_hosts_2_d_bits_sink(tl_ibex_core_d_i_32.d_sink), + .io_hosts_2_d_bits_data(tl_ibex_core_d_i_32.d_data), + .io_hosts_2_d_bits_error(tl_ibex_core_d_i_32.d_error), + .io_hosts_2_d_bits_user_rsp_intg(tl_ibex_core_d_i_32.d_user.rsp_intg), + .io_hosts_2_d_bits_user_data_intg(tl_ibex_core_d_i_32.d_user.data_intg), + + // Device connections + .io_devices_0_a_ready(tl_kelvin_device_i.a_ready), + .io_devices_0_d_valid(tl_kelvin_device_i.d_valid), + .io_devices_0_d_bits_opcode(tl_kelvin_device_i.d_opcode), + .io_devices_0_d_bits_param(tl_kelvin_device_i.d_param), + .io_devices_0_d_bits_size(tl_kelvin_device_i.d_size), + .io_devices_0_d_bits_source(tl_kelvin_device_i.d_source), + .io_devices_0_d_bits_sink(tl_kelvin_device_i.d_sink), + .io_devices_0_d_bits_data(tl_kelvin_device_i.d_data), + .io_devices_0_d_bits_error(tl_kelvin_device_i.d_error), + .io_devices_0_d_bits_user_rsp_intg(tl_kelvin_device_i.d_user.rsp_intg), + .io_devices_0_d_bits_user_data_intg(tl_kelvin_device_i.d_user.data_intg), + .io_devices_1_a_ready(tl_rom_i_32.a_ready), + .io_devices_1_d_valid(tl_rom_i_32.d_valid), + .io_devices_1_d_bits_opcode(tl_rom_i_32.d_opcode), + .io_devices_1_d_bits_param(tl_rom_i_32.d_param), + .io_devices_1_d_bits_size(tl_rom_i_32.d_size), + .io_devices_1_d_bits_source(tl_rom_i_32.d_source), + .io_devices_1_d_bits_sink(tl_rom_i_32.d_sink), + .io_devices_1_d_bits_data(tl_rom_i_32.d_data), + .io_devices_1_d_bits_error(tl_rom_i_32.d_error), + .io_devices_1_d_bits_user_rsp_intg(tl_rom_i_32.d_user.rsp_intg), + .io_devices_1_d_bits_user_data_intg(tl_rom_i_32.d_user.data_intg), + .io_devices_2_a_ready(tl_sram_i.a_ready), + .io_devices_2_d_valid(tl_sram_i.d_valid), + .io_devices_2_d_bits_opcode(tl_sram_i.d_opcode), + .io_devices_2_d_bits_param(tl_sram_i.d_param), + .io_devices_2_d_bits_size(tl_sram_i.d_size), + .io_devices_2_d_bits_source(tl_sram_i.d_source), + .io_devices_2_d_bits_sink(tl_sram_i.d_sink), + .io_devices_2_d_bits_data(tl_sram_i.d_data), + .io_devices_2_d_bits_error(tl_sram_i.d_error), + .io_devices_2_d_bits_user_rsp_intg(tl_sram_i.d_user.rsp_intg), + .io_devices_2_d_bits_user_data_intg(tl_sram_i.d_user.data_intg), + .io_devices_3_a_ready(tl_uart0_i.a_ready), + .io_devices_3_d_valid(tl_uart0_i.d_valid), + .io_devices_3_d_bits_opcode(tl_uart0_i.d_opcode), + .io_devices_3_d_bits_param(tl_uart0_i.d_param), + .io_devices_3_d_bits_size(tl_uart0_i.d_size), + .io_devices_3_d_bits_source(tl_uart0_i.d_source), + .io_devices_3_d_bits_sink(tl_uart0_i.d_sink), + .io_devices_3_d_bits_data(tl_uart0_i.d_data), + .io_devices_3_d_bits_error(tl_uart0_i.d_error), + .io_devices_3_d_bits_user_rsp_intg(tl_uart0_i.d_user.rsp_intg), + .io_devices_3_d_bits_user_data_intg(tl_uart0_i.d_user.data_intg), + .io_devices_4_a_ready(tl_uart1_i.a_ready), + .io_devices_4_d_valid(tl_uart1_i.d_valid), + .io_devices_4_d_bits_opcode(tl_uart1_i.d_opcode), + .io_devices_4_d_bits_param(tl_uart1_i.d_param), + .io_devices_4_d_bits_size(tl_uart1_i.d_size), + .io_devices_4_d_bits_source(tl_uart1_i.d_source), + .io_devices_4_d_bits_sink(tl_uart1_i.d_sink), + .io_devices_4_d_bits_data(tl_uart1_i.d_data), + .io_devices_4_d_bits_error(tl_uart1_i.d_error), + .io_devices_4_d_bits_user_rsp_intg(tl_uart1_i.d_user.rsp_intg), + .io_devices_4_d_bits_user_data_intg(tl_uart1_i.d_user.data_intg), + .io_devices_5_a_ready(tl_spi0_i.a_ready), + .io_devices_5_d_valid(tl_spi0_i.d_valid), + .io_devices_5_d_bits_opcode(tl_spi0_i.d_opcode), + .io_devices_5_d_bits_param(tl_spi0_i.d_param), + .io_devices_5_d_bits_size(tl_spi0_i.d_size), + .io_devices_5_d_bits_source(tl_spi0_i.d_source), + .io_devices_5_d_bits_sink(tl_spi0_i.d_sink), + .io_devices_5_d_bits_data(tl_spi0_i.d_data), + .io_devices_5_d_bits_error(tl_spi0_i.d_error), + .io_devices_5_d_bits_user_rsp_intg(tl_spi0_i.d_user.rsp_intg), + .io_devices_5_d_bits_user_data_intg(tl_spi0_i.d_user.data_intg), + + // Device response connections + .io_devices_0_a_valid(tl_kelvin_device_o.a_valid), + .io_devices_0_a_bits_opcode(tl_kelvin_device_o.a_opcode), + .io_devices_0_a_bits_param(tl_kelvin_device_o.a_param), + .io_devices_0_a_bits_size(tl_kelvin_device_o.a_size), + .io_devices_0_a_bits_source(tl_kelvin_device_o.a_source), + .io_devices_0_a_bits_address(tl_kelvin_device_o.a_address), + .io_devices_0_a_bits_mask(tl_kelvin_device_o.a_mask), + .io_devices_0_a_bits_data(tl_kelvin_device_o.a_data), + .io_devices_0_a_bits_user_rsvd(tl_kelvin_device_o.a_user.rsvd), + .io_devices_0_a_bits_user_instr_type(tl_kelvin_device_o.a_user.instr_type), + .io_devices_0_a_bits_user_cmd_intg(tl_kelvin_device_o.a_user.cmd_intg), + .io_devices_0_a_bits_user_data_intg(tl_kelvin_device_o.a_user.data_intg), + .io_devices_0_d_ready(tl_kelvin_device_o.d_ready), + .io_devices_1_a_valid(tl_rom_o_32.a_valid), + .io_devices_1_a_bits_opcode(tl_rom_o_32.a_opcode), + .io_devices_1_a_bits_param(tl_rom_o_32.a_param), + .io_devices_1_a_bits_size(tl_rom_o_32.a_size), + .io_devices_1_a_bits_source(tl_rom_o_32.a_source), + .io_devices_1_a_bits_address(tl_rom_o_32.a_address), + .io_devices_1_a_bits_mask(tl_rom_o_32.a_mask), + .io_devices_1_a_bits_data(tl_rom_o_32.a_data), + .io_devices_1_a_bits_user_rsvd(tl_rom_o_32.a_user.rsvd), + .io_devices_1_a_bits_user_instr_type(tl_rom_o_32.a_user.instr_type), + .io_devices_1_a_bits_user_cmd_intg(tl_rom_o_32.a_user.cmd_intg), + .io_devices_1_a_bits_user_data_intg(tl_rom_o_32.a_user.data_intg), + .io_devices_1_d_ready(tl_rom_o_32.d_ready), + .io_devices_2_a_valid(tl_sram_o.a_valid), + .io_devices_2_a_bits_opcode(tl_sram_o.a_opcode), + .io_devices_2_a_bits_param(tl_sram_o.a_param), + .io_devices_2_a_bits_size(tl_sram_o.a_size), + .io_devices_2_a_bits_source(tl_sram_o.a_source), + .io_devices_2_a_bits_address(tl_sram_o.a_address), + .io_devices_2_a_bits_mask(tl_sram_o.a_mask), + .io_devices_2_a_bits_data(tl_sram_o.a_data), + .io_devices_2_a_bits_user_rsvd(tl_sram_o.a_user.rsvd), + .io_devices_2_a_bits_user_instr_type(tl_sram_o.a_user.instr_type), + .io_devices_2_a_bits_user_cmd_intg(tl_sram_o.a_user.cmd_intg), + .io_devices_2_a_bits_user_data_intg(tl_sram_o.a_user.data_intg), + .io_devices_2_d_ready(tl_sram_o.d_ready), + .io_devices_3_a_valid(tl_uart0_o.a_valid), + .io_devices_3_a_bits_opcode(tl_uart0_o.a_opcode), + .io_devices_3_a_bits_param(tl_uart0_o.a_param), + .io_devices_3_a_bits_size(tl_uart0_o.a_size), + .io_devices_3_a_bits_source(tl_uart0_o.a_source), + .io_devices_3_a_bits_address(tl_uart0_o.a_address), + .io_devices_3_a_bits_mask(tl_uart0_o.a_mask), + .io_devices_3_a_bits_data(tl_uart0_o.a_data), + .io_devices_3_a_bits_user_rsvd(tl_uart0_o.a_user.rsvd), + .io_devices_3_a_bits_user_instr_type(tl_uart0_o.a_user.instr_type), + .io_devices_3_a_bits_user_cmd_intg(tl_uart0_o.a_user.cmd_intg), + .io_devices_3_a_bits_user_data_intg(tl_uart0_o.a_user.data_intg), + .io_devices_3_d_ready(tl_uart0_o.d_ready), + .io_devices_4_a_valid(tl_uart1_o.a_valid), + .io_devices_4_a_bits_opcode(tl_uart1_o.a_opcode), + .io_devices_4_a_bits_param(tl_uart1_o.a_param), + .io_devices_4_a_bits_size(tl_uart1_o.a_size), + .io_devices_4_a_bits_source(tl_uart1_o.a_source), + .io_devices_4_a_bits_address(tl_uart1_o.a_address), + .io_devices_4_a_bits_mask(tl_uart1_o.a_mask), + .io_devices_4_a_bits_data(tl_uart1_o.a_data), + .io_devices_4_a_bits_user_rsvd(tl_uart1_o.a_user.rsvd), + .io_devices_4_a_bits_user_instr_type(tl_uart1_o.a_user.instr_type), + .io_devices_4_a_bits_user_cmd_intg(tl_uart1_o.a_user.cmd_intg), + .io_devices_4_a_bits_user_data_intg(tl_uart1_o.a_user.data_intg), + .io_devices_4_d_ready(tl_uart1_o.d_ready), + .io_devices_5_a_valid(tl_spi0_o.a_valid), + .io_devices_5_a_bits_opcode(tl_spi0_o.a_opcode), + .io_devices_5_a_bits_param(tl_spi0_o.a_param), + .io_devices_5_a_bits_size(tl_spi0_o.a_size), + .io_devices_5_a_bits_source(tl_spi0_o.a_source), + .io_devices_5_a_bits_address(tl_spi0_o.a_address), + .io_devices_5_a_bits_mask(tl_spi0_o.a_mask), + .io_devices_5_a_bits_data(tl_spi0_o.a_data), + .io_devices_5_a_bits_user_rsvd(tl_spi0_o.a_user.rsvd), + .io_devices_5_a_bits_user_instr_type(tl_spi0_o.a_user.instr_type), + .io_devices_5_a_bits_user_cmd_intg(tl_spi0_o.a_user.cmd_intg), + .io_devices_5_a_bits_user_data_intg(tl_spi0_o.a_user.data_intg), + .io_devices_5_d_ready(tl_spi0_o.d_ready) + ); uart i_uart0(.clk_i(clk_i), .rst_ni(rst_ni), @@ -308,226 +465,11 @@ logic rst_cpu_n; - // Data and Response integrity generation for Kelvin Device Port - localparam int XbarSourceWidth = kelvin_tlul_pkg_128::TL_AIW; - localparam int XbarSourceCount = 1 << XbarSourceWidth; - logic [1 : 0] host_lane_reg[XbarSourceCount - 1 : 0]; - - logic [38 : 0] dev_ecc_full_0, dev_ecc_full_1, dev_ecc_full_2, dev_ecc_full_3; - logic [6 : 0] dev_ecc_0, dev_ecc_1, dev_ecc_2, dev_ecc_3; - logic [6 : 0] dev_selected_ecc; - tl_d2h_rsp_intg_t dev_rsp_metadata; - logic [63 : 0] dev_rsp_ecc_full; - logic [6 : 0] dev_rsp_ecc; - - assign dev_ecc_0 = dev_ecc_full_0[38 : 32]; - assign dev_ecc_1 = dev_ecc_full_1[38 : 32]; - assign dev_ecc_2 = dev_ecc_full_2[38 : 32]; - assign dev_ecc_3 = dev_ecc_full_3[38 : 32]; - assign dev_rsp_ecc = dev_rsp_ecc_full[63 : 57]; - - prim_secded_inv_39_32_enc dev_enc0(.data_i(tl_kelvin_device_i.d_data[31 : 0]), - .data_o(dev_ecc_full_0)); - prim_secded_inv_39_32_enc dev_enc1(.data_i( - tl_kelvin_device_i.d_data[63 : 32]), - .data_o(dev_ecc_full_1)); - prim_secded_inv_39_32_enc dev_enc2(.data_i( - tl_kelvin_device_i.d_data[95 : 64]), - .data_o(dev_ecc_full_2)); - prim_secded_inv_39_32_enc dev_enc3(.data_i( - tl_kelvin_device_i.d_data[127 : 96]), - .data_o(dev_ecc_full_3)); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - for (int i = 0; i < XbarSourceCount; i++) begin - host_lane_reg[i] <= 2'b0; - end - end else begin - // Capture lane index from Ibex data core requests - if (tl_ibex_core_d_o_xbar.a_valid && tl_ibex_core_d_i_xbar.a_ready) begin - unique case (4'hF) - tl_ibex_core_d_o_xbar.a_mask[3 : 0]: - host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b00; - tl_ibex_core_d_o_xbar.a_mask[7 : 4]: - host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b01; - tl_ibex_core_d_o_xbar.a_mask[11 : 8]: - host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b10; - tl_ibex_core_d_o_xbar.a_mask[15 : 12]: - host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b11; - endcase - end - - // Capture lane index from Ibex instruction core requests - if (tl_ibex_core_i_o_xbar.a_valid && tl_ibex_core_i_i_xbar.a_ready) begin - unique case (4'hF) - tl_ibex_core_i_o_xbar.a_mask[3 : 0]: - host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b00; - tl_ibex_core_i_o_xbar.a_mask[7 : 4]: - host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b01; - tl_ibex_core_i_o_xbar.a_mask[11 : 8]: - host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b10; - tl_ibex_core_i_o_xbar.a_mask[15 : 12]: - host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b11; - endcase - end - - // Capture lane index from Kelvin core requests - if (tl_kelvin_core_i.a_valid && tl_kelvin_core_o.a_ready) begin - unique case (4'hF) - tl_kelvin_core_i.a_mask[3 : 0]: - host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b00; - tl_kelvin_core_i.a_mask[7 : 4]: - host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b01; - tl_kelvin_core_i.a_mask[11 : 8]: - host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b10; - tl_kelvin_core_i.a_mask[15 : 12]: - host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b11; - endcase - end - end - end - - always_comb begin - logic [1 : 0] lane_idx; - lane_idx = host_lane_reg[tl_from_kelvin_core.d_source]; - case (lane_idx) - 2'b00: - dev_selected_ecc = dev_ecc_0; - 2'b01: - dev_selected_ecc = dev_ecc_1; - 2'b10: - dev_selected_ecc = dev_ecc_2; - 2'b11: - dev_selected_ecc = dev_ecc_3; - default: - dev_selected_ecc = dev_ecc_0; - endcase - end - - assign dev_rsp_metadata = '{ - opcode: tl_from_kelvin_core.d_opcode, - size: 2'b10, - error: tl_from_kelvin_core.d_error - }; - - prim_secded_inv_64_57_enc dev_enc_rsp(.data_i( - D2HRspMaxWidth'(dev_rsp_metadata)), - .data_o(dev_rsp_ecc_full)); - // Kelvin Core Instantiation logic kelvin_halted, kelvin_fault, kelvin_wfi; - kelvin_tlul_pkg_128::tl_d2h_t tl_from_kelvin_core; - assign io_halted = kelvin_halted; assign io_fault = kelvin_fault; - // Assign all fields for the device D-channel from the Kelvin core's output, - // except for the user integrity bits, which we override with our generated - // ECC. - assign tl_kelvin_device_i.d_valid = tl_from_kelvin_core.d_valid; - assign tl_kelvin_device_i.d_opcode = tl_from_kelvin_core.d_opcode; - assign tl_kelvin_device_i.d_param = tl_from_kelvin_core.d_param; - assign tl_kelvin_device_i.d_size = tl_from_kelvin_core.d_size; - assign tl_kelvin_device_i.d_source = tl_from_kelvin_core.d_source; - assign tl_kelvin_device_i.d_sink = tl_from_kelvin_core.d_sink; - assign tl_kelvin_device_i.d_data = tl_from_kelvin_core.d_data; - assign tl_kelvin_device_i.d_error = tl_from_kelvin_core.d_error; - assign tl_kelvin_device_i.a_ready = tl_from_kelvin_core.a_ready; - assign tl_kelvin_device_i.d_user.rsp_intg = dev_rsp_ecc; - assign tl_kelvin_device_i.d_user.data_intg = dev_selected_ecc; - - // Command and Data integrity generation for Kelvin Host Port - logic [38 : 0] host_a_data_ecc_full_0, host_a_data_ecc_full_1, - host_a_data_ecc_full_2, host_a_data_ecc_full_3; - logic [6 : 0] host_a_data_ecc_0, host_a_data_ecc_1, host_a_data_ecc_2, - host_a_data_ecc_3; - logic [6 : 0] host_a_data_selected_ecc; - tl_h2d_cmd_intg_t host_a_cmd_metadata; - logic [63 : 0] host_a_cmd_ecc_full; - logic [6 : 0] host_a_cmd_ecc; - - assign host_a_data_ecc_0 = host_a_data_ecc_full_0[38 : 32]; - assign host_a_data_ecc_1 = host_a_data_ecc_full_1[38 : 32]; - assign host_a_data_ecc_2 = host_a_data_ecc_full_2[38 : 32]; - assign host_a_data_ecc_3 = host_a_data_ecc_full_3[38 : 32]; - assign host_a_cmd_ecc = host_a_cmd_ecc_full[63 : 57]; - - prim_secded_inv_39_32_enc host_a_data_enc0( - .data_i(tl_kelvin_core_i.a_data[31 : 0]), - .data_o(host_a_data_ecc_full_0)); - prim_secded_inv_39_32_enc host_a_data_enc1( - .data_i(tl_kelvin_core_i.a_data[63 : 32]), - .data_o(host_a_data_ecc_full_1)); - prim_secded_inv_39_32_enc host_a_data_enc2( - .data_i(tl_kelvin_core_i.a_data[95 : 64]), - .data_o(host_a_data_ecc_full_2)); - prim_secded_inv_39_32_enc host_a_data_enc3( - .data_i(tl_kelvin_core_i.a_data[127 : 96]), - .data_o(host_a_data_ecc_full_3)); - - logic [top_pkg::TL_DBW - 1 : 0] host_a_cmd_mask; - - localparam logic [top_pkg::TL_AW - 1 : 0] Uart1BaseAddr = 32'h40010000; - logic [15 : 0] computed_mask; - logic [3 : 0] host_a_cmd_mask_4b; - logic [1 : 0] host_a_cmd_lane; - tl_h2d_cmd_intg_t host_a_cmd_payload; - logic [15 : 0] kelvin_core_i_a_mask; - - always_comb begin - if (tl_kelvin_core_i.a_opcode == tlul_pkg::Get) begin - computed_mask = ((1 << (1 << tl_kelvin_core_i.a_size)) - 1) - << (tl_kelvin_core_i.a_address[3 : 0]); - end else begin - computed_mask = kelvin_core_i_a_mask; - end - host_a_data_selected_ecc = 7'b0; - host_a_cmd_mask_4b = '0; - host_a_cmd_lane = '0; - // This is a priority mux, which is what we want. - if (|computed_mask[3 : 0]) begin - host_a_data_selected_ecc = host_a_data_ecc_0; - host_a_cmd_mask_4b = computed_mask[3 : 0]; - host_a_cmd_lane = 2'b00; - end else if (|computed_mask[7 : 4]) begin - host_a_data_selected_ecc = host_a_data_ecc_1; - host_a_cmd_mask_4b = computed_mask[7 : 4]; - host_a_cmd_lane = 2'b01; - end else if (|computed_mask[11 : 8]) begin - host_a_data_selected_ecc = host_a_data_ecc_2; - host_a_cmd_mask_4b = computed_mask[11 : 8]; - host_a_cmd_lane = 2'b10; - end else if (|computed_mask[15 : 12]) begin - host_a_data_selected_ecc = host_a_data_ecc_3; - host_a_cmd_mask_4b = computed_mask[15 : 12]; - host_a_cmd_lane = 2'b11; - end - end - - // Manually pack the command integrity payload to match the 32-bit - // peripheral's view. The packing order is derived from the tl_h2d_cmd_intg_t - // struct definition. - assign host_a_cmd_payload = '{ - instr_type: prim_mubi_pkg::MuBi4False, // instr_type (4 bits) - addr: tl_kelvin_core_i.a_address, // addr (32 bits) - opcode: tl_kelvin_core_i.a_opcode, // opcode (3 bits) - mask: host_a_cmd_mask_4b // mask (4 bits) - }; - logic [31 : 0] dbg_uart1_addr = host_a_cmd_payload.addr; - logic [2 : 0] dbg_uart1_opcode = host_a_cmd_payload.opcode; - logic [3 : 0] dbg_uart1_mask = host_a_cmd_payload.mask; - logic [3 : 0] dbg_uart1_instr_type = host_a_cmd_payload.instr_type; - - prim_secded_inv_64_57_enc host_a_cmd_enc(.data_i(H2DCmdMaxWidth'( - host_a_cmd_payload)), - .data_o(host_a_cmd_ecc_full)); - - assign tl_kelvin_core_i.a_user.cmd_intg = host_a_cmd_ecc; - assign tl_kelvin_core_i.a_user.data_intg = host_a_data_selected_ecc; - assign tl_kelvin_core_i.a_user.instr_type = prim_mubi_pkg::MuBi4False; - assign tl_kelvin_core_i.a_mask = computed_mask; - RvvCoreMiniTlul i_kelvin_core( .io_clk(clk_i), @@ -539,12 +481,12 @@ .io_tl_host_a_bits_size(tl_kelvin_core_i.a_size), .io_tl_host_a_bits_source(tl_kelvin_core_i.a_source), .io_tl_host_a_bits_address(tl_kelvin_core_i.a_address), - .io_tl_host_a_bits_mask(kelvin_core_i_a_mask), + .io_tl_host_a_bits_mask(tl_kelvin_core_i.a_mask), .io_tl_host_a_bits_data(tl_kelvin_core_i.a_data), .io_tl_host_a_bits_user_rsvd(tl_kelvin_core_i.a_user.rsvd), - .io_tl_host_a_bits_user_instr_type(), - .io_tl_host_a_bits_user_cmd_intg(), - .io_tl_host_a_bits_user_data_intg(), + .io_tl_host_a_bits_user_instr_type(tl_kelvin_core_i.a_user.instr_type), + .io_tl_host_a_bits_user_cmd_intg(tl_kelvin_core_i.a_user.cmd_intg), + .io_tl_host_a_bits_user_data_intg(tl_kelvin_core_i.a_user.data_intg), .io_tl_host_d_ready(tl_kelvin_core_i.d_ready), .io_tl_host_d_valid(tl_kelvin_core_o.d_valid), .io_tl_host_d_bits_opcode(tl_kelvin_core_o.d_opcode), @@ -574,17 +516,17 @@ .io_tl_device_a_bits_user_data_intg( tl_kelvin_device_o.a_user.data_intg), .io_tl_device_d_ready(tl_kelvin_device_o.d_ready), - .io_tl_device_a_ready(tl_from_kelvin_core.a_ready), - .io_tl_device_d_valid(tl_from_kelvin_core.d_valid), - .io_tl_device_d_bits_opcode(tl_from_kelvin_core.d_opcode), - .io_tl_device_d_bits_param(tl_from_kelvin_core.d_param), - .io_tl_device_d_bits_size(tl_from_kelvin_core.d_size), - .io_tl_device_d_bits_source(tl_from_kelvin_core.d_source), - .io_tl_device_d_bits_sink(tl_from_kelvin_core.d_sink), - .io_tl_device_d_bits_data(tl_from_kelvin_core.d_data), - .io_tl_device_d_bits_error(tl_from_kelvin_core.d_error), - .io_tl_device_d_bits_user_rsp_intg(), - .io_tl_device_d_bits_user_data_intg(), + .io_tl_device_a_ready(tl_kelvin_device_i.a_ready), + .io_tl_device_d_valid(tl_kelvin_device_i.d_valid), + .io_tl_device_d_bits_opcode(tl_kelvin_device_i.d_opcode), + .io_tl_device_d_bits_param(tl_kelvin_device_i.d_param), + .io_tl_device_d_bits_size(tl_kelvin_device_i.d_size), + .io_tl_device_d_bits_source(tl_kelvin_device_i.d_source), + .io_tl_device_d_bits_sink(tl_kelvin_device_i.d_sink), + .io_tl_device_d_bits_data(tl_kelvin_device_i.d_data), + .io_tl_device_d_bits_error(tl_kelvin_device_i.d_error), + .io_tl_device_d_bits_user_rsp_intg(tl_kelvin_device_i.d_user.rsp_intg), + .io_tl_device_d_bits_user_data_intg(tl_kelvin_device_i.d_user.data_intg), .io_halted(kelvin_halted), .io_fault(kelvin_fault), .io_wfi(kelvin_wfi), @@ -594,8 +536,8 @@ // Ibex Core Instantiation rv_core_ibex #(.PipeLine(1'b1), .PMPEnable(1'b0)) - i_ibex_core(.clk_i(clk_i), - .rst_ni(rst_ni), + i_ibex_core(.clk_i(ibex_clk_i), + .rst_ni(ibex_rst_ni), .corei_tl_h_o(tl_ibex_core_i_o_32), .corei_tl_h_i(tl_ibex_core_i_i_32), .cored_tl_h_o(tl_ibex_core_d_o_32),
diff --git a/fpga/rules.bzl b/fpga/rules.bzl deleted file mode 100644 index df307ad..0000000 --- a/fpga/rules.bzl +++ /dev/null
@@ -1,43 +0,0 @@ -"""Starlark rules for FPGA development.""" - -def _tlgen_impl(ctx): - """Implementation of the tlgen_rule.""" - topcfg = ctx.file.topcfg - out_dir = ctx.actions.declare_directory(ctx.label.name + "_out") - core_file = ctx.actions.declare_file(ctx.label.name + "_out/" + "xbar_kelvin_soc_xbar.core") - - ctx.actions.run( - outputs = [out_dir, core_file], - inputs = [topcfg], - executable = ctx.executable._tool, - arguments = [ - "--topcfg", - topcfg.path, - "--outdir", - out_dir.path, - ], - progress_message = "Running tlgen and extracting core for %s" % topcfg.short_path, - ) - - return [ - DefaultInfo(files = depset([out_dir])), - OutputGroupInfo( - core_file_output = depset([core_file, out_dir]), - ), - ] - -tlgen_rule = rule( - implementation = _tlgen_impl, - attrs = { - "topcfg": attr.label( - allow_single_file = True, - mandatory = True, - doc = "HJSON top-level configuration file.", - ), - "_tool": attr.label( - default = Label("//fpga:tlgen_tool"), - executable = True, - cfg = "exec", - ), - }, -)
diff --git a/fpga/sw/main.cc b/fpga/sw/main.cc index 3ff561f..f9c7b8e 100644 --- a/fpga/sw/main.cc +++ b/fpga/sw/main.cc
@@ -6,8 +6,15 @@ extern "C" int main() { // Copy the embedded binary to Kelvin's ITCM at 0x0. - void *itcm_base = reinterpret_cast<void *>(static_cast<uintptr_t>(0x0)); - memcpy(itcm_base, add_uint32_m1_bin, add_uint32_m1_bin_len); + // NB: Use this copy loop instead of memcpy to get word writes + // instead of byte writes. + uint32_t* itcm_base = + reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(0x0)); + const uint32_t* add_uint32_m1_bin_u32 = + reinterpret_cast<const uint32_t*>(add_uint32_m1_bin); + for (unsigned int i = 0; i < add_uint32_m1_bin_len / 4; i++) { + *(itcm_base + i) = add_uint32_m1_bin_u32[i]; + } // Kelvin run sequence volatile unsigned int *kelvin_reset_csr =
diff --git a/fpga/tl_config.hjson b/fpga/tl_config.hjson deleted file mode 100644 index 82f5a83..0000000 --- a/fpga/tl_config.hjson +++ /dev/null
@@ -1,95 +0,0 @@ -{ - // Top-level configuration for the Kelvin SoC crossbar. - name: "kelvin_soc_xbar", - clock: "clk_i", - reset: "rst_ni", - - // Define all the hosts (masters) and devices (slaves) in the system. - nodes: [ - // Hosts (CPU Cores) - { name: "kelvin_core", type: "host", clock: "clk_i", reset: "rst_ni", addr_space: "asid0" }, - { name: "ibex_core_i", type: "host", clock: "clk_i", reset: "rst_ni", addr_space: "asid0" }, - { name: "ibex_core_d", type: "host", clock: "clk_i", reset: "rst_ni", addr_space: "asid0" }, - - // Devices (Peripherals and Memory) - { - name: "kelvin_device", - type: "device", - clock: "clk_i", - reset: "rst_ni", - xbar: false, - addr_range: [ - { base_addrs: {"asid0": "0x00000000"}, size_byte: "0x2000" }, // 8kB - { base_addrs: {"asid0": "0x00010000"}, size_byte: "0x8000" }, // 32kB - { base_addrs: {"asid0": "0x00030000"}, size_byte: "0x1000" } // 4kB - ] - }, - { - name: "rom", - type: "device", - clock: "clk_i", - reset: "rst_ni", - xbar: false, - addr_range: [{ base_addrs: {"asid0": "0x10000000"}, size_byte: "0x8000" }] // 32kB - }, - { - name: "sram", - type: "device", - clock: "clk_i", - reset: "rst_ni", - xbar: false, - addr_range: [{ base_addrs: {"asid0": "0x20000000"}, size_byte: "0x400000" }] // 4MB - }, - { - name: "uart0", - type: "device", - clock: "clk_i", - reset: "rst_ni", - xbar: false, - addr_range: [{ base_addrs: {"asid0": "0x40000000"}, size_byte: "0x1000" }] - }, - { - name: "uart1", - type: "device", - clock: "clk_i", - reset: "rst_ni", - xbar: false, - addr_range: [{ base_addrs: {"asid0": "0x40010000"}, size_byte: "0x1000" }] - }, - { - name: "spi0", - type: "device", - clock: "spi_clk_i", // Using a separate clock for the SPI peripheral - reset: "rst_ni", - xbar: false, - addr_range: [{ base_addrs: {"asid0": "0x40020000"}, size_byte: "0x1000" }] - } - ], - - // Define which hosts can access which devices. - connections: { - kelvin_core: [ "sram", "uart1", "spi0" ], - ibex_core_i: [ "rom", "sram" ], - ibex_core_d: [ "rom", "sram", "uart0", "kelvin_device" ] - }, - - // Define clock connections for all components. - clock_connections: { - clk_i: [ - "kelvin_core", - "ibex_core_i", - "ibex_core_d", - "kelvin_device", - "rom", - "sram", - "uart0", - "uart1" - ], - spi_clk_i: [ - "spi0" - ] - }, - reset_connections: { - rst_ni: "rst_ni" - } -}
diff --git a/hdl/chisel/src/kelvin/CoreTlul.scala b/hdl/chisel/src/kelvin/CoreTlul.scala index 7c41c55..88ba92b 100644 --- a/hdl/chisel/src/kelvin/CoreTlul.scala +++ b/hdl/chisel/src/kelvin/CoreTlul.scala
@@ -20,6 +20,7 @@ class CoreTlul(p: Parameters, coreModuleName: String) extends RawModule { override val desiredName = coreModuleName + "Tlul" val memoryRegions = p.m + val tlul_p = new TLULParameters(p) val io = IO(new Bundle { val clk = Input(Clock()) val rst_ni = Input(AsyncReset()) @@ -51,9 +52,22 @@ hostBridge.io.axi <> coreAxi.io.axi_master deviceBridge.io.axi <> coreAxi.io.axi_slave - io.tl_host.a <> hostBridge.io.tl_a + val host_req_intg_gen = withClockAndReset(io.clk, (!io.rst_ni.asBool).asAsyncReset) { + Module(new RequestIntegrityGen(tlul_p)) + } + io.tl_host.a.valid := hostBridge.io.tl_a.valid + hostBridge.io.tl_a.ready := io.tl_host.a.ready + host_req_intg_gen.io.a_i := hostBridge.io.tl_a.bits + host_req_intg_gen.io.a_i.user.instr_type := 9.U // MuBi4False + io.tl_host.a.bits := host_req_intg_gen.io.a_o hostBridge.io.tl_d <> io.tl_host.d + val device_rsp_intg_gen = withClockAndReset(io.clk, (!io.rst_ni.asBool).asAsyncReset) { + Module(new ResponseIntegrityGen(tlul_p)) + } deviceBridge.io.tl_a <> io.tl_device.a - io.tl_device.d <> deviceBridge.io.tl_d + io.tl_device.d.valid := deviceBridge.io.tl_d.valid + deviceBridge.io.tl_d.ready := io.tl_device.d.ready + device_rsp_intg_gen.io.d_i := deviceBridge.io.tl_d.bits + io.tl_device.d.bits := device_rsp_intg_gen.io.d_o } \ No newline at end of file