diff --git a/CHANGELOG.md b/CHANGELOG.md index 088053d96..06a29467c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Add infinite, simulation-only memory `axi_sim_mem`. +- `assign.svh`: Add macros for assigning between `struct`s, both inside a process + (`AXI_SET_*_STRUCT`) and outside a process (`AXI_ASSIGN_*_STRUCT`). This is safer than assigning + `struct`s with a simple `=`, because the macros assign individual fields. (Fields that mismatch + between two `struct`s, e.g., due to different `user` signal widths, should, and in some cases + must, be still assigned separately.) ### Changed - Rename the following classes in `axi_test` to follow the convention that all user-facing objects diff --git a/include/axi/assign.svh b/include/axi/assign.svh index 13d2a2020..bec27709b 100644 --- a/include/axi/assign.svh +++ b/include/axi/assign.svh @@ -17,6 +17,71 @@ `ifndef AXI_ASSIGN_SVH_ `define AXI_ASSIGN_SVH_ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Internal implementation for assigning one AXI 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 __AXI_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; +`define __AXI_TO_W(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``data = __rhs``__rhs_sep``data; \ + __opt_as __lhs``__lhs_sep``strb = __rhs``__rhs_sep``strb; \ + __opt_as __lhs``__lhs_sep``last = __rhs``__rhs_sep``last; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; +`define __AXI_TO_B(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + __opt_as __lhs``__lhs_sep``id = __rhs``__rhs_sep``id; \ + __opt_as __lhs``__lhs_sep``resp = __rhs``__rhs_sep``resp; \ + __opt_as __lhs``__lhs_sep``user = __rhs``__rhs_sep``user; +`define __AXI_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; +`define __AXI_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 __AXI_TO_REQ(__opt_as, __lhs, __lhs_sep, __rhs, __rhs_sep) \ + `__AXI_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; \ + `__AXI_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; +`define __AXI_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; \ + `__AXI_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;` // @@ -30,55 +95,25 @@ // `AXI_ASSIGN(slv, mst) // `AXI_ASSIGN_AW(dst, src) // `AXI_ASSIGN_R(dst, src) -`define AXI_ASSIGN_AW(dst, src) \ - assign dst.aw_id = src.aw_id; \ - assign dst.aw_addr = src.aw_addr; \ - assign dst.aw_len = src.aw_len; \ - assign dst.aw_size = src.aw_size; \ - assign dst.aw_burst = src.aw_burst; \ - assign dst.aw_lock = src.aw_lock; \ - assign dst.aw_cache = src.aw_cache; \ - assign dst.aw_prot = src.aw_prot; \ - assign dst.aw_qos = src.aw_qos; \ - assign dst.aw_region = src.aw_region; \ - assign dst.aw_atop = src.aw_atop; \ - assign dst.aw_user = src.aw_user; \ - assign dst.aw_valid = src.aw_valid; \ - assign src.aw_ready = dst.aw_ready; -`define AXI_ASSIGN_W(dst, src) \ - assign dst.w_data = src.w_data; \ - assign dst.w_strb = src.w_strb; \ - assign dst.w_last = src.w_last; \ - assign dst.w_user = src.w_user; \ - assign dst.w_valid = src.w_valid; \ +`define AXI_ASSIGN_AW(dst, src) \ + `__AXI_TO_AW(assign, dst.aw, _, src.aw, _) \ + assign dst.aw_valid = src.aw_valid; \ + assign src.aw_ready = dst.aw_ready; +`define AXI_ASSIGN_W(dst, src) \ + `__AXI_TO_W(assign, dst.w, _, src.w, _) \ + assign dst.w_valid = src.w_valid; \ assign src.w_ready = dst.w_ready; -`define AXI_ASSIGN_B(dst, src) \ - assign dst.b_id = src.b_id; \ - assign dst.b_resp = src.b_resp; \ - assign dst.b_user = src.b_user; \ - assign dst.b_valid = src.b_valid; \ +`define AXI_ASSIGN_B(dst, src) \ + `__AXI_TO_B(assign, dst.b, _, src.b, _) \ + assign dst.b_valid = src.b_valid; \ assign src.b_ready = dst.b_ready; -`define AXI_ASSIGN_AR(dst, src) \ - assign dst.ar_id = src.ar_id; \ - assign dst.ar_addr = src.ar_addr; \ - assign dst.ar_len = src.ar_len; \ - assign dst.ar_size = src.ar_size; \ - assign dst.ar_burst = src.ar_burst; \ - assign dst.ar_lock = src.ar_lock; \ - assign dst.ar_cache = src.ar_cache; \ - assign dst.ar_prot = src.ar_prot; \ - assign dst.ar_qos = src.ar_qos; \ - assign dst.ar_region = src.ar_region; \ - assign dst.ar_user = src.ar_user; \ - assign dst.ar_valid = src.ar_valid; \ - assign src.ar_ready = dst.ar_ready; -`define AXI_ASSIGN_R(dst, src) \ - assign dst.r_id = src.r_id; \ - assign dst.r_data = src.r_data; \ - assign dst.r_resp = src.r_resp; \ - assign dst.r_last = src.r_last; \ - assign dst.r_user = src.r_user; \ - assign dst.r_valid = src.r_valid; \ +`define AXI_ASSIGN_AR(dst, src) \ + `__AXI_TO_AR(assign, dst.ar, _, src.ar, _) \ + assign dst.ar_valid = src.ar_valid; \ + assign src.ar_ready = dst.ar_ready; +`define AXI_ASSIGN_R(dst, src) \ + `__AXI_TO_R(assign, dst.r, _, src.r, _) \ + assign dst.r_valid = src.r_valid; \ assign src.r_ready = dst.r_ready; `define AXI_ASSIGN(slv, mst) \ `AXI_ASSIGN_AW(slv, mst) \ @@ -97,119 +132,25 @@ // // Usage Example: // `AXI_ASSIGN_MONITOR(mon_dv, axi_if) -`define AXI_ASSIGN_MONITOR(mon_dv, axi_if) \ - assign mon_dv.aw_id = axi_if.aw_id; \ - assign mon_dv.aw_addr = axi_if.aw_addr; \ - assign mon_dv.aw_len = axi_if.aw_len; \ - assign mon_dv.aw_size = axi_if.aw_size; \ - assign mon_dv.aw_burst = axi_if.aw_burst; \ - assign mon_dv.aw_lock = axi_if.aw_lock; \ - assign mon_dv.aw_cache = axi_if.aw_cache; \ - assign mon_dv.aw_prot = axi_if.aw_prot; \ - assign mon_dv.aw_qos = axi_if.aw_qos; \ - assign mon_dv.aw_region = axi_if.aw_region; \ - assign mon_dv.aw_atop = axi_if.aw_atop; \ - assign mon_dv.aw_user = axi_if.aw_user; \ - assign mon_dv.aw_valid = axi_if.aw_valid; \ - assign mon_dv.aw_ready = axi_if.aw_ready; \ - assign mon_dv.w_data = axi_if.w_data; \ - assign mon_dv.w_strb = axi_if.w_strb; \ - assign mon_dv.w_last = axi_if.w_last; \ - assign mon_dv.w_user = axi_if.w_user; \ - assign mon_dv.w_valid = axi_if.w_valid; \ - assign mon_dv.w_ready = axi_if.w_ready; \ - assign mon_dv.b_id = axi_if.b_id; \ - assign mon_dv.b_resp = axi_if.b_resp; \ - assign mon_dv.b_user = axi_if.b_user; \ - assign mon_dv.b_valid = axi_if.b_valid; \ - assign mon_dv.b_ready = axi_if.b_ready; \ - assign mon_dv.ar_id = axi_if.ar_id; \ - assign mon_dv.ar_addr = axi_if.ar_addr; \ - assign mon_dv.ar_len = axi_if.ar_len; \ - assign mon_dv.ar_size = axi_if.ar_size; \ - assign mon_dv.ar_burst = axi_if.ar_burst; \ - assign mon_dv.ar_lock = axi_if.ar_lock; \ - assign mon_dv.ar_cache = axi_if.ar_cache; \ - assign mon_dv.ar_prot = axi_if.ar_prot; \ - assign mon_dv.ar_qos = axi_if.ar_qos; \ - assign mon_dv.ar_region = axi_if.ar_region; \ - assign mon_dv.ar_user = axi_if.ar_user; \ - assign mon_dv.ar_valid = axi_if.ar_valid; \ - assign mon_dv.ar_ready = axi_if.ar_ready; \ - assign mon_dv.r_id = axi_if.r_id; \ - assign mon_dv.r_data = axi_if.r_data; \ - assign mon_dv.r_resp = axi_if.r_resp; \ - assign mon_dv.r_last = axi_if.r_last; \ - assign mon_dv.r_user = axi_if.r_user; \ - assign mon_dv.r_valid = axi_if.r_valid; \ +`define AXI_ASSIGN_MONITOR(mon_dv, axi_if) \ + `__AXI_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; \ + `__AXI_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; \ + `__AXI_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; //////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Internal implementation for assigning interfaces from structs, allows for standalone assignments -// (with `opt_as = assign`) and assignments inside processes (with `opt_as` void) with the same -// code. -`define AXI_FROM_AW(opt_as, axi_if, aw_struct) \ - opt_as axi_if.aw_id = aw_struct.id; \ - opt_as axi_if.aw_addr = aw_struct.addr; \ - opt_as axi_if.aw_len = aw_struct.len; \ - opt_as axi_if.aw_size = aw_struct.size; \ - opt_as axi_if.aw_burst = aw_struct.burst; \ - opt_as axi_if.aw_lock = aw_struct.lock; \ - opt_as axi_if.aw_cache = aw_struct.cache; \ - opt_as axi_if.aw_prot = aw_struct.prot; \ - opt_as axi_if.aw_qos = aw_struct.qos; \ - opt_as axi_if.aw_region = aw_struct.region; \ - opt_as axi_if.aw_atop = aw_struct.atop; \ - opt_as axi_if.aw_user = aw_struct.user; -`define AXI_FROM_W(opt_as, axi_if, w_struct) \ - opt_as axi_if.w_data = w_struct.data; \ - opt_as axi_if.w_strb = w_struct.strb; \ - opt_as axi_if.w_last = w_struct.last; \ - opt_as axi_if.w_user = w_struct.user; -`define AXI_FROM_B(opt_as, axi_if, b_struct) \ - opt_as axi_if.b_id = b_struct.id; \ - opt_as axi_if.b_resp = b_struct.resp; \ - opt_as axi_if.b_user = b_struct.user; -`define AXI_FROM_AR(opt_as, axi_if, ar_struct) \ - opt_as axi_if.ar_id = ar_struct.id; \ - opt_as axi_if.ar_addr = ar_struct.addr; \ - opt_as axi_if.ar_len = ar_struct.len; \ - opt_as axi_if.ar_size = ar_struct.size; \ - opt_as axi_if.ar_burst = ar_struct.burst; \ - opt_as axi_if.ar_lock = ar_struct.lock; \ - opt_as axi_if.ar_cache = ar_struct.cache; \ - opt_as axi_if.ar_prot = ar_struct.prot; \ - opt_as axi_if.ar_qos = ar_struct.qos; \ - opt_as axi_if.ar_region = ar_struct.region; \ - opt_as axi_if.ar_user = ar_struct.user; -`define AXI_FROM_R(opt_as, axi_if, r_struct) \ - opt_as axi_if.r_id = r_struct.id; \ - opt_as axi_if.r_data = r_struct.data; \ - opt_as axi_if.r_resp = r_struct.resp; \ - opt_as axi_if.r_last = r_struct.last; \ - opt_as axi_if.r_user = r_struct.user; -`define AXI_FROM_REQ(opt_as, axi_if, req_struct) \ - `AXI_FROM_AW(opt_as, axi_if, req_struct.aw) \ - opt_as axi_if.aw_valid = req_struct.aw_valid; \ - `AXI_FROM_W(opt_as, axi_if, req_struct.w) \ - opt_as axi_if.w_valid = req_struct.w_valid; \ - opt_as axi_if.b_ready = req_struct.b_ready; \ - `AXI_FROM_AR(opt_as, axi_if, req_struct.ar) \ - opt_as axi_if.ar_valid = req_struct.ar_valid; \ - opt_as axi_if.r_ready = req_struct.r_ready; -`define AXI_FROM_RESP(opt_as, axi_if, resp_struct) \ - opt_as axi_if.aw_ready = resp_struct.aw_ready; \ - opt_as axi_if.ar_ready = resp_struct.ar_ready; \ - opt_as axi_if.w_ready = resp_struct.w_ready; \ - opt_as axi_if.b_valid = resp_struct.b_valid; \ - `AXI_FROM_B(opt_as, axi_if, resp_struct.b) \ - opt_as axi_if.r_valid = resp_struct.r_valid; \ - `AXI_FROM_R(opt_as, axi_if, resp_struct.r) -//////////////////////////////////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////////////////////////////////// // Setting an interface from channel or request/response structs inside a process. // @@ -226,13 +167,13 @@ // always_comb begin // `AXI_SET_FROM_REQ(my_if, my_req_struct) // end -`define AXI_SET_FROM_AW(axi_if, aw_struct) `AXI_FROM_AW(, axi_if, aw_struct) -`define AXI_SET_FROM_W(axi_if, w_struct) `AXI_FROM_W(, axi_if, w_struct) -`define AXI_SET_FROM_B(axi_if, b_struct) `AXI_FROM_B(, axi_if, b_struct) -`define AXI_SET_FROM_AR(axi_if, ar_struct) `AXI_FROM_AR(, axi_if, ar_struct) -`define AXI_SET_FROM_R(axi_if, r_struct) `AXI_FROM_R(, axi_if, r_struct) -`define AXI_SET_FROM_REQ(axi_if, req_struct) `AXI_FROM_REQ(, axi_if, req_struct) -`define AXI_SET_FROM_RESP(axi_if, resp_struct) `AXI_FROM_RESP(, axi_if, resp_struct) +`define AXI_SET_FROM_AW(axi_if, aw_struct) `__AXI_TO_AW(, axi_if.aw, _, aw_struct, .) +`define AXI_SET_FROM_W(axi_if, w_struct) `__AXI_TO_W(, axi_if.w, _, w_struct, .) +`define AXI_SET_FROM_B(axi_if, b_struct) `__AXI_TO_B(, axi_if.b, _, b_struct, .) +`define AXI_SET_FROM_AR(axi_if, ar_struct) `__AXI_TO_AR(, axi_if.ar, _, ar_struct, .) +`define AXI_SET_FROM_R(axi_if, r_struct) `__AXI_TO_R(, axi_if.r, _, r_struct, .) +`define AXI_SET_FROM_REQ(axi_if, req_struct) `__AXI_TO_REQ(, axi_if, _, req_struct, .) +`define AXI_SET_FROM_RESP(axi_if, resp_struct) `__AXI_TO_RESP(, axi_if, _, resp_struct, .) //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -250,87 +191,13 @@ // // Usage Example: // `AXI_ASSIGN_FROM_REQ(my_if, my_req_struct) -`define AXI_ASSIGN_FROM_AW(axi_if, aw_struct) `AXI_FROM_AW(assign, axi_if, aw_struct) -`define AXI_ASSIGN_FROM_W(axi_if, w_struct) `AXI_FROM_W(assign, axi_if, w_struct) -`define AXI_ASSIGN_FROM_B(axi_if, b_struct) `AXI_FROM_B(assign, axi_if, b_struct) -`define AXI_ASSIGN_FROM_AR(axi_if, ar_struct) `AXI_FROM_AR(assign, axi_if, ar_struct) -`define AXI_ASSIGN_FROM_R(axi_if, r_struct) `AXI_FROM_R(assign, axi_if, r_struct) -`define AXI_ASSIGN_FROM_REQ(axi_if, req_struct) `AXI_FROM_REQ(assign, axi_if, req_struct) -`define AXI_ASSIGN_FROM_RESP(axi_if, resp_struct) `AXI_FROM_RESP(assign, axi_if, resp_struct) -//////////////////////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Internal implementation for assigning to structs from interfaces, allows for standalone -// assignments (with `opt_as = assign`) and assignments inside processes (with `opt_as` void) with -// the same code. -`define AXI_TO_AW(opt_as, aw_struct, axi_if) \ - opt_as aw_struct = '{ \ - id: axi_if.aw_id, \ - addr: axi_if.aw_addr, \ - len: axi_if.aw_len, \ - size: axi_if.aw_size, \ - burst: axi_if.aw_burst, \ - lock: axi_if.aw_lock, \ - cache: axi_if.aw_cache, \ - prot: axi_if.aw_prot, \ - qos: axi_if.aw_qos, \ - region: axi_if.aw_region, \ - atop: axi_if.aw_atop, \ - user: axi_if.aw_user \ - }; -`define AXI_TO_W(opt_as, w_struct, axi_if) \ - opt_as w_struct = '{ \ - data: axi_if.w_data, \ - strb: axi_if.w_strb, \ - last: axi_if.w_last, \ - user: axi_if.w_user \ - }; -`define AXI_TO_B(opt_as, b_struct, axi_if) \ - opt_as b_struct = '{ \ - id: axi_if.b_id, \ - resp: axi_if.b_resp, \ - user: axi_if.b_user \ - }; -`define AXI_TO_AR(opt_as, ar_struct, axi_if) \ - opt_as ar_struct = '{ \ - id: axi_if.ar_id, \ - addr: axi_if.ar_addr, \ - len: axi_if.ar_len, \ - size: axi_if.ar_size, \ - burst: axi_if.ar_burst, \ - lock: axi_if.ar_lock, \ - cache: axi_if.ar_cache, \ - prot: axi_if.ar_prot, \ - qos: axi_if.ar_qos, \ - region: axi_if.ar_region, \ - user: axi_if.ar_user \ - }; -`define AXI_TO_R(opt_as, r_struct, axi_if) \ - opt_as r_struct = '{ \ - id: axi_if.r_id, \ - data: axi_if.r_data, \ - resp: axi_if.r_resp, \ - last: axi_if.r_last, \ - user: axi_if.r_user \ - }; -`define AXI_TO_REQ(opt_as, req_struct, axi_if) \ - `AXI_TO_AW(opt_as, req_struct.aw, axi_if) \ - opt_as req_struct.aw_valid = axi_if.aw_valid; \ - `AXI_TO_W(opt_as, req_struct.w, axi_if) \ - opt_as req_struct.w_valid = axi_if.w_valid; \ - opt_as req_struct.b_ready = axi_if.b_ready; \ - `AXI_TO_AR(opt_as, req_struct.ar, axi_if) \ - opt_as req_struct.ar_valid = axi_if.ar_valid; \ - opt_as req_struct.r_ready = axi_if.r_ready; -`define AXI_TO_RESP(opt_as, resp_struct, axi_if) \ - opt_as resp_struct.aw_ready = axi_if.aw_ready; \ - opt_as resp_struct.ar_ready = axi_if.ar_ready; \ - opt_as resp_struct.w_ready = axi_if.w_ready; \ - opt_as resp_struct.b_valid = axi_if.b_valid; \ - `AXI_TO_B(opt_as, resp_struct.b, axi_if) \ - opt_as resp_struct.r_valid = axi_if.r_valid; \ - `AXI_TO_R(opt_as, resp_struct.r, axi_if) +`define AXI_ASSIGN_FROM_AW(axi_if, aw_struct) `__AXI_TO_AW(assign, axi_if.aw, _, aw_struct, .) +`define AXI_ASSIGN_FROM_W(axi_if, w_struct) `__AXI_TO_W(assign, axi_if.w, _, w_struct, .) +`define AXI_ASSIGN_FROM_B(axi_if, b_struct) `__AXI_TO_B(assign, axi_if.b, _, b_struct, .) +`define AXI_ASSIGN_FROM_AR(axi_if, ar_struct) `__AXI_TO_AR(assign, axi_if.ar, _, ar_struct, .) +`define AXI_ASSIGN_FROM_R(axi_if, r_struct) `__AXI_TO_R(assign, axi_if.r, _, r_struct, .) +`define AXI_ASSIGN_FROM_REQ(axi_if, req_struct) `__AXI_TO_REQ(assign, axi_if, _, req_struct, .) +`define AXI_ASSIGN_FROM_RESP(axi_if, resp_struct) `__AXI_TO_RESP(assign, axi_if, _, resp_struct, .) //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -351,13 +218,13 @@ // always_comb begin // `AXI_SET_TO_REQ(my_req_struct, my_if) // end -`define AXI_SET_TO_AW(aw_struct, axi_if) `AXI_TO_AW(, aw_struct, axi_if) -`define AXI_SET_TO_W(w_struct, axi_if) `AXI_TO_W(, w_struct, axi_if) -`define AXI_SET_TO_B(b_struct, axi_if) `AXI_TO_B(, b_struct, axi_if) -`define AXI_SET_TO_AR(ar_struct, axi_if) `AXI_TO_AR(, ar_struct, axi_if) -`define AXI_SET_TO_R(r_struct, axi_if) `AXI_TO_R(, r_struct, axi_if) -`define AXI_SET_TO_REQ(req_struct, axi_if) `AXI_TO_REQ(, req_struct, axi_if) -`define AXI_SET_TO_RESP(resp_struct, axi_if) `AXI_TO_RESP(, resp_struct, axi_if) +`define AXI_SET_TO_AW(aw_struct, axi_if) `__AXI_TO_AW(, aw_struct, ., axi_if.aw, _) +`define AXI_SET_TO_W(w_struct, axi_if) `__AXI_TO_W(, w_struct, ., axi_if.w, _) +`define AXI_SET_TO_B(b_struct, axi_if) `__AXI_TO_B(, b_struct, ., axi_if.b, _) +`define AXI_SET_TO_AR(ar_struct, axi_if) `__AXI_TO_AR(, ar_struct, ., axi_if.ar, _) +`define AXI_SET_TO_R(r_struct, axi_if) `__AXI_TO_R(, r_struct, ., axi_if.r, _) +`define AXI_SET_TO_REQ(req_struct, axi_if) `__AXI_TO_REQ(, req_struct, ., axi_if, _) +`define AXI_SET_TO_RESP(resp_struct, axi_if) `__AXI_TO_RESP(, resp_struct, ., axi_if, _) //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -376,13 +243,65 @@ // // Usage Example: // `AXI_ASSIGN_TO_REQ(my_req_struct, my_if) -`define AXI_ASSIGN_TO_AW(aw_struct, axi_if) `AXI_TO_AW(assign, aw_struct, axi_if) -`define AXI_ASSIGN_TO_W(w_struct, axi_if) `AXI_TO_W(assign, w_struct, axi_if) -`define AXI_ASSIGN_TO_B(b_struct, axi_if) `AXI_TO_B(assign, b_struct, axi_if) -`define AXI_ASSIGN_TO_AR(ar_struct, axi_if) `AXI_TO_AR(assign, ar_struct, axi_if) -`define AXI_ASSIGN_TO_R(r_struct, axi_if) `AXI_TO_R(assign, r_struct, axi_if) -`define AXI_ASSIGN_TO_REQ(req_struct, axi_if) `AXI_TO_REQ(assign, req_struct, axi_if) -`define AXI_ASSIGN_TO_RESP(resp_struct, axi_if) `AXI_TO_RESP(assign, resp_struct, axi_if) +`define AXI_ASSIGN_TO_AW(aw_struct, axi_if) `__AXI_TO_AW(assign, aw_struct, ., axi_if.aw, _) +`define AXI_ASSIGN_TO_W(w_struct, axi_if) `__AXI_TO_W(assign, w_struct, ., axi_if.w, _) +`define AXI_ASSIGN_TO_B(b_struct, axi_if) `__AXI_TO_B(assign, b_struct, ., axi_if.b, _) +`define AXI_ASSIGN_TO_AR(ar_struct, axi_if) `__AXI_TO_AR(assign, ar_struct, ., axi_if.ar, _) +`define AXI_ASSIGN_TO_R(r_struct, axi_if) `__AXI_TO_R(assign, r_struct, ., axi_if.r, _) +`define AXI_ASSIGN_TO_REQ(req_struct, axi_if) `__AXI_TO_REQ(assign, req_struct, ., axi_if, _) +`define AXI_ASSIGN_TO_RESP(resp_struct, axi_if) `__AXI_TO_RESP(assign, resp_struct, ., axi_if, _) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Setting channel or request/response structs from another struct inside a process. +// +// The channel macros `AXI_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 `AXI_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 `AXI_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_REQ_STRUCT(my_req_struct, another_req_struct) +// end +`define AXI_SET_AW_STRUCT(lhs, rhs) `__AXI_TO_AW(, lhs, ., rhs, .) +`define AXI_SET_W_STRUCT(lhs, rhs) `__AXI_TO_W(, lhs, ., rhs, .) +`define AXI_SET_B_STRUCT(lhs, rhs) `__AXI_TO_B(, lhs, ., rhs, .) +`define AXI_SET_AR_STRUCT(lhs, rhs) `__AXI_TO_AR(, lhs, ., rhs, .) +`define AXI_SET_R_STRUCT(lhs, rhs) `__AXI_TO_R(, lhs, ., rhs, .) +`define AXI_SET_REQ_STRUCT(lhs, rhs) `__AXI_TO_REQ(, lhs, ., rhs, .) +`define AXI_SET_RESP_STRUCT(lhs, rhs) `__AXI_TO_RESP(, lhs, ., rhs, .) +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Assigning channel or request/response structs from another struct outside a process. +// +// The channel macros `AXI_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 `AXI_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 `AXI_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: +// `AXI_ASSIGN_REQ_STRUCT(my_req_struct, another_req_struct) +`define AXI_ASSIGN_AW_STRUCT(lhs, rhs) `__AXI_TO_AW(assign, lhs, ., rhs, .) +`define AXI_ASSIGN_W_STRUCT(lhs, rhs) `__AXI_TO_W(assign, lhs, ., rhs, .) +`define AXI_ASSIGN_B_STRUCT(lhs, rhs) `__AXI_TO_B(assign, lhs, ., rhs, .) +`define AXI_ASSIGN_AR_STRUCT(lhs, rhs) `__AXI_TO_AR(assign, lhs, ., rhs, .) +`define AXI_ASSIGN_R_STRUCT(lhs, rhs) `__AXI_TO_R(assign, lhs, ., rhs, .) +`define AXI_ASSIGN_REQ_STRUCT(lhs, rhs) `__AXI_TO_REQ(assign, lhs, ., rhs, .) +`define AXI_ASSIGN_RESP_STRUCT(lhs, rhs) `__AXI_TO_RESP(assign, lhs, ., rhs, .) //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/tb_axi_serializer.sv b/test/tb_axi_serializer.sv index a06ff54e6..ea2908a51 100644 --- a/test/tb_axi_serializer.sv +++ b/test/tb_axi_serializer.sv @@ -181,7 +181,7 @@ module tb_axi_serializer #( #TestTime; // All FIFOs get populated if there is something to put in if (master.aw_valid && master.aw_ready) begin - `AXI_TO_AW(, aw_exp, master) + `AXI_SET_TO_AW(aw_exp, master) aw_exp.id = '0; id_exp = master.aw_id; aw_chan.push_back(aw_exp); @@ -191,24 +191,24 @@ module tb_axi_serializer #( end end if (master.w_valid && master.w_ready) begin - `AXI_TO_W(, w_exp, master) + `AXI_SET_TO_W(w_exp, master) w_chan.push_back(w_exp); end if (slave.b_valid && slave.b_ready) begin id_exp = aw_queue.pop_front(); - `AXI_TO_B(, b_exp, slave) + `AXI_SET_TO_B(b_exp, slave) b_exp.id = id_exp; b_chan.push_back(b_exp); end if (master.ar_valid && master.ar_ready) begin - `AXI_TO_AR(, ar_exp, master) + `AXI_SET_TO_AR(ar_exp, master) ar_exp.id = '0; id_exp = master.ar_id; ar_chan.push_back(ar_exp); ar_queue.push_back(id_exp); end if (slave.r_valid && slave.r_ready) begin - `AXI_TO_R(, r_exp, slave) + `AXI_SET_TO_R(r_exp, slave) if (slave.r_last) begin id_exp = ar_queue.pop_front(); end else begin @@ -220,27 +220,27 @@ module tb_axi_serializer #( // Check that all channels match the expected response if (slave.aw_valid && slave.aw_ready) begin aw_exp = aw_chan.pop_front(); - `AXI_TO_AW(, aw_act, slave) + `AXI_SET_TO_AW(aw_act, slave) assert(aw_act == aw_exp) else $error("AW Measured: %h Expected: %h", aw_act, aw_exp); end if (slave.w_valid && slave.w_ready) begin w_exp = w_chan.pop_front(); - `AXI_TO_W(, w_act, slave) + `AXI_SET_TO_W(w_act, slave) assert(w_act == w_exp) else $error("W Measured: %h Expected: %h", w_act, w_exp); end if (master.b_valid && master.b_ready) begin b_exp = b_chan.pop_front(); - `AXI_TO_B(, b_act, master) + `AXI_SET_TO_B(b_act, master) assert(b_act == b_exp) else $error("B Measured: %h Expected: %h", b_act, b_exp); end if (slave.ar_valid && slave.ar_ready) begin ar_exp = ar_chan.pop_front(); - `AXI_TO_AR(, ar_act, slave) + `AXI_SET_TO_AR(ar_act, slave) assert(ar_act == ar_exp) else $error("AR Measured: %h Expected: %h", ar_act, ar_exp); end if (master.r_valid && master.r_ready) begin r_exp = r_chan.pop_front(); - `AXI_TO_R(, r_act, master) + `AXI_SET_TO_R(r_act, master) assert(r_act == r_exp) else $error("R Measured: %h Expected: %h", r_act, r_exp); end end