A SystemC productivity library for virtual platform development utilizing SCV and TLM2.0 https://www.minres.com/#opensource

router.h 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*******************************************************************************
  2. * Copyright 2016, 2018 MINRES Technologies GmbH
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *******************************************************************************/
  16. #ifndef _SYSC_ROUTER_H_
  17. #define _SYSC_ROUTER_H_
  18. #include "initiator_mixin.h"
  19. #include "scv4tlm/tlm_rec_initiator_socket.h"
  20. #include "scv4tlm/tlm_rec_target_socket.h"
  21. #include "target_mixin.h"
  22. #include "util/range_lut.h"
  23. #include "utilities.h"
  24. #include <limits>
  25. #include <sysc/utils/sc_vector.h>
  26. #include <tlm.h>
  27. #include <unordered_map>
  28. namespace scc {
  29. template <unsigned BUSWIDTH = 32> class router : sc_core::sc_module {
  30. public:
  31. using intor_sckt = scc::initiator_mixin<scv4tlm::tlm_rec_initiator_socket<BUSWIDTH>>;
  32. using target_sckt = scc::target_mixin<scv4tlm::tlm_rec_target_socket<BUSWIDTH>>;
  33. /**
  34. * the array of target sockets
  35. */
  36. sc_core::sc_vector<target_sckt> target;
  37. /**
  38. * the array of initiator sockets
  39. */
  40. sc_core::sc_vector<intor_sckt> initiator;
  41. /**
  42. * constructs a router
  43. *
  44. * @param nm
  45. * @param slave_cnt
  46. * @param master_cnt
  47. */
  48. router(const sc_core::sc_module_name &nm, unsigned slave_cnt = 1, unsigned master_cnt = 1);
  49. /**
  50. *
  51. */
  52. ~router() = default;
  53. /**
  54. * bind the initiator socket of the router to some target giving a base and size
  55. *
  56. * @param socket
  57. * @param idx
  58. * @param base
  59. * @param size
  60. * @param remap
  61. */
  62. template<typename TYPE>
  63. void bind_target(TYPE& socket, size_t idx, uint64_t base, uint64_t size, bool remap = true){
  64. set_target_range(idx, base, size, remap);
  65. initiator[idx].bind(socket);
  66. }
  67. /**
  68. * bind the initiator socket of the router to some target and name it
  69. *
  70. * @param socket
  71. * @param idx
  72. * @param name
  73. */
  74. template<typename TYPE>
  75. void bind_target(TYPE& socket, size_t idx, std::string name){
  76. set_target_name(idx, name);
  77. initiator[idx].bind(socket);
  78. }
  79. /**
  80. * define a base address of a socket. This will be added to the address of each access
  81. * coming thru this socket
  82. *
  83. * @param idx
  84. * @param base
  85. */
  86. void set_initiator_base(size_t idx, uint64_t base) { ibases[idx] = base; }
  87. /**
  88. * define the default target socket. If no target address range is hit the access is routed to this socket.
  89. * If this is not defined a address error response is generated
  90. *
  91. * @param idx
  92. */
  93. void set_default_target(size_t idx) { default_idx = idx; }
  94. /**
  95. * establish a mapping between socket name and socket index
  96. *
  97. * @param idx
  98. * @param name
  99. */
  100. void set_target_name(size_t idx, std::string name) { target_name_lut.insert(std::make_pair(name, idx)); }
  101. /**
  102. * establish a mapping between a named socket and a target address range
  103. *
  104. * @param idx
  105. * @param base
  106. * @param size
  107. * @param remap
  108. */
  109. void add_target_range(std::string name, uint64_t base, uint64_t size, bool remap = true);
  110. /**
  111. * establish a mapping between a socket and a target address range
  112. *
  113. * @param name
  114. * @param base
  115. * @param size
  116. * @param remap
  117. */
  118. void set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap = true);
  119. /**
  120. * tagged blocking transport method
  121. *
  122. * @param i
  123. * @param trans
  124. * @param delay
  125. */
  126. void b_transport(int i, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay);
  127. /**
  128. * tagged forward DMI method
  129. *
  130. * @param i
  131. * @param trans
  132. * @param dmi_data
  133. * @return
  134. */
  135. bool get_direct_mem_ptr(int i, tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data);
  136. /**
  137. * tagged debug transaction method
  138. *
  139. * @param i
  140. * @param trans
  141. */
  142. unsigned transport_dbg(int i, tlm::tlm_generic_payload &trans);
  143. /**
  144. * Tagged backward DMI method
  145. *
  146. * @param id
  147. * @param start_range
  148. * @param end_range
  149. */
  150. void invalidate_direct_mem_ptr(int id, sc_dt::uint64 start_range, sc_dt::uint64 end_range);
  151. protected:
  152. struct range_entry {
  153. uint64_t base, size;
  154. bool remap;
  155. };
  156. size_t default_idx = std::numeric_limits<size_t>::max();
  157. std::vector<uint64_t> ibases;
  158. std::vector<range_entry> tranges;
  159. std::vector<sc_core::sc_mutex> mutexes;
  160. util::range_lut<unsigned> addr_decoder;
  161. std::unordered_map<std::string, size_t> target_name_lut;
  162. };
  163. template <unsigned BUSWIDTH>
  164. router<BUSWIDTH>::router(const sc_core::sc_module_name &nm, unsigned slave_cnt, unsigned master_cnt)
  165. : sc_module(nm)
  166. , target("target", master_cnt)
  167. , initiator("intor", slave_cnt)
  168. , ibases(master_cnt)
  169. , tranges(slave_cnt)
  170. , mutexes(slave_cnt)
  171. , addr_decoder(std::numeric_limits<unsigned>::max()) {
  172. for (size_t i = 0; i < target.size(); ++i) {
  173. target[i].register_b_transport([=](tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) -> void {
  174. this->b_transport(i, trans, delay);
  175. });
  176. target[i].register_get_direct_mem_ptr([=](tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data) -> bool {
  177. return this->get_direct_mem_ptr(i, trans, dmi_data);
  178. });
  179. target[i].register_transport_dbg(
  180. [=](tlm::tlm_generic_payload &trans) -> unsigned { return this->transport_dbg(i, trans); });
  181. ibases[i] = 0ULL;
  182. }
  183. for (size_t i = 0; i < initiator.size(); ++i) {
  184. initiator[i].register_invalidate_direct_mem_ptr(
  185. [=](sc_dt::uint64 start_range, sc_dt::uint64 end_range) -> void {
  186. this->invalidate_direct_mem_ptr(i, start_range, end_range);
  187. });
  188. tranges[i].base = 0ULL;
  189. tranges[i].size = 0ULL;
  190. tranges[i].remap = false;
  191. }
  192. }
  193. template <unsigned BUSWIDTH>
  194. void router<BUSWIDTH>::set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap) {
  195. tranges[idx].base = base;
  196. tranges[idx].size = size;
  197. tranges[idx].remap = remap;
  198. addr_decoder.addEntry(idx, base, size);
  199. }
  200. template <unsigned BUSWIDTH>
  201. void router<BUSWIDTH>::add_target_range(std::string name, uint64_t base, uint64_t size, bool remap) {
  202. auto it = target_name_lut.find(name);
  203. #ifndef NDEBUG
  204. // sc_assert(it!=target_name_lut.end());
  205. if (it == target_name_lut.end()) {
  206. std::stringstream ss;
  207. ss << "No target index entry for '" << name << "' found ";
  208. ::sc_core::sc_assertion_failed(ss.str().c_str(), __FILE__, __LINE__);
  209. }
  210. #endif
  211. auto idx = it->second;
  212. tranges[idx].base = base;
  213. tranges[idx].size = size;
  214. tranges[idx].remap = remap;
  215. addr_decoder.addEntry(idx, base, size);
  216. }
  217. template <unsigned BUSWIDTH>
  218. void router<BUSWIDTH>::b_transport(int i, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) {
  219. sc_dt::uint64 address = trans.get_address();
  220. if (ibases[i]) {
  221. address += ibases[i];
  222. trans.set_address(address);
  223. }
  224. size_t idx = addr_decoder.getEntry(address);
  225. if (idx == addr_decoder.null_entry) {
  226. if (default_idx == std::numeric_limits<size_t>::max()) {
  227. trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
  228. return;
  229. }
  230. idx = default_idx;
  231. } else {
  232. // Modify address within transaction
  233. trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
  234. }
  235. // Forward transaction to appropriate target
  236. mutexes[idx].lock();
  237. initiator[idx]->b_transport(trans, delay);
  238. mutexes[idx].unlock();
  239. }
  240. template <unsigned BUSWIDTH>
  241. bool router<BUSWIDTH>::get_direct_mem_ptr(int i, tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data) {
  242. sc_dt::uint64 address = trans.get_address();
  243. if (ibases[i]) {
  244. address += ibases[i];
  245. trans.set_address(address);
  246. }
  247. size_t idx = addr_decoder.getEntry(address);
  248. if (idx == addr_decoder.null_entry) {
  249. if (default_idx == std::numeric_limits<size_t>::max()) {
  250. trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
  251. return false;
  252. }
  253. idx = default_idx;
  254. } else {
  255. // Modify address within transaction
  256. trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
  257. }
  258. bool status = initiator[idx]->get_direct_mem_ptr(trans, dmi_data);
  259. // Calculate DMI address of target in system address space
  260. auto offset = tranges[idx].remap ? tranges[idx].base : 0;
  261. dmi_data.set_start_address(dmi_data.get_start_address() - ibases[i] + offset);
  262. dmi_data.set_end_address(dmi_data.get_end_address() - ibases[i] + offset);
  263. return status;
  264. }
  265. template <unsigned BUSWIDTH> unsigned router<BUSWIDTH>::transport_dbg(int i, tlm::tlm_generic_payload &trans) {
  266. sc_dt::uint64 address = trans.get_address();
  267. if (ibases[i]) {
  268. address += ibases[i];
  269. trans.set_address(address);
  270. }
  271. size_t idx = addr_decoder.getEntry(address);
  272. if (idx == addr_decoder.null_entry) {
  273. if (default_idx == std::numeric_limits<size_t>::max()) {
  274. trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
  275. return 0;
  276. }
  277. idx = default_idx;
  278. } else {
  279. // Modify address within transaction
  280. trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
  281. }
  282. // Forward debug transaction to appropriate target
  283. return initiator[idx]->transport_dbg(trans);
  284. }
  285. template <unsigned BUSWIDTH>
  286. void router<BUSWIDTH>::invalidate_direct_mem_ptr(int id, sc_dt::uint64 start_range, sc_dt::uint64 end_range) {
  287. // Reconstruct address range in system memory map
  288. sc_dt::uint64 bw_start_range = start_range;
  289. if (tranges[id].remap) bw_start_range += tranges[id].base;
  290. sc_dt::uint64 bw_end_range = end_range;
  291. if (tranges[id].remap) bw_end_range += tranges[id].base;
  292. for (size_t i = 0; i < target.size(); ++i) {
  293. target[i]->invalidate_direct_mem_ptr(bw_start_range - ibases[i], bw_end_range - ibases[i]);
  294. }
  295. }
  296. } // namespace scc
  297. #endif /* SYSC_AVR_ROUTER_H_ */