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

memory.h 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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_MEMORY_H_
  17. #define _SYSC_MEMORY_H_
  18. // Needed for the simple_target_socket
  19. #define SC_INCLUDE_DYNAMIC_PROCESSES
  20. #include "report.h"
  21. #include "target_mixin.h"
  22. #include "utilities.h"
  23. #include <tlm.h>
  24. #include <util/sparse_array.h>
  25. namespace scc {
  26. /**
  27. * simple memory model
  28. *
  29. * TODO: add some more attributes/parameters to configure access time and type (DMI allowed, read only, etc)
  30. */
  31. template <unsigned long long SIZE, unsigned BUSWIDTH = 32, bool LOG_ACCESS = false>
  32. class memory : public sc_core::sc_module {
  33. public:
  34. //! the target socket to connect to TLM
  35. scc::target_mixin<tlm::tlm_target_socket<BUSWIDTH>> target;
  36. /**
  37. * constructor with explicit instance name
  38. *
  39. * @param nm
  40. */
  41. memory(const sc_core::sc_module_name &nm);
  42. protected:
  43. //! the real memory structure
  44. util::sparse_array<uint8_t, SIZE> mem;
  45. private:
  46. //!! handle the memory operation independent on interface function used
  47. int handle_operation(tlm::tlm_generic_payload &trans);
  48. //! handle the dmi functionality
  49. bool handle_dmi(tlm::tlm_generic_payload &gp, tlm::tlm_dmi &dmi_data);
  50. };
  51. template <unsigned long long SIZE, unsigned BUSWIDTH, bool LOG_ACCESS>
  52. memory<SIZE, BUSWIDTH, LOG_ACCESS>::memory(const sc_core::sc_module_name &nm)
  53. : sc_module(nm)
  54. , NAMED(target) {
  55. // Register callback for incoming b_transport interface method call
  56. target.register_b_transport([=](tlm::tlm_generic_payload &gp, sc_core::sc_time &delay) -> void {
  57. auto count = this->handle_operation(gp);
  58. });
  59. target.register_transport_dbg(
  60. [this](tlm::tlm_generic_payload &gp) -> unsigned { return this->handle_operation(gp); });
  61. target.register_get_direct_mem_ptr([this](tlm::tlm_generic_payload &gp, tlm::tlm_dmi &dmi_data) -> bool {
  62. return this->handle_dmi(gp, dmi_data);
  63. });
  64. }
  65. template <unsigned long long SIZE, unsigned BUSWIDTH, bool LOG_ACCESS>
  66. int memory<SIZE, BUSWIDTH, LOG_ACCESS>::handle_operation(tlm::tlm_generic_payload &trans) {
  67. sc_dt::uint64 adr = trans.get_address();
  68. uint8_t *ptr = trans.get_data_ptr();
  69. unsigned len = trans.get_data_length();
  70. uint8_t *byt = trans.get_byte_enable_ptr();
  71. unsigned wid = trans.get_streaming_width();
  72. // check address range and check for unsupported features,
  73. // i.e. byte enables, streaming, and bursts
  74. // Can ignore DMI hint and extensions
  75. if (adr + len > sc_dt::uint64(SIZE)) {
  76. SC_REPORT_ERROR("TLM-2", "generic payload transaction exceeeds memory size");
  77. trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
  78. return 0;
  79. }
  80. if (adr + len > sc_dt::uint64(SIZE) || byt != 0 || wid < len) {
  81. SC_REPORT_ERROR("TLM-2", "generic payload transaction not supported");
  82. trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
  83. return 0;
  84. }
  85. tlm::tlm_command cmd = trans.get_command();
  86. if (LOG_ACCESS) {
  87. if (adr >= 0x20 && adr < 0x60)
  88. LOG(WARNING) << (cmd == tlm::TLM_READ_COMMAND ? "read" : "write") << " access to addr 0x" << std::hex
  89. << adr - 0x20 << "(0x" << (adr) << ")" << std::dec;
  90. else
  91. LOG(WARNING) << (cmd == tlm::TLM_READ_COMMAND ? "read" : "write") << " access to addr 0x" << std::hex << adr
  92. << std::dec;
  93. }
  94. if (cmd == tlm::TLM_READ_COMMAND) {
  95. if (mem.is_allocated(adr)) {
  96. const auto &p = mem(adr / mem.page_size);
  97. auto offs = adr & mem.page_addr_mask;
  98. std::copy(p.data() + offs, p.data() + offs + len, ptr);
  99. } else {
  100. // no allocated page so return randomized data
  101. for (size_t i = 0; i < len; i++) ptr[i] = rand() % 256;
  102. }
  103. } else if (cmd == tlm::TLM_WRITE_COMMAND) {
  104. auto &p = mem(adr / mem.page_size);
  105. auto offs = adr & mem.page_addr_mask;
  106. std::copy(ptr, ptr + len, p.data() + offs);
  107. }
  108. trans.set_response_status(tlm::TLM_OK_RESPONSE);
  109. trans.set_dmi_allowed(true);
  110. return len;
  111. }
  112. template <unsigned long long SIZE, unsigned BUSWIDTH, bool LOG_ACCESS>
  113. inline bool memory<SIZE, BUSWIDTH, LOG_ACCESS>::handle_dmi(tlm::tlm_generic_payload &gp, tlm::tlm_dmi &dmi_data) {
  114. auto &p = mem(gp.get_address() / mem.page_size);
  115. dmi_data.set_start_address(gp.get_address() & ~mem.page_addr_mask);
  116. // TODO: fix to provide the correct end address
  117. dmi_data.set_end_address(dmi_data.get_start_address() + mem.page_size - 1);
  118. dmi_data.set_dmi_ptr(p.data());
  119. dmi_data.set_granted_access(tlm::tlm_dmi::DMI_ACCESS_READ_WRITE);
  120. return true;
  121. }
  122. } // namespace scc
  123. #endif /* _SYSC_MEMORY_H_ */