From 548d297d6f74f88a0ae503196aa7bedb7cbf9ec8 Mon Sep 17 00:00:00 2001 From: Riccardo Tedeschi Date: Mon, 2 Dec 2024 11:31:34 +0100 Subject: [PATCH] Add ACE `include` and `src` files * Provide TYPEDEF and ASSIGN macros * Proivde ACE_BUS and SNOOP_BUS --- Bender.yml | 3 + include/ace/assign.svh | 510 ++++++++++++++++++++++++++++++++++++++++ include/ace/convert.svh | 104 ++++++++ include/ace/domain.svh | 28 +++ include/ace/typedef.svh | 167 +++++++++++++ src/ace/ace_intf.sv | 277 ++++++++++++++++++++++ src/ace/ace_pkg.sv | 124 ++++++++++ src/ace/snoop_intf.sv | 122 ++++++++++ 8 files changed, 1335 insertions(+) create mode 100644 include/ace/assign.svh create mode 100644 include/ace/convert.svh create mode 100644 include/ace/domain.svh create mode 100644 include/ace/typedef.svh create mode 100644 src/ace/ace_intf.sv create mode 100644 src/ace/ace_pkg.sv create mode 100644 src/ace/snoop_intf.sv diff --git a/Bender.yml b/Bender.yml index f30fcff2d..460321999 100644 --- a/Bender.yml +++ b/Bender.yml @@ -32,8 +32,11 @@ sources: # levels 1 and 0, etc. Files within a level are ordered alphabetically. # Level 0 - src/axi_pkg.sv + - src/ace/ace_pkg.sv # Level 1 - src/axi_intf.sv + - src/ace/ace_intf.sv + - src/ace/snoop_intf.sv # Level 2 - src/axi_atop_filter.sv - src/axi_burst_splitter.sv diff --git a/include/ace/assign.svh b/include/ace/assign.svh new file mode 100644 index 000000000..d37943c40 --- /dev/null +++ b/include/ace/assign.svh @@ -0,0 +1,510 @@ +// Copyright (c) 2014-2018 ETH Zurich, University of Bologna +// Copyright (c) 2022 PlanV GmbH +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. +// + +// Macros to assign ACE Interfaces and Structs + +`ifndef ACE_ASSIGN_SVH_ +`define ACE_ASSIGN_SVH_ + +`include "axi/assign.svh" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal implementation for assigning one ACE struct or interface to another struct or interface. +// The path to the signals on each side is defined by the `__sep*` arguments. The `__opt_as` +// argument allows to use this standalone (with `__opt_as = assign`) or in assignments inside +// processes (with `__opt_as` void). +`define __ACE_TO_AW(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``addr = __rhs``__rhs_sep``addr; \ + __opt_as __lhs``__lhs_sep``len = __rhs``__rhs_sep``len; \ + __opt_as __lhs``__lhs_sep``size = __rhs``__rhs_sep``size; \ + __opt_as __lhs``__lhs_sep``burst = __rhs``__rhs_sep``burst; \ + __opt_as __lhs``__lhs_sep``lock = __rhs``__rhs_sep``lock; \ + __opt_as __lhs``__lhs_sep``cache = __rhs``__rhs_sep``cache; \ + __opt_as __lhs``__lhs_sep``prot = __rhs``__rhs_sep``prot; \ + __opt_as __lhs``__lhs_sep``qos = __rhs``__rhs_sep``qos; \ + __opt_as __lhs``__lhs_sep``region = __rhs``__rhs_sep``region; \ + __opt_as __lhs``__lhs_sep``atop = __rhs``__rhs_sep``atop; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; \ + __opt_as __lhs``__lhs_sep``snoop = __rhs``__rhs_sep``snoop; \ + __opt_as __lhs``__lhs_sep``bar = __rhs``__rhs_sep``bar; \ + __opt_as __lhs``__lhs_sep``domain = __rhs``__rhs_sep``domain; \ + __opt_as __lhs``__lhs_sep``awunique = __rhs``__rhs_sep``awunique; + + +`define __ACE_TO_AR(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``addr = __rhs``__rhs_sep``addr; \ + __opt_as __lhs``__lhs_sep``len = __rhs``__rhs_sep``len; \ + __opt_as __lhs``__lhs_sep``size = __rhs``__rhs_sep``size; \ + __opt_as __lhs``__lhs_sep``burst = __rhs``__rhs_sep``burst; \ + __opt_as __lhs``__lhs_sep``lock = __rhs``__rhs_sep``lock; \ + __opt_as __lhs``__lhs_sep``cache = __rhs``__rhs_sep``cache; \ + __opt_as __lhs``__lhs_sep``prot = __rhs``__rhs_sep``prot; \ + __opt_as __lhs``__lhs_sep``qos = __rhs``__rhs_sep``qos; \ + __opt_as __lhs``__lhs_sep``region = __rhs``__rhs_sep``region; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; \ + __opt_as __lhs``__lhs_sep``snoop = __rhs``__rhs_sep``snoop; \ + __opt_as __lhs``__lhs_sep``bar = __rhs``__rhs_sep``bar; \ + __opt_as __lhs``__lhs_sep``domain = __rhs``__rhs_sep``domain; +`define __ACE_TO_R(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``data = __rhs``__rhs_sep``data; \ + __opt_as __lhs``__lhs_sep``resp = __rhs``__rhs_sep``resp; \ + __opt_as __lhs``__lhs_sep``last = __rhs``__rhs_sep``last; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; +`define __ACE_TO_REQ(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + `__ACE_TO_AW(__opt_as, __lhs.aw, __lhs_sep, __rhs.aw, __rhs_sep) \ + __opt_as __lhs.aw_valid = __rhs.aw_valid; \ + `__AXI_TO_W(__opt_as, __lhs.w, __lhs_sep, __rhs.w, __rhs_sep) \ + __opt_as __lhs.w_valid = __rhs.w_valid; \ + __opt_as __lhs.b_ready = __rhs.b_ready; \ + `__ACE_TO_AR(__opt_as, __lhs.ar, __lhs_sep, __rhs.ar, __rhs_sep) \ + __opt_as __lhs.ar_valid = __rhs.ar_valid; \ + __opt_as __lhs.r_ready = __rhs.r_ready; \ + __opt_as __lhs.wack = __rhs.wack; \ + __opt_as __lhs.rack = __rhs.rack; +`define __ACE_TO_RESP(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs.aw_ready = __rhs.aw_ready; \ + __opt_as __lhs.ar_ready = __rhs.ar_ready; \ + __opt_as __lhs.w_ready = __rhs.w_ready; \ + __opt_as __lhs.b_valid = __rhs.b_valid; \ + `__AXI_TO_B(__opt_as, __lhs.b, __lhs_sep, __rhs.b, __rhs_sep) \ + __opt_as __lhs.r_valid = __rhs.r_valid; \ + `__ACE_TO_R(__opt_as, __lhs.r, __lhs_sep, __rhs.r, __rhs_sep) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning one AXI4+ATOP interface to another, as if you would do `assign slv = mst;` +// +// The channel assignments `ACE_ASSIGN_XX(dst, src)` assign all payload and the valid signal of the +// `XX` channel from the `src` to the `dst` interface and they assign the ready signal from the +// `src` to the `dst` interface. +// The interface assignment `AXI_ASSIGN(dst, src)` assigns all channels including handshakes as if +// `src` was the master of `dst`. +// +// Usage Example: +// `ACE_ASSIGN(slv, mst) +// `ACE_ASSIGN_AW(dst, src) +// `ACE_ASSIGN_R(dst, src) +`define ACE_ASSIGN_AW(dst, src) \ + `__ACE_TO_AW(assign, dst.aw, _, src.aw, _) \ + assign dst.aw_valid = src.aw_valid; \ + assign src.aw_ready = dst.aw_ready; + +`define ACE_ASSIGN_AR(dst, src) \ + `__ACE_TO_AR(assign, dst.ar, _, src.ar, _) \ + assign dst.ar_valid = src.ar_valid; \ + assign src.ar_ready = dst.ar_ready; +`define ACE_ASSIGN_R(dst, src) \ + `__ACE_TO_R(assign, dst.r, _, src.r, _) \ + assign dst.r_valid = src.r_valid; \ + assign src.r_ready = dst.r_ready; +`define ACE_ASSIGN(slv, mst) \ + `ACE_ASSIGN_AW(slv, mst) \ + `AXI_ASSIGN_W(slv, mst) \ + `AXI_ASSIGN_B(mst, slv) \ + `ACE_ASSIGN_AR(slv, mst) \ + `ACE_ASSIGN_R(mst, slv) \ + assign slv.wack = mst.wack; \ + assign slv.rack = mst.rack; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning a AXI4+ATOP interface to a monitor modport, as if you would do `assign mon = axi_if;` +// +// The channel assignment `ACE_ASSIGN_MONITOR(mon_dv, axi_if)` assigns all signals from `axi_if` +// to the `mon_dv` interface. +// +// Usage Example: +// `ACE_ASSIGN_MONITOR(mon_dv, axi_if) +`define ACE_ASSIGN_MONITOR(mon_dv, axi_if) \ + `__ACE_TO_AW(assign, mon_dv.aw, _, axi_if.aw, _) \ + assign mon_dv.aw_valid = axi_if.aw_valid; \ + assign mon_dv.aw_ready = axi_if.aw_ready; \ + `__AXI_TO_W(assign, mon_dv.w, _, axi_if.w, _) \ + assign mon_dv.w_valid = axi_if.w_valid; \ + assign mon_dv.w_ready = axi_if.w_ready; \ + `__AXI_TO_B(assign, mon_dv.b, _, axi_if.b, _) \ + assign mon_dv.b_valid = axi_if.b_valid; \ + assign mon_dv.b_ready = axi_if.b_ready; \ + `__ACE_TO_AR(assign, mon_dv.ar, _, axi_if.ar, _) \ + assign mon_dv.ar_valid = axi_if.ar_valid; \ + assign mon_dv.ar_ready = axi_if.ar_ready; \ + `__ACE_TO_R(assign, mon_dv.r, _, axi_if.r, _) \ + assign mon_dv.r_valid = axi_if.r_valid; \ + assign mon_dv.r_ready = axi_if.r_ready; \ + assign mon_dv.wack = axi_if.wack; \ + assign mon_dv.rack = axi_if.rack; +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting an interface from channel or request/response structs inside a process. +// +// The channel macros `ACE_SET_FROM_XX(axi_if, xx_struct)` set the payload signals of the `axi_if` +// interface from the signals in `xx_struct`. They do not set the handshake signals. +// The request macro `ACE_SET_FROM_REQ(axi_if, req_struct)` sets all request channels (AW, W, AR) +// and the request-side handshake signals (AW, W, and AR valid and B and R ready) of the `axi_if` +// interface from the signals in `req_struct`. +// The response macro `ACE_SET_FROM_RESP(axi_if, resp_struct)` sets both response channels (B and R) +// and the response-side handshake signals (B and R valid and AW, W, and AR ready) of the `axi_if` +// interface from the signals in `resp_struct`. +// +// Usage Example: +// always_comb begin +// `ACE_SET_FROM_REQ(my_if, my_req_struct) +// end +`define ACE_SET_FROM_AW(axi_if, aw_struct) `__ACE_TO_AW(, axi_if.aw, _, aw_struct, .) +`define ACE_SET_FROM_AR(axi_if, ar_struct) `__ACE_TO_AR(, axi_if.ar, _, ar_struct, .) +`define ACE_SET_FROM_R(axi_if, r_struct) `__ACE_TO_R(, axi_if.r, _, r_struct, .) +`define ACE_SET_FROM_REQ(axi_if, req_struct) `__ACE_TO_REQ(, axi_if, _, req_struct, .) +`define ACE_SET_FROM_RESP(axi_if, resp_struct) `__ACE_TO_RESP(, axi_if, _, resp_struct, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning an interface from channel or request/response structs outside a process. +// +// The channel macros `ACE_ASSIGN_FROM_XX(axi_if, xx_struct)` assign the payload signals of the +// `axi_if` interface from the signals in `xx_struct`. They do not assign the handshake signals. +// The request macro `ACE_ASSIGN_FROM_REQ(axi_if, req_struct)` assigns all request channels (AW, W, +// AR) and the request-side handshake signals (AW, W, and AR valid and B and R ready) of the +// `axi_if` interface from the signals in `req_struct`. +// The response macro `ACE_ASSIGN_FROM_RESP(axi_if, resp_struct)` assigns both response channels (B +// and R) and the response-side handshake signals (B and R valid and AW, W, and AR ready) of the +// `axi_if` interface from the signals in `resp_struct`. +// +// Usage Example: +// `ACE_ASSIGN_FROM_REQ(my_if, my_req_struct) +`define ACE_ASSIGN_FROM_AW(axi_if, aw_struct) `__ACE_TO_AW(assign, axi_if.aw, _, aw_struct, .) +`define ACE_ASSIGN_FROM_AR(axi_if, ar_struct) `__ACE_TO_AR(assign, axi_if.ar, _, ar_struct, .) +`define ACE_ASSIGN_FROM_R(axi_if, r_struct) `__ACE_TO_R(assign, axi_if.r, _, r_struct, .) +`define ACE_ASSIGN_FROM_REQ(axi_if, req_struct) `__ACE_TO_REQ(assign, axi_if, _, req_struct, .) +`define ACE_ASSIGN_FROM_RESP(axi_if, resp_struct) `__ACE_TO_RESP(assign, axi_if, _, resp_struct, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting channel or request/response structs from an interface inside a process. +// +// The channel macros `ACE_SET_TO_XX(xx_struct, axi_if)` set the signals of `xx_struct` to the +// payload signals of that channel in the `axi_if` interface. They do not set the handshake +// signals. +// The request macro `ACE_SET_TO_REQ(axi_if, req_struct)` sets all signals of `req_struct` (i.e., +// request channel (AW, W, AR) payload and request-side handshake signals (AW, W, and AR valid and +// B and R ready)) to the signals in the `axi_if` interface. +// The response macro `ACE_SET_TO_RESP(axi_if, resp_struct)` sets all signals of `resp_struct` +// (i.e., response channel (B and R) payload and response-side handshake signals (B and R valid and +// AW, W, and AR ready)) to the signals in the `axi_if` interface. +// +// Usage Example: +// always_comb begin +// `ACE_SET_TO_REQ(my_req_struct, my_if) +// end +`define ACE_SET_TO_AW(aw_struct, axi_if) `__ACE_TO_AW(, aw_struct, ., axi_if.aw, _) +`define ACE_SET_TO_AR(ar_struct, axi_if) `__ACE_TO_AR(, ar_struct, ., axi_if.ar, _) +`define ACE_SET_TO_R(r_struct, axi_if) `__ACE_TO_R(, r_struct, ., axi_if.r, _) +`define ACE_SET_TO_REQ(req_struct, axi_if) `__ACE_TO_REQ(, req_struct, ., axi_if, _) +`define ACE_SET_TO_RESP(resp_struct, axi_if) `__ACE_TO_RESP(, resp_struct, ., axi_if, _) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning channel or request/response structs from an interface outside a process. +// +// The channel macros `ACE_ASSIGN_TO_XX(xx_struct, axi_if)` assign the signals of `xx_struct` to the +// payload signals of that channel in the `axi_if` interface. They do not assign the handshake +// signals. +// The request macro `ACE_ASSIGN_TO_REQ(axi_if, req_struct)` assigns all signals of `req_struct` +// (i.e., request channel (AW, W, AR) payload and request-side handshake signals (AW, W, and AR +// valid and B and R ready)) to the signals in the `axi_if` interface. +// The response macro `ACE_ASSIGN_TO_RESP(axi_if, resp_struct)` assigns all signals of `resp_struct` +// (i.e., response channel (B and R) payload and response-side handshake signals (B and R valid and +// AW, W, and AR ready)) to the signals in the `axi_if` interface. +// +// Usage Example: +// `ACE_ASSIGN_TO_REQ(my_req_struct, my_if) +`define ACE_ASSIGN_TO_AW(aw_struct, axi_if) `__ACE_TO_AW(assign, aw_struct, ., axi_if.aw, _) +`define ACE_ASSIGN_TO_AR(ar_struct, axi_if) `__ACE_TO_AR(assign, ar_struct, ., axi_if.ar, _) +`define ACE_ASSIGN_TO_R(r_struct, axi_if) `__ACE_TO_R(assign, r_struct, ., axi_if.r, _) +`define ACE_ASSIGN_TO_REQ(req_struct, axi_if) `__ACE_TO_REQ(assign, req_struct, ., axi_if, _) +`define ACE_ASSIGN_TO_RESP(resp_struct, axi_if) `__ACE_TO_RESP(assign, resp_struct, ., axi_if, _) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting channel or request/response structs from another struct inside a process. +// +// The channel macros `ACE_SET_XX_STRUCT(lhs, rhs)` set the fields of the `lhs` channel struct to +// the fields of the `rhs` channel struct. They do not set the handshake signals, which are not +// part of channel structs. +// The request macro `ACE_SET_REQ_STRUCT(lhs, rhs)` sets all fields of the `lhs` request struct to +// the fields of the `rhs` request struct. This includes all request channel (AW, W, AR) payload +// and request-side handshake signals (AW, W, and AR valid and B and R ready). +// The response macro `ACE_SET_RESP_STRUCT(lhs, rhs)` sets all fields of the `lhs` response struct +// to the fields of the `rhs` response struct. This includes all response channel (B and R) payload +// and response-side handshake signals (B and R valid and AW, W, and R ready). +// +// Usage Example: +// always_comb begin +// `AXI_SET_S_REQ_STRUCT(my_req_struct, another_req_struct) +// end +`define ACE_SET_AW_STRUCT(lhs, rhs) `__ACE_TO_AW(, lhs, ., rhs, .) +`define ACE_SET_AR_STRUCT(lhs, rhs) `__ACE_TO_AR(, lhs, ., rhs, .) +`define ACE_SET_R_STRUCT(lhs, rhs) `__ACE_TO_R(, lhs, ., rhs, .) +`define ACE_SET_REQ_STRUCT(lhs, rhs) `__ACE_TO_REQ(, lhs, ., rhs, .) +`define ACE_SET_RESP_STRUCT(lhs, rhs) `__ACE_TO_RESP(, lhs, ., rhs, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning channel or request/response structs from another struct outside a process. +// +// The channel macros `ACE_ASSIGN_XX_STRUCT(lhs, rhs)` assign the fields of the `lhs` channel struct +// to the fields of the `rhs` channel struct. They do not assign the handshake signals, which are +// not part of the channel structs. +// The request macro `ACE_ASSIGN_REQ_STRUCT(lhs, rhs)` assigns all fields of the `lhs` request +// struct to the fields of the `rhs` request struct. This includes all request channel (AW, W, AR) +// payload and request-side handshake signals (AW, W, and AR valid and B and R ready). +// The response macro `ACE_ASSIGN_RESP_STRUCT(lhs, rhs)` assigns all fields of the `lhs` response +// struct to the fields of the `rhs` response struct. This includes all response channel (B and R) +// payload and response-side handshake signals (B and R valid and AW, W, and R ready). +// +// Usage Example: +// `ACE_ASSIGN_REQ_STRUCT(my_req_struct, another_req_struct) +`define ACE_ASSIGN_AW_STRUCT(lhs, rhs) `__ACE_TO_AW(assign, lhs, ., rhs, .) +`define ACE_ASSIGN_AR_STRUCT(lhs, rhs) `__ACE_TO_AR(assign, lhs, ., rhs, .) +`define ACE_ASSIGN_R_STRUCT(lhs, rhs) `__ACE_TO_R(assign, lhs, ., rhs, .) +`define ACE_ASSIGN_REQ_STRUCT(lhs, rhs) `__ACE_TO_REQ(assign, lhs, ., rhs, .) +`define ACE_ASSIGN_RESP_STRUCT(lhs, rhs) `__ACE_TO_RESP(assign, lhs, ., rhs, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal implementation for assigning one SNOOP struct or interface to another struct or interface. +// The path to the signals on each side is defined by the `__sep*` arguments. The `__opt_as` +// argument allows to use this standalone (with `__opt_as = assign`) or in assignments inside +// processes (with `__opt_as` void). +`define __SNOOP_TO_AC(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``addr = __rhs``__rhs_sep``addr; \ + __opt_as __lhs``__lhs_sep``snoop = __rhs``__rhs_sep``snoop; \ + __opt_as __lhs``__lhs_sep``prot = __rhs``__rhs_sep``prot; +`define __SNOOP_TO_CD(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``data = __rhs``__rhs_sep``data; \ + __opt_as __lhs``__lhs_sep``last = __rhs``__rhs_sep``last; +`define __SNOOP_TO_CR(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``resp = __rhs``__rhs_sep``resp; +`define __SNOOP_TO_REQ(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + `__SNOOP_TO_AC(__opt_as, __lhs.ac, __lhs_sep, __rhs.ac, __rhs_sep) \ + __opt_as __lhs.ac_valid = __rhs.ac_valid; \ + __opt_as __lhs.cd_ready = __rhs.cd_ready; \ + __opt_as __lhs.cr_ready = __rhs.cr_ready; +`define __SNOOP_TO_RESP(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs.ac_ready = __rhs.ac_ready; \ + __opt_as __lhs.cd_valid = __rhs.cd_valid; \ + `__SNOOP_TO_CD(__opt_as, __lhs.cd, __lhs_sep, __rhs.cd, __rhs_sep) \ + __opt_as __lhs.cr_valid = __rhs.cr_valid; \ + __opt_as __lhs.cr_resp = __rhs.cr_resp; +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning one SNOOP+ATOP interface to another, as if you would do `assign slv = mst;` +// +// The channel assignments `SNOOP_ASSIGN_XX(dst, src)` assign all payload and the valid signal of the +// `XX` channel from the `src` to the `dst` interface and they assign the ready signal from the +// `src` to the `dst` interface. +// The interface assignment `SNOOP_ASSIGN(dst, src)` assigns all channels including handshakes as if +// `src` was the master of `dst`. +// +// Usage Example: +// `SNOOP_ASSIGN(slv, mst) +// `SNOOP_ASSIGN_AC(dst, src) +// `SNOOP_ASSIGN_Cd(dst, src) +`define SNOOP_ASSIGN_AC(dst, src) \ + `__SNOOP_TO_AC(assign, dst.ac, _, src.ac, _) \ + assign dst.ac_valid = src.ac_valid; \ + assign src.ac_ready = dst.ac_ready; +`define SNOOP_ASSIGN_CD(dst, src) \ + `__SNOOP_TO_CD(assign, dst.cd, _, src.cd, _) \ + assign dst.cd_valid = src.cd_valid; \ + assign src.cd_ready = dst.cd_ready; +`define SNOOP_ASSIGN_CR(dst, src) \ + `__SNOOP_TO_CR(assign, dst.cr, _, src.cr, _) \ + assign dst.cr_valid = src.cr_valid; \ + assign src.cr_ready = dst.cr_ready; +`define SNOOP_ASSIGN(slv, mst) \ + `SNOOP_ASSIGN_AC(slv, mst) \ + `SNOOP_ASSIGN_CD(mst, slv) \ + `SNOOP_ASSIGN_CR(mst, slv) +//////////////////////////////////////////////////////////////////////////////////////////////////// +// The channel assignment `SNOOP_ASSIGN_MONITOR(mon_dv, snoop_if)` assigns all signals from `snoop_if` +// to the `mon_dv` interface. +// +// Usage Example: +// `SNOOP_ASSIGN_MONITOR(mon_dv, snoop_if) +`define SNOOP_ASSIGN_MONITOR(mon_dv, snoop_if) \ + `__SNOOP_TO_AC(assign, mon_dv.ac, _, snoop_if.ac, _) \ + assign mon_dv.ac_valid = snoop_if.ac_valid; \ + assign mon_dv.ac_ready = snoop_if.ac_ready; \ + `__SNOOP_TO_CD(assign, mon_dv.cd, _, snoop_if.cd, _) \ + assign mon_dv.cd_valid = snoop_if.cd_valid; \ + assign mon_dv.cd_ready = snoop_if.cd_ready; \ + `__SNOOP_TO_CR(assign, mon_dv.cr, _, snoop_if.cr, _) \ + assign mon_dv.cr_ready = snoop_if.cr_ready; \ + assign mon_dv.cr_valid = snoop_if.cr_valid; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting an interface from channel or request/response structs inside a process. +// +// The channel macros `SNOOP_SET_FROM_XX(snoop_if, xx_struct)` set the payload signals of the `snoop_if` +// interface from the signals in `xx_struct`. They do not set the handshake signals. +// The request macro `SNOOP_SET_FROM_REQ(snoop_if, req_struct)` sets all request channels (AC) +// and the request-side handshake signals (AC valid, CD and CR ready) of the `snoop_if` +// interface from the signals in `req_struct`. +// The response macro `SNOOP_SET_FROM_RESP(snoop_if, resp_struct)` sets both response channels (CD and CR) +// and the response-side handshake signals (CD and CR valid, AC ready) of the `snoop_if` +// interface from the signals in `resp_struct`. +// +// Usage Example: +// always_comb begin +// `SNOOP_SET_FROM_REQ(my_if, my_req_struct) +// end +`define SNOOP_SET_FROM_AC(snoop_if, ac_struct) `__SNOOP_TO_AC(, snoop_if.ac, _, ac_struct, .) +`define SNOOP_SET_FROM_CD(snoop_if, cd_struct) `__SNOOP_TO_CD(, snoop_if.cd, _, cd_struct, .) +`define SNOOP_SET_FROM_CR(snoop_if, cr_struct) `__SNOOP_TO_CR(, snoop_if.cr, _, cr_struct, .) +`define SNOOP_SET_FROM_REQ(snoop_if, req_struct) `__SNOOP_TO_REQ(, snoop_if, _, req_struct, .) +`define SNOOP_SET_FROM_RESP(snoop_if, resp_struct) `__SNOOP_TO_RESP(, snoop_if, _, resp_struct, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning an interface from channel or request/response structs outside a process. +// +// The channel macros `SNOOP_ASSIGN_FROM_XX(snoop_if, xx_struct)` assign the payload signals of the +// `snoop_if` interface from the signals in `xx_struct`. They do not assign the handshake signals. +// The request macro `SNOOP_ASSIGN_FROM_REQ(snoop_if, req_struct)` assigns all request channels (AC) +// and the request-side handshake signals (AC valid and CD and CR ready) of the `snoop_if` interface +// from the signals in `req_struct`.The response macro `SNOOP_ASSIGN_FROM_RESP(snoop_if, resp_struct)` +// assigns both response channels (CD and CR) and the response-side handshake signals (CD and CR valid +// and AC ready) of the `snoop_if` interface from the signals in `resp_struct`. +// +// Usage Example: +// `SNOOP_ASSIGN_FROM_REQ(my_if, my_req_struct) +`define SNOOP_ASSIGN_FROM_AC(snoop_if, ac_struct) `__SNOOP_TO_AC(assign, snoop_if.ac, _, ac_struct, .) +`define SNOOP_ASSIGN_FROM_CD(snoop_if, cd_struct) `__SNOOP_TO_CD(assign, snoop_if.cd, _, cd_struct, .) +`define SNOOP_ASSIGN_FROM_CR(snoop_if, cr_struct) `__SNOOP_TO_CR(assign, snoop_if.cr, _, cr_struct, .) +`define SNOOP_ASSIGN_FROM_REQ(snoop_if, req_struct) `__SNOOP_TO_REQ(assign, snoop_if, _, req_struct, .) +`define SNOOP_ASSIGN_FROM_RESP(snoop_if, resp_struct) `__SNOOP_TO_RESP(assign, snoop_if, _, resp_struct, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting channel or request/response structs from an interface inside a process. +// +// The channel macros `SNOOP_SET_TO_XX(xx_struct, snoop_if)` set the signals of `xx_struct` to the +// payload signals of that channel in the `snoop_if` interface. They do not set the handshake +// signals. +// The request macro `SNOOP_SET_TO_REQ(snoop_if, req_struct)` sets all signals of `req_struct` (i.e., +// request channel (AC) payload and request-side handshake signals (AC valid and +// CD and CR ready)) to the signals in the `snoop_if` interface. +// The response macro `SNOOP_SET_TO_RESP(snoop_if, resp_struct)` sets all signals of `resp_struct` +// (i.e., response channel (CD and CR) payload and response-side handshake signals (CD and CR valid and +// AC ready)) to the signals in the `snoop_if` interface. +// +// Usage Example: +// always_comb begin +// `SNOOP_SET_TO_REQ(my_req_struct, my_if) +// end +`define SNOOP_SET_TO_AC(ac_struct, snoop_if) `__SNOOP_TO_AC(, ac_struct, ., snoop_if.ac, _) +`define SNOOP_SET_TO_CD(cd_struct, snoop_if) `__SNOOP_TO_CD(, cd_struct, ., snoop_if.cd, _) +`define SNOOP_SET_TO_CR(cr_struct, snoop_if) `__SNOOP_TO_CR(, cr_struct, ., snoop_if.cr, _) +`define SNOOP_SET_TO_REQ(req_struct, snoop_if) `__SNOOP_TO_REQ(, req_struct, ., snoop_if, _) +`define SNOOP_SET_TO_RESP(resp_struct, snoop_if) `__SNOOP_TO_RESP(, resp_struct, ., snoop_if, _) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning channel or request/response structs from an interface outside a process. +// +// The channel macros `SNOOP_ASSIGN_TO_XX(xx_struct, snoop_if)` assign the signals of `xx_struct` to the +// payload signals of that channel in the `snoop_if` interface. They do not assign the handshake +// signals. +// The request macro `SNOOP_ASSIGN_TO_REQ(snoop_if, req_struct)` assigns all signals of `req_struct` +// (i.e., request channel (AC) payload and request-side handshake signals (AC valid and CD and CR ready)) +// to the signals in the `snoop_if` interface. +// The response macro `SNOOP_ASSIGN_TO_RESP(snoop_if, resp_struct)` assigns all signals of `resp_struct` +// (i.e., response channel (CD and CR) payload and response-side handshake signals (CD and CR valid and +// AC ready)) to the signals in the `snoop_if` interface. +// +// Usage Example: +// `SNOOP_ASSIGN_TO_REQ(my_req_struct, my_if) +`define SNOOP_ASSIGN_TO_AC(aw_struct, snoop_if) `__SNOOP_TO_AC(assign, aw_struct, ., snoop_if.aw, _) +`define SNOOP_ASSIGN_TO_CD(ar_struct, snoop_if) `__SNOOP_TO_CD(assign, ar_struct, ., snoop_if.ar, _) +`define SNOOP_ASSIGN_TO_CR(r_struct, snoop_if) `__SNOOP_TO_CR(assign, r_struct, ., snoop_if.r, _) +`define SNOOP_ASSIGN_TO_REQ(req_struct, snoop_if) `__SNOOP_TO_REQ(assign, req_struct, ., snoop_if, _) +`define SNOOP_ASSIGN_TO_RESP(resp_struct, snoop_if) `__SNOOP_TO_RESP(assign, resp_struct, ., snoop_if, _) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting channel or request/response structs from another struct inside a process. +// +// The channel macros `SNOOP_SET_XX_STRUCT(lhs, rhs)` set the fields of the `lhs` channel struct to +// the fields of the `rhs` channel struct. They do not set the handshake signals, which are not +// part of channel structs. +// The request macro `SNOOP_SET_REQ_STRUCT(lhs, rhs)` sets all fields of the `lhs` request struct to +// the fields of the `rhs` request struct. This includes all request channel (AC) payload +// and request-side handshake signals (AC valid and CD and CR ready). +// The response macro `SNOOP_SET_RESP_STRUCT(lhs, rhs)` sets all fields of the `lhs` response struct +// to the fields of the `rhs` response struct. This includes all response channel (CD and CR) payload +// and response-side handshake signals (CD and CR valid and AC ready). +// +// Usage Example: +// always_comb begin +// `SNOOP_SET_S_REQ_STRUCT(my_req_struct, another_req_struct) +// end +`define SNOOP_SET_AC_STRUCT(lhs, rhs) `__SNOOP_TO_AC(, lhs, ., rhs, .) +`define SNOOP_SET_CD_STRUCT(lhs, rhs) `__SNOOP_TO_CD(, lhs, ., rhs, .) +`define SNOOP_SET_CR_STRUCT(lhs, rhs) `__SNOOP_TO_CR(, lhs, ., rhs, .) +`define SNOOP_SET_REQ_STRUCT(lhs, rhs) `__SNOOP_TO_REQ(, lhs, ., rhs, .) +`define SNOOP_SET_RESP_STRUCT(lhs, rhs) `__SNOOP_TO_RESP(, lhs, ., rhs, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning channel or request/response structs from another struct outside a process. +// +// The channel macros `SNOOP_ASSIGN_XX_STRUCT(lhs, rhs)` assign the fields of the `lhs` channel struct +// to the fields of the `rhs` channel struct. They do not assign the handshake signals, which are +// not part of the channel structs. +// The request macro `SNOOP_ASSIGN_REQ_STRUCT(lhs, rhs)` assigns all fields of the `lhs` request +// struct to the fields of the `rhs` request struct. This includes all request channel (AW, W, AR) +// payload and request-side handshake signals (AC valid and CD and CR ready). +// The response macro `SNOOP_ASSIGN_RESP_STRUCT(lhs, rhs)` assigns all fields of the `lhs` response +// struct to the fields of the `rhs` response struct. This includes all response channel (CD and CR) +// payload and response-side handshake signals (CD and CR valid and AC ready). +// +// Usage Example: +// `SNOOP_ASSIGN_REQ_STRUCT(my_req_struct, another_req_struct) +`define SNOOP_ASSIGN_AC_STRUCT(lhs, rhs) `__SNOOP_TO_AC(assign, lhs, ., rhs, .) +`define SNOOP_ASSIGN_CD_STRUCT(lhs, rhs) `__SNOOP_TO_CD(assign, lhs, ., rhs, .) +`define SNOOP_ASSIGN_CR_STRUCT(lhs, rhs) `__SNOOP_TO_CR(assign, lhs, ., rhs, .) +`define SNOOP_ASSIGN_REQ_STRUCT(lhs, rhs) `__SNOOP_TO_REQ(assign, lhs, ., rhs, .) +`define SNOOP_ASSIGN_RESP_STRUCT(lhs, rhs) `__SNOOP_TO_RESP(assign, lhs, ., rhs, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +`endif diff --git a/include/ace/convert.svh b/include/ace/convert.svh new file mode 100644 index 000000000..61f840b24 --- /dev/null +++ b/include/ace/convert.svh @@ -0,0 +1,104 @@ +`include "axi/assign.svh" + +`ifndef ACE_CONVERT_SVH_ +`define ACE_CONVERT_SVH_ + +`define __ACE_TO_AXI_R(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``data = __rhs``__rhs_sep``data; \ + __opt_as __lhs``__lhs_sep``resp = __rhs``__rhs_sep``resp[1:0]; \ + __opt_as __lhs``__lhs_sep``last = __rhs``__rhs_sep``last; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; +`define __AXI_TO_ACE_AW(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``addr = __rhs``__rhs_sep``addr; \ + __opt_as __lhs``__lhs_sep``len = __rhs``__rhs_sep``len; \ + __opt_as __lhs``__lhs_sep``size = __rhs``__rhs_sep``size; \ + __opt_as __lhs``__lhs_sep``burst = __rhs``__rhs_sep``burst; \ + __opt_as __lhs``__lhs_sep``lock = __rhs``__rhs_sep``lock; \ + __opt_as __lhs``__lhs_sep``cache = __rhs``__rhs_sep``cache; \ + __opt_as __lhs``__lhs_sep``prot = __rhs``__rhs_sep``prot; \ + __opt_as __lhs``__lhs_sep``qos = __rhs``__rhs_sep``qos; \ + __opt_as __lhs``__lhs_sep``region = __rhs``__rhs_sep``region; \ + __opt_as __lhs``__lhs_sep``atop = __rhs``__rhs_sep``atop; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; \ + __opt_as __lhs``__lhs_sep``snoop = '0; \ + __opt_as __lhs``__lhs_sep``bar = '0; \ + __opt_as __lhs``__lhs_sep``domain = '0; \ + __opt_as __lhs``__lhs_sep``awunique = '0; +`define __AXI_TO_ACE_AR(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``addr = __rhs``__rhs_sep``addr; \ + __opt_as __lhs``__lhs_sep``len = __rhs``__rhs_sep``len; \ + __opt_as __lhs``__lhs_sep``size = __rhs``__rhs_sep``size; \ + __opt_as __lhs``__lhs_sep``burst = __rhs``__rhs_sep``burst; \ + __opt_as __lhs``__lhs_sep``lock = __rhs``__rhs_sep``lock; \ + __opt_as __lhs``__lhs_sep``cache = __rhs``__rhs_sep``cache; \ + __opt_as __lhs``__lhs_sep``prot = __rhs``__rhs_sep``prot; \ + __opt_as __lhs``__lhs_sep``qos = __rhs``__rhs_sep``qos; \ + __opt_as __lhs``__lhs_sep``region = __rhs``__rhs_sep``region; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; \ + __opt_as __lhs``__lhs_sep``snoop = '0; \ + __opt_as __lhs``__lhs_sep``bar = '0; \ + __opt_as __lhs``__lhs_sep``domain = '0; +`define __AXI_TO_ACE_R(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``data = __rhs``__rhs_sep``data; \ + __opt_as __lhs``__lhs_sep``resp = {2'b00, __rhs``__rhs_sep``resp}; \ + __opt_as __lhs``__lhs_sep``last = __rhs``__rhs_sep``last; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; + +`define ACE_TO_AXI_ASSIGN_R_STRUCT(dst, src) \ + `__ACE_TO_AXI_R(assign, dst, ., src, .) + +`define AXI_TO_ACE_ASSIGN_AW_STRUCT(dst, src) \ + `__AXI_TO_ACE_AW(assign, dst, ., src, .) + +`define AXI_TO_ACE_ASSIGN_AR_STRUCT(dst, src) \ + `__AXI_TO_ACE_AR(assign, dst, ., src, .) + +`define AXI_TO_ACE_ASSIGN_R_STRUCT(dst, src) \ + `__AXI_TO_ACE_R(assign, dst, ., src, .) + + +`define ACE_TO_AXI_ASSIGN_REQ(dst, src) \ + `AXI_ASSIGN_AW_STRUCT(dst.aw, src.aw) \ + `AXI_ASSIGN_AR_STRUCT(dst.ar, src.ar) \ + `AXI_ASSIGN_W_STRUCT(dst.w, src.w) \ + assign dst.aw_valid = src.aw_valid; \ + assign dst.ar_valid = src.ar_valid; \ + assign dst.w_valid = src.w_valid; \ + assign dst.b_ready = src.b_ready; \ + assign dst.r_ready = src.r_ready; + +`define ACE_TO_AXI_ASSIGN_RESP(dst, src) \ + `ACE_TO_AXI_ASSIGN_R_STRUCT(dst.r, src.r) \ + `AXI_ASSIGN_B_STRUCT(dst.b, src.b) \ + assign dst.aw_ready = src.aw_ready; \ + assign dst.ar_ready = src.ar_ready; \ + assign dst.w_ready = src.w_ready; \ + assign dst.b_valid = src.b_valid; \ + assign dst.r_valid = src.r_valid; + +`define AXI_TO_ACE_ASSIGN_REQ(dst, src) \ + `AXI_TO_ACE_ASSIGN_AW_STRUCT(dst.aw, src.aw) \ + `AXI_TO_ACE_ASSIGN_AR_STRUCT(dst.ar, src.ar) \ + `AXI_ASSIGN_W_STRUCT(dst.w, src.w) \ + assign dst.aw_valid = src.aw_valid; \ + assign dst.ar_valid = src.ar_valid; \ + assign dst.w_valid = src.w_valid; \ + assign dst.b_ready = src.b_ready; \ + assign dst.r_ready = src.r_ready; + + +`define AXI_TO_ACE_ASSIGN_RESP(dst, src) \ + `AXI_TO_ACE_ASSIGN_R_STRUCT(dst.r, src.r) \ + `AXI_ASSIGN_B_STRUCT(dst.b, src.b) \ + assign dst.aw_ready = src.aw_ready; \ + assign dst.ar_ready = src.ar_ready; \ + assign dst.w_ready = src.w_ready; \ + assign dst.b_valid = src.b_valid; \ + assign dst.r_valid = src.r_valid; + + +`endif // ACE_CONVERT_SVH_ diff --git a/include/ace/domain.svh b/include/ace/domain.svh new file mode 100644 index 000000000..cbc867373 --- /dev/null +++ b/include/ace/domain.svh @@ -0,0 +1,28 @@ +`ifndef ACE_DOMAIN_SVH_ +`define ACE_DOMAIN_SVH_ + + ////////////////// + // Domain types // + ////////////////// + + `define DOMAIN_MASK_T(width)\ + logic [width-1:0] + `define DOMAIN_SET_T \ + struct packed { \ + domain_mask_t initiator; \ + domain_mask_t inner; \ + domain_mask_t outer; \ + } + `define DOMAIN_TYPEDEF_MASK_T(width) \ + typedef logic [width-1:0] domain_mask_t; + `define DOMAIN_TYPEDEF_SET_T \ + typedef struct packed { \ + domain_mask_t initiator; \ + domain_mask_t inner; \ + domain_mask_t outer; \ + } domain_set_t; + `define DOMAIN_TYPEDEF_ALL(width) \ + `DOMAIN_TYPEDEF_MASK_T(width) \ + `DOMAIN_TYPEDEF_SET_T + +`endif // ACE_DOMAIN_SVH_ diff --git a/include/ace/typedef.svh b/include/ace/typedef.svh new file mode 100644 index 000000000..fb35d1cc5 --- /dev/null +++ b/include/ace/typedef.svh @@ -0,0 +1,167 @@ +// Copyright (c) 2019 ETH Zurich, University of Bologna +// Copyright (c) 2022 PlanV GmbH +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. +// + +// Macros to define ACE Channel and Request/Response Structs + +`ifndef ACE_TYPEDEF_SVH_ +`define ACE_TYPEDEF_SVH_ + +`include "axi/typedef.svh" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// AXI4+ATOP Channel and Request/Response Structs (with snoop support) +// +// Usage Example: +// `ACE_TYPEDEF_AW_CHAN_T(axi_aw_t, axi_addr_t, axi_id_t, axi_user_t) +// `ACE_TYPEDEF_AR_CHAN_T(axi_ar_t, axi_addr_t, axi_id_t, axi_user_t) +// `ACE_TYPEDEF_R_CHAN_T(axi_r_t, axi_data_t, axi_id_t, axi_user_t) +// `ACE_TYPEDEF_REQ_T(axi_req_t, axi_aw_t, axi_w_t, axi_ar_t) +// `ACE_TYPEDEF_RESP_T(axi_resp_t, axi_b_t, axi_r_t) +`define ACE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t) \ + typedef struct packed { \ + id_t id; \ + addr_t addr; \ + axi_pkg::len_t len; \ + axi_pkg::size_t size; \ + axi_pkg::burst_t burst; \ + logic lock; \ + axi_pkg::cache_t cache; \ + axi_pkg::prot_t prot; \ + axi_pkg::qos_t qos; \ + axi_pkg::region_t region; \ + axi_pkg::atop_t atop; \ + user_t user; \ + ace_pkg::awsnoop_t snoop; \ + ace_pkg::axbar_t bar; \ + ace_pkg::axdomain_t domain; \ + ace_pkg::awunique_t awunique; \ + } aw_chan_t; +`define ACE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t) \ + typedef struct packed { \ + id_t id; \ + addr_t addr; \ + axi_pkg::len_t len; \ + axi_pkg::size_t size; \ + axi_pkg::burst_t burst; \ + logic lock; \ + axi_pkg::cache_t cache; \ + axi_pkg::prot_t prot; \ + axi_pkg::qos_t qos; \ + axi_pkg::region_t region; \ + user_t user; \ + ace_pkg::arsnoop_t snoop; \ + ace_pkg::axbar_t bar; \ + ace_pkg::axdomain_t domain; \ + } ar_chan_t; +`define ACE_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t) \ + typedef struct packed { \ + id_t id; \ + data_t data; \ + ace_pkg::rresp_t resp; \ + logic last; \ + user_t user; \ + } r_chan_t; +`define ACE_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t) \ + typedef struct packed { \ + aw_chan_t aw; \ + logic aw_valid; \ + w_chan_t w; \ + logic w_valid; \ + logic b_ready; \ + ar_chan_t ar; \ + logic ar_valid; \ + logic r_ready; \ + logic wack; \ + logic rack; \ + } req_t; +`define ACE_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t) \ + typedef struct packed { \ + logic aw_ready; \ + logic ar_ready; \ + logic w_ready; \ + logic b_valid; \ + b_chan_t b; \ + logic r_valid; \ + r_chan_t r; \ + } resp_t; +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// All AXI4+ATOP Channels and Request/Response Structs in One Macro (with snoop support) +// +// This can be used whenever the user is not interested in "precise" control of the naming of the +// individual channels. +// +// Usage Example: +// `AXI_TYPEDEF_ALL(axi, addr_t, id_t, data_t, strb_t, user_t) +// +// This defines `axi_req_t` and `axi_resp_t` request/response structs as well as `axi_aw_chan_t`, +// `axi_w_chan_t`, `axi_b_chan_t`, `axi_ar_chan_t`, and `axi_r_chan_t` channel structs. +`define ACE_TYPEDEF_ALL(__name, __addr_t, __id_t, __data_t, __strb_t, __user_t) \ + `ACE_TYPEDEF_AW_CHAN_T(__name``_aw_chan_t, __addr_t, __id_t, __user_t) \ + `AXI_TYPEDEF_W_CHAN_T(__name``_w_chan_t, __data_t, __strb_t, __user_t) \ + `AXI_TYPEDEF_B_CHAN_T(__name``_b_chan_t, __id_t, __user_t) \ + `ACE_TYPEDEF_AR_CHAN_T(__name``_ar_chan_t, __addr_t, __id_t, __user_t) \ + `ACE_TYPEDEF_R_CHAN_T(__name``_r_chan_t, __data_t, __id_t, __user_t) \ + `ACE_TYPEDEF_REQ_T(__name``_req_t, __name``_aw_chan_t, __name``_w_chan_t, __name``_ar_chan_t) \ + `ACE_TYPEDEF_RESP_T(__name``_resp_t, __name``_b_chan_t, __name``_r_chan_t) +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Usage Example: +// `SNOOP_TYPEDEF_AC_CHAN_T(snoop_ac_t, snoop_addr_t) +// 'SNOOP_TYPEDEF_CD_CHAN_T(snoop_cd_t, snoop_data_t) +// `SNOOP_TYPEDEF_REQ_T(snoop_req_t, snoop_ac_t) +// `SNOOP_TYPEDEF_RESP_T(snoop_resp_t, snoop_cd_t, snoop_cr_t) +`define SNOOP_TYPEDEF_AC_CHAN_T(ac_chan_t, addr_t) \ + typedef struct packed { \ + addr_t addr; \ + ace_pkg::acsnoop_t snoop; \ + ace_pkg::acprot_t prot; \ + } ac_chan_t; +`define SNOOP_TYPEDEF_CD_CHAN_T(cd_chan_t, data_t) \ + typedef struct packed { \ + data_t data; \ + logic last; \ + } cd_chan_t; +`define SNOOP_TYPEDEF_CR_CHAN_T(cr_chan_t) \ + typedef ace_pkg::crresp_t cr_chan_t; +`define SNOOP_TYPEDEF_REQ_T(req_t, ac_chan_t) \ + typedef struct packed { \ + logic ac_valid; \ + logic cd_ready; \ + ac_chan_t ac; \ + logic cr_ready; \ + } req_t; +`define SNOOP_TYPEDEF_RESP_T(resp_t, cd_chan_t, cr_chan_t) \ + typedef struct packed { \ + logic ac_ready; \ + logic cd_valid; \ + cd_chan_t cd; \ + logic cr_valid; \ + cr_chan_t cr_resp; \ + } resp_t; +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Usage Example: +// `SNOOP_TYPEDEF_ALL(snoop, addr_t, data_t) +// +// This defines `snoop_req_t` and `snoop_resp_t` request/response structs as well as `snoop_ac_chan_t`, +// `snoop_cd_chan_t` and `snoop_cr_chan_t` channel structs. + `define SNOOP_TYPEDEF_ALL(__name, __addr_t, __data_t) \ + `SNOOP_TYPEDEF_AC_CHAN_T(__name``_aw_chan_t, __addr_t) \ + `SNOOP_TYPEDEF_CR_CHAN_T(__name``_cr_chan_t) \ + `SNOOP_TYPEDEF_CD_CHAN_T(__name``_cd_chan_t, __data_t) \ + `SNOOP_TYPEDEF_REQ_T(__name``_req_t, __name``_ac_chan_t) \ + `SNOOP_TYPEDEF_RESP_T(__name``_resp_t, __name``_cd_chan_t, __name``_cr_chan_t) +//////////////////////////////////////////////////////////////////////////////////////////////////// + +`endif diff --git a/src/ace/ace_intf.sv b/src/ace/ace_intf.sv new file mode 100644 index 000000000..ce79e57c1 --- /dev/null +++ b/src/ace/ace_intf.sv @@ -0,0 +1,277 @@ +// Copyright (c) 2014-2018 ETH Zurich, University of Bologna +// Copyright (c) 2022 PlanV GmbH +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + +interface CLK_IF (input clk_i); +endinterface + +// ACE bus interafces +interface ACE_BUS #( + parameter int unsigned AXI_ADDR_WIDTH = 0, + parameter int unsigned AXI_DATA_WIDTH = 0, + parameter int unsigned AXI_ID_WIDTH = 0, + parameter int unsigned AXI_USER_WIDTH = 0 +); + + localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; + + typedef logic [AXI_ID_WIDTH-1:0] id_t; + typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; + typedef logic [AXI_DATA_WIDTH-1:0] data_t; + typedef logic [AXI_STRB_WIDTH-1:0] strb_t; + typedef logic [AXI_USER_WIDTH-1:0] user_t; + + id_t aw_id; + addr_t aw_addr; + axi_pkg::len_t aw_len; + axi_pkg::size_t aw_size; + axi_pkg::burst_t aw_burst; + logic aw_lock; + axi_pkg::cache_t aw_cache; + axi_pkg::prot_t aw_prot; + axi_pkg::qos_t aw_qos; + axi_pkg::region_t aw_region; + axi_pkg::atop_t aw_atop; + user_t aw_user; + logic aw_valid; + logic aw_ready; + ace_pkg::awsnoop_t aw_snoop; + ace_pkg::axbar_t aw_bar; + ace_pkg::axdomain_t aw_domain; + ace_pkg::awunique_t aw_awunique; + + data_t w_data; + strb_t w_strb; + logic w_last; + user_t w_user; + logic w_valid; + logic w_ready; + + id_t b_id; + axi_pkg::resp_t b_resp; + user_t b_user; + logic b_valid; + logic b_ready; + + id_t ar_id; + addr_t ar_addr; + axi_pkg::len_t ar_len; + axi_pkg::size_t ar_size; + axi_pkg::burst_t ar_burst; + logic ar_lock; + axi_pkg::cache_t ar_cache; + axi_pkg::prot_t ar_prot; + axi_pkg::qos_t ar_qos; + axi_pkg::region_t ar_region; + user_t ar_user; + logic ar_valid; + logic ar_ready; + ace_pkg::arsnoop_t ar_snoop; + ace_pkg::axbar_t ar_bar; + ace_pkg::axdomain_t ar_domain; + + id_t r_id; + data_t r_data; + ace_pkg::rresp_t r_resp; + logic r_last; + user_t r_user; + logic r_valid; + logic r_ready; + + logic wack; + logic rack; + + modport Master ( + output aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, input aw_ready, + output w_data, w_strb, w_last, w_user, w_valid, input w_ready, + input b_id, b_resp, b_user, b_valid, output b_ready, + output ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar, ar_domain, input ar_ready, + input r_id, r_data, r_resp, r_last, r_user, r_valid, output r_ready, + output wack, rack + ); + + modport Slave ( + input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, output aw_ready, + input w_data, w_strb, w_last, w_user, w_valid, output w_ready, + output b_id, b_resp, b_user, b_valid, input b_ready, + input ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar, ar_domain, output ar_ready, + output r_id, r_data, r_resp, r_last, r_user, r_valid, input r_ready, + input wack, rack + ); + + modport Monitor ( + input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_ready, aw_snoop, aw_bar, aw_domain, aw_awunique, + w_data, w_strb, w_last, w_user, w_valid, w_ready, + b_id, b_resp, b_user, b_valid, b_ready, + ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_ready, ar_snoop, ar_bar, ar_domain, + r_id, r_data, r_resp, r_last, r_user, r_valid, r_ready, + wack, rack + ); + +endinterface + + +/// A clocked ACE interface for use in design verification. +interface ACE_BUS_DV #( + parameter int unsigned AXI_ADDR_WIDTH = 0, + parameter int unsigned AXI_DATA_WIDTH = 0, + parameter int unsigned AXI_ID_WIDTH = 0, + parameter int unsigned AXI_USER_WIDTH = 0 +)( + input logic clk_i +); + + localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; + + typedef logic [AXI_ID_WIDTH-1:0] id_t; + typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; + typedef logic [AXI_DATA_WIDTH-1:0] data_t; + typedef logic [AXI_STRB_WIDTH-1:0] strb_t; + typedef logic [AXI_USER_WIDTH-1:0] user_t; + + id_t aw_id; + addr_t aw_addr; + axi_pkg::len_t aw_len; + axi_pkg::size_t aw_size; + axi_pkg::burst_t aw_burst; + logic aw_lock; + axi_pkg::cache_t aw_cache; + axi_pkg::prot_t aw_prot; + axi_pkg::qos_t aw_qos; + axi_pkg::region_t aw_region; + axi_pkg::atop_t aw_atop; + user_t aw_user; + logic aw_valid; + logic aw_ready; + ace_pkg::awsnoop_t aw_snoop; + ace_pkg::axbar_t aw_bar; + ace_pkg::axdomain_t aw_domain; + ace_pkg::awunique_t aw_awunique; + + data_t w_data; + strb_t w_strb; + logic w_last; + user_t w_user; + logic w_valid; + logic w_ready; + + id_t b_id; + axi_pkg::resp_t b_resp; + user_t b_user; + logic b_valid; + logic b_ready; + + id_t ar_id; + addr_t ar_addr; + axi_pkg::len_t ar_len; + axi_pkg::size_t ar_size; + axi_pkg::burst_t ar_burst; + logic ar_lock; + axi_pkg::cache_t ar_cache; + axi_pkg::prot_t ar_prot; + axi_pkg::qos_t ar_qos; + axi_pkg::region_t ar_region; + user_t ar_user; + logic ar_valid; + logic ar_ready; + ace_pkg::arsnoop_t ar_snoop; + ace_pkg::axbar_t ar_bar; + ace_pkg::axdomain_t ar_domain; + + id_t r_id; + data_t r_data; + ace_pkg::rresp_t r_resp; + logic r_last; + user_t r_user; + logic r_valid; + logic r_ready; + + logic wack; + logic rack; + + modport Master ( + output aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, input aw_ready, + output w_data, w_strb, w_last, w_user, w_valid, input w_ready, + input b_id, b_resp, b_user, b_valid, output b_ready, + output ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar,ar_domain, input ar_ready, + input r_id, r_data, r_resp, r_last, r_user, r_valid, output r_ready, + output wack, rack + ); + + modport Slave ( + input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, output aw_ready, + input w_data, w_strb, w_last, w_user, w_valid, output w_ready, + output b_id, b_resp, b_user, b_valid, input b_ready, + input ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar, ar_domain, output ar_ready, + output r_id, r_data, r_resp, r_last, r_user, r_valid, input r_ready, + input wack, rack + ); + + modport Monitor ( + input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_ready, aw_snoop, aw_bar, aw_domain, aw_awunique, + w_data, w_strb, w_last, w_user, w_valid, w_ready, + b_id, b_resp, b_user, b_valid, b_ready, + ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_ready, ar_snoop, ar_bar, ar_domain, + r_id, r_data, r_resp, r_last, r_user, r_valid, r_ready, wack, rack + ); + + // pragma translate_off + `ifndef VERILATOR + // Single-Channel Assertions: Signals including valid must not change between valid and handshake. + // AW + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_id))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_addr))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_len))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_size))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_burst))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_lock))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_cache))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_prot))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_qos))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_region))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_atop))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_user))); + assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> aw_valid)); + // W + assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_data))); + assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_strb))); + assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_last))); + assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_user))); + assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> w_valid)); + // B + assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> $stable(b_id))); + assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> $stable(b_resp))); + assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> $stable(b_user))); + assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> b_valid)); + // AR + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_id))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_addr))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_len))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_size))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_burst))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_lock))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_cache))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_prot))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_qos))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_region))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_user))); + assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> ar_valid)); + // R + assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_id))); + assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_data))); + assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_resp))); + assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_last))); + assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_user))); + assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> r_valid)); + `endif + // pragma translate_on + +endinterface diff --git a/src/ace/ace_pkg.sv b/src/ace/ace_pkg.sv new file mode 100644 index 000000000..f27f526db --- /dev/null +++ b/src/ace/ace_pkg.sv @@ -0,0 +1,124 @@ +// Copyright (c) 2014-2018 ETH Zurich, University of Bologna +// Copyright (c) 2022 PlanV GmbH +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + + +//! ACE Package +/// Contains all necessary type definitions, constants, and generally useful functions. +package ace_pkg; + + ////////////// + // Typedefs // + ////////////// + + // Additional types for already existing AXI channels + typedef logic [3:0] arsnoop_t; + typedef logic [2:0] awsnoop_t; + typedef logic [1:0] axbar_t; + typedef logic [1:0] axdomain_t; + typedef logic [3:0] rresp_t; + typedef logic [0:0] awunique_t; + + // Snoop related types + typedef logic [3:0] acsnoop_t; + typedef logic [2:0] acprot_t; + + typedef struct packed { + logic WasUnique; + logic IsShared; + logic PassDirty; + logic Error; + logic DataTransfer; + } crresp_t; + + typedef struct packed { + acsnoop_t snoop_trs; + logic accepts_dirty; + logic accepts_dirty_shared; + logic accepts_shared; + } snoop_info_t; + + /////////////// + // Encodings // + /////////////// + + // AxDOMAIN + localparam axdomain_t NonShareable = 2'b00; + localparam axdomain_t InnerShareable = 2'b01; + localparam axdomain_t OuterShareable = 2'b10; + localparam axdomain_t System = 2'b11; + + + // AxBAR + localparam axbar_t NormalAccessRespectingBarriers = 2'b00; + localparam axbar_t MemoryBarrier = 2'b01; + localparam axbar_t NormalAccessIgnoringBarriers = 2'b10; + localparam axbar_t SynchronizationBarrier = 2'b11; + + // Uniquely defined here both for ARSNOOP and AWSNOOP + localparam int unsigned Barrier = 0; + + // ARSNOOP + localparam arsnoop_t ReadNoSnoop = 4'b0000; + localparam arsnoop_t ReadOnce = 4'b0000; + localparam arsnoop_t ReadShared = 4'b0001; + localparam arsnoop_t ReadClean = 4'b0010; + localparam arsnoop_t ReadNotSharedDirty = 4'b0011; + localparam arsnoop_t ReadUnique = 4'b0111; + localparam arsnoop_t CleanUnique = 4'b1011; + localparam arsnoop_t MakeUnique = 4'b1100; + localparam arsnoop_t CleanShared = 4'b1000; + localparam arsnoop_t CleanInvalid = 4'b1001; + localparam arsnoop_t MakeInvalid = 4'b1101; + localparam arsnoop_t DVMComplete = 4'b1110; + localparam arsnoop_t DVMMessage = 4'b1111; + /* Barrier is already defined */ + + // AWSNOOP + localparam awsnoop_t WriteNoSnoop = 3'b000; + localparam awsnoop_t WriteUnique = 3'b000; + localparam awsnoop_t WriteLineUnique = 3'b001; + localparam awsnoop_t WriteClean = 3'b010; + localparam awsnoop_t WriteBack = 3'b011; + localparam awsnoop_t Evict = 3'b100; + localparam awsnoop_t WriteEvict = 3'b101; + /* Barrier is already defined */ + + // ACSNOOP + // + // The encoding is shared with ARSNOOP transactions for the following cases: + // - ReadOnce + // - ReadShared + // - ReadClean + // - ReadNotSharedDirty + // - ReadUnique + // - CleanShared + // - CleanInvalid + // - MakeInvalid + // - DVMComplete + // - DVMMessage + // Cast the parameters to acsnoop_t for consistency (but works anyway) + + ////////////////// + // Domain rules // + ////////////////// + + localparam int unsigned MaxMasterNum = 16; + localparam int unsigned MasterIdxBits = $clog2(MaxMasterNum); + + typedef struct packed { + logic [MasterIdxBits-1:0] InnerShareableNum; + logic [MaxMasterNum-1:0][MasterIdxBits-1:0] InnerShareableList; + logic [MasterIdxBits-1:0] OuterShareableNum; + logic [MaxMasterNum-1:0][MasterIdxBits-1:0] OuterShareableList; + } domain_rule_t; + +endpackage diff --git a/src/ace/snoop_intf.sv b/src/ace/snoop_intf.sv new file mode 100644 index 000000000..faeb22d98 --- /dev/null +++ b/src/ace/snoop_intf.sv @@ -0,0 +1,122 @@ +// Copyright (c) 2014-2018 ETH Zurich, University of Bologna +// Copyright (c) 2022 PlanV GmbH +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + + +// Snoop bus interafces +interface SNOOP_BUS #( + parameter int unsigned SNOOP_ADDR_WIDTH = 0, + parameter int unsigned SNOOP_DATA_WIDTH = 0 +); + + typedef logic [SNOOP_ADDR_WIDTH-1:0] addr_t; + typedef logic [SNOOP_DATA_WIDTH-1:0] data_t; + + addr_t ac_addr; + ace_pkg::acprot_t ac_prot; + ace_pkg::acsnoop_t ac_snoop; + logic ac_valid; + logic ac_ready; + + ace_pkg::crresp_t cr_resp; + logic cr_valid; + logic cr_ready; + + data_t cd_data; + logic cd_last; + logic cd_valid; + logic cd_ready; + + modport Master ( + input ac_addr, ac_prot, ac_snoop, ac_valid, output ac_ready, + input cr_ready, output cr_valid, cr_resp, + input cd_ready, output cd_data, cd_last, cd_valid + ); + + modport Slave ( + output ac_addr, ac_prot, ac_snoop, ac_valid, input ac_ready, + output cr_ready, input cr_valid, cr_resp, + output cd_ready, input cd_data, cd_last, cd_valid + ); + + + modport Monitor ( + input ac_addr, ac_prot, ac_snoop, ac_valid, ac_ready, + cr_ready, cr_valid, cr_resp, + cd_ready, cd_data, cd_last, cd_valid + ); + +endinterface + +/// A clocked SNOOP interface for use in design verification. +interface SNOOP_BUS_DV #( + parameter int unsigned SNOOP_ADDR_WIDTH = 0, + parameter int unsigned SNOOP_DATA_WIDTH = 0 +)( + input clk_i +); + + typedef logic [SNOOP_ADDR_WIDTH-1:0] addr_t; + typedef logic [SNOOP_DATA_WIDTH-1:0] data_t; + + addr_t ac_addr; + ace_pkg::acprot_t ac_prot; + ace_pkg::acsnoop_t ac_snoop; + logic ac_valid; + logic ac_ready; + + ace_pkg::crresp_t cr_resp; + logic cr_valid; + logic cr_ready; + + data_t cd_data; + logic cd_last; + logic cd_valid; + logic cd_ready; + + modport Master ( + input ac_addr, ac_prot, ac_snoop, ac_valid, output ac_ready, + input cr_ready, output cr_valid, cr_resp, + input cd_ready, output cd_data, cd_last, cd_valid + ); + + modport Slave ( + output ac_addr, ac_prot, ac_snoop, ac_valid, input ac_ready, + output cr_ready, input cr_valid, cr_resp, + output cd_ready, input cd_data, cd_last, cd_valid + ); + + + modport Monitor ( + input ac_addr, ac_prot, ac_snoop, ac_valid, ac_ready, + cr_ready, cr_valid, cr_resp, + cd_ready, cd_data, cd_last, cd_valid + ); + + // pragma translate_off + `ifndef VERILATOR + // Single-Channel Assertions: Signals including valid must not change between valid and handshake. + // AC + assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> $stable(ac_addr))); + assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> $stable(ac_snoop))); + assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> $stable(ac_prot))); + assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> ac_valid)); + // CR + assert property (@(posedge clk_i) (cr_valid && !cr_ready |=> $stable(cr_resp))); + assert property (@(posedge clk_i) (cr_valid && !cr_ready |=> cr_valid)); + // CD + assert property (@(posedge clk_i) (cd_valid && !cd_ready |=> $stable(cd_data))); + assert property (@(posedge clk_i) (cd_valid && !cd_ready |=> $stable(cd_last))); + assert property (@(posedge clk_i) (cd_valid && !cd_ready |=> cd_valid)); + `endif + // pragma translate_on + +endinterface