From 7c183df27b117065e8380df633586e2d35e1b11f Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Thu, 9 Nov 2023 15:43:35 +0100 Subject: [PATCH] First PIM modifications --- configs/example/gem5_library/arm-baremetal.py | 52 + src/mem/dramsys.cc | 3 + src/mem/dramsys.hh | 2 + src/mem/dramsys_wrapper.cc | 18 + src/mem/dramsys_wrapper.hh | 1 + src/mem/tlm2_base_protocol_checker.h | 1049 +++++++++++++++++ src/python/SConscript | 1 + .../components/boards/arm_baremetal_board.py | 298 +++++ src/systemc/tlm_bridge/gem5_to_tlm.cc | 2 +- 9 files changed, 1425 insertions(+), 1 deletion(-) create mode 100644 configs/example/gem5_library/arm-baremetal.py create mode 100644 src/mem/tlm2_base_protocol_checker.h create mode 100644 src/python/gem5/components/boards/arm_baremetal_board.py diff --git a/configs/example/gem5_library/arm-baremetal.py b/configs/example/gem5_library/arm-baremetal.py new file mode 100644 index 0000000000..3d59f12453 --- /dev/null +++ b/configs/example/gem5_library/arm-baremetal.py @@ -0,0 +1,52 @@ +from gem5.isas import ISA +from m5.objects import ( + ArmDefaultRelease, +) +from gem5.utils.requires import requires +from gem5.resources.workload import CustomWorkload +from gem5.resources.resource import BinaryResource +from gem5.simulate.simulator import Simulator +from m5.objects import VExpress_GEM5_Foundation +from gem5.components.boards.arm_baremetal_board import ArmBareMetalBoard +from gem5.components.memory import DRAMSysDDR3_1600 +from gem5.components.processors.cpu_types import CPUTypes +from gem5.components.processors.simple_processor import SimpleProcessor + +requires(isa_required=ISA.ARM) + +from gem5.components.cachehierarchies.classic.private_l1_private_l2_cache_hierarchy import ( + PrivateL1PrivateL2CacheHierarchy, +) +from gem5.components.cachehierarchies.classic.no_cache import NoCache + +cache_hierarchy = PrivateL1PrivateL2CacheHierarchy( + l1d_size="16kB", l1i_size="16kB", l2_size="256kB" +) +# cache_hierarchy = NoCache() + +memory = DRAMSysDDR3_1600(recordable=True) +processor = SimpleProcessor(cpu_type=CPUTypes.O3, num_cores=1, isa=ISA.ARM) +release = ArmDefaultRelease() +platform = VExpress_GEM5_Foundation() + +board = ArmBareMetalBoard( + clk_freq="3GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, + release=release, + platform=platform, +) + +board.m5ops_base = 0x10010000 + +workload = CustomWorkload( + "set_baremetal_workload", + { + "kernel": BinaryResource("aarch64"), + }, +) +board.set_workload(workload) + +simulator = Simulator(board=board) +simulator.run() diff --git a/src/mem/dramsys.cc b/src/mem/dramsys.cc index 68fe983d30..d1b6e9c372 100644 --- a/src/mem/dramsys.cc +++ b/src/mem/dramsys.cc @@ -41,7 +41,10 @@ DRAMSys::DRAMSys(Params const& params) : params.resource_directory)), dramSysWrapper( params.name.c_str(), config, params.recordable, params.range) + // checker("checker") { + // checker.initiator_socket.bind(dramSysWrapper.tSocket); + dramSysWrapper.dramsys->registerIdleCallback( [this] { diff --git a/src/mem/dramsys.hh b/src/mem/dramsys.hh index 8530f2c563..f95ac67138 100644 --- a/src/mem/dramsys.hh +++ b/src/mem/dramsys.hh @@ -33,6 +33,7 @@ #include "mem/abstract_mem.hh" #include "mem/dramsys_wrapper.hh" #include "params/DRAMSys.hh" +// #include "tlm2_base_protocol_checker.h" namespace gem5 { @@ -58,6 +59,7 @@ class DRAMSys : public AbstractMemory private: ::DRAMSys::Config::Configuration config; DRAMSysWrapper dramSysWrapper; + // tlm_utils::tlm2_base_protocol_checker<> checker; }; } // namespace memory diff --git a/src/mem/dramsys_wrapper.cc b/src/mem/dramsys_wrapper.cc index 2decec42a2..0b7376bdd8 100644 --- a/src/mem/dramsys_wrapper.cc +++ b/src/mem/dramsys_wrapper.cc @@ -89,6 +89,24 @@ tlm::tlm_sync_enum DRAMSysWrapper::nb_transport_fw( // Subtract base address offset payload.set_address(payload.get_address() - range.start()); + if (payload.get_address() < 0x4000 && payload.is_write() && phase == tlm::BEGIN_REQ) + { + char *msg = reinterpret_cast(payload.get_data_ptr()); + for (std::size_t i = 0; i < payload.get_data_length(); i++) + { + if (msg[i] != '\0') + { + message.push_back(msg[i]); + } + else + { + std::cout << message << std::endl; + message.clear(); + break; + } + } + } + return iSocket->nb_transport_fw(payload, phase, fwDelay); } diff --git a/src/mem/dramsys_wrapper.hh b/src/mem/dramsys_wrapper.hh index 26d552fd2f..11974faaf1 100644 --- a/src/mem/dramsys_wrapper.hh +++ b/src/mem/dramsys_wrapper.hh @@ -84,6 +84,7 @@ class DRAMSysWrapper : public sc_core::sc_module tlm_utils::simple_target_socket tSocket; std::shared_ptr<::DRAMSys::DRAMSys> dramsys; + std::string message; AddrRange range; }; diff --git a/src/mem/tlm2_base_protocol_checker.h b/src/mem/tlm2_base_protocol_checker.h new file mode 100644 index 0000000000..6874d38181 --- /dev/null +++ b/src/mem/tlm2_base_protocol_checker.h @@ -0,0 +1,1049 @@ + +// Filename: tlm2_base_protocol_checker.h + +//---------------------------------------------------------------------- +// Copyright (c) 2008-2013 by Doulos Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------- + +// Author: John Aynsley, Doulos + +// Version 1, 11 July 2008 +// Version 2, 16 July 2008 Only generate ref_count > 1 warning from 1st checker of path +// Version 3, 17 July 2008 Support compilation under SystemC 2.1.v1 +// Version 4, 12 Aug 2008 Add header #include +// Version 5, 08 Sep 2008 Fix bugs in message text +// Version 6, 01 Aug 2010 Update messages to refer to OSCI TLM-2.0 LRM of July 2009 +// Version 7, 25 Oct 2011 Minor bug fix for certain compilers: replace u_char with uchar_t +// Version 8, 02 Nov 2011 Support the endianness conversion functions by excluding the +// tlm_endian_context extension from the protocol checks +// Version 9, 17 Aug 2012 Fix LRM reference on line 805 (should be 8.2.11 a) [NOT YET RELEASED] +// Version 10, 3 Jan 2013 Updated messages to refer to IEEE Std 1666-2011, the combined SystemC + TLM-2.0 LRM +// Added checks related to the generic payload option attribute +// Version 11, 14 Mar 2016 Fix minor bug - start_phase should be a copy, not a reference + +// TLM-2.0 Base Protocol Compliance Checker + +/* +Instantiate this checker module in-line between initiator and target, initiator and interconnect, +or interconnect and target by binding the target_socket and initiator_socket +Binding two checkers either side of an interconnect component, or interleaving a series of +checkers with interconnect components, will enable some deeper checks as against having just +a single checker + +For example + + Initiator *initiator; + Bus *bus; + Memory *memory; + ... + initiator->socket.bind(bus->target_socket); + bus->initiator_socket.bind(memory->socket); + +might become + + tlm_utils::tlm2_base_protocol_checker<32> *checker1; + tlm_utils::tlm2_base_protocol_checker<32> *checker2; + ... + initiator->socket.bind(checker1->target_socket); + checker1->initiator_socket.bind(bus->target_socket); + bus->initiator_socket.bind(checker2->target_socket); + checker2->initiator_socket.bind(memory->socket); + + +GENERAL FEATURES OF THE BASE PROTOCOL CHECKER + +The checks are relatively expensive, hence by default the number of checks is limited. +A maximum number can be set explicitly by calling set_num_checks(max) +Checking can be deactivated at any time by calling set_num_checks(0) +All checkers decrement a single global count, because having some checkers running and +others not can cause bogus violation reports +It is not permitted to turn checks on by calling set_num_checks() once checking has been +deactivated, because this could cause bogus violation reports + +The DMI and debug checks are unaffected by the num_checks count (because they are cheap) + +The error messages contain User Manual references + +The checker is designed to be used with a transaction pool: otherwise it could consume +a lot of memory. The checker keeps a local copy of each transaction object +Failures are reported with a severity of SC_ERROR. The actions may be overridden by calling: + sc_report_handler::set_actions("tlm2_protocol_checker", ...); + +SPECIFIC CHECKS + +nb_transport: phase sequence BEGIN_REQ -> END_REQ -> BEGIN_RESP -> END_RESP +Must not have two outstanding requests or responses (exclusion rules) +Must not have decreasing timing annotations on calls to or returns from nb_transport_fw/bw +Phase extensions permitted and ignored +Must not call b_transport during nb_transport phase sequence and vice-versa + +nb_transport: memory manager must be set +nb_transport: reference count must be non-zero +First checker in BEGIN_REQ path should see ref_count == 1 (warning only) +An interconnect component that sets a memory manager should also clear it +An interconnect component that sets extensions with no memory manager should also clear them +(Does not bother with these memory manager checks for DMI and debug) + +Transaction object must be properly initialized +Many generic payload attributes must not be modified during the transaction lifetime +Transaction object must not be re-allocated for a new transaction while still in use +DMI descriptor must be properly initialized +Debug transaction must be properly initialized +Debug byte count must be less than data_length + +Checks that require multiple checkers to be instantiated along a transaction path: +The BEGIN_RESP path must be the reverse of the BEGIN_REQ path +Transaction object must not be sent with BEGIN_REQ while participating in a previous response +Interconnect component must not set response status attribute to TLM_OK_RESPONSE +Interconnect component must not modify data array on the response path + +Generic payload option attribute (IEEE Std 1666-2011, SystemC 2.3.x) +gp_option must be properly initialized and only used for DMI and debug transport +When gp_option is used, other gp attributes must be initalized and used as per the transport interfaces +*/ + + +// ******************** PREAMBLE ******************** + + +#ifndef __tlm2_base_protocol_checker__ +#define __tlm2_base_protocol_checker__ + +#include "systemc" +using std::cout; +using std::endl; +using std::dec; +using std::hex; + +#include "tlm.h" +#include +#include + + +namespace tlm_utils { + + +// Number of checks remaining +const sc_dt::uint64 default_num_checks = 100000; +static sc_dt::uint64 num_checks = default_num_checks; + + +// Types used when building a trace of the transaction path +typedef unsigned char uchar_t; +typedef std::deque deque_t; + +struct path_t { + path_t () + { + response_in_progress = false; + ok_response = false; + resp_data_ptr = 0; + } + + bool response_in_progress; + bool ok_response; + deque_t path; + uchar_t *resp_data_ptr; // Copy of data on response path +}; + +// Global variable used for checks involving multiple checkers along a transaction path +static std::map shared_map; + + +// ******************** CLASS DEFINITION ******************** + + +template +class tlm2_base_protocol_checker + + : public sc_core::sc_module + , public tlm::tlm_fw_transport_if + , public tlm::tlm_bw_transport_if +{ +public: + + // Instantiate and bind checker inline between an existing pair of initiator and target sockets + + tlm::tlm_target_socket + target_socket; + tlm::tlm_initiator_socket + initiator_socket; + + SC_CTOR(tlm2_base_protocol_checker) + : m_request_in_progress(0), m_response_in_progress(0) + { + target_socket .bind( *this ); + initiator_socket.bind( *this ); + } + + + // Access methods for num_checks count + + static void set_num_checks(sc_dt::uint64 n) + { + if (num_checks == 0) + SC_REPORT_FATAL("tlm2_protocol_checker", + "Method set_num_checks called after checking has stopped due to maximum number of checks being reached"); + num_checks = n; + } + + static sc_dt::uint64 get_num_checks() + { + return num_checks; + } + + + // TLM-2.0 interface methods for initiator and target sockets, instrumented with checks + + virtual tlm::tlm_sync_enum nb_transport_fw( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay) + { + tlm::tlm_phase start_phase = phase; + + if (num_checks) + nb_transport_fw_pre_checks( trans, phase, delay ); + + tlm::tlm_sync_enum status; + status = initiator_socket->nb_transport_fw( trans, phase, delay ); + + if (num_checks) + nb_transport_fw_post_checks( trans, start_phase, phase, delay, status ); + + return status; + } + + virtual tlm::tlm_sync_enum nb_transport_bw( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay) + { + if (num_checks) + nb_transport_bw_pre_checks( trans, phase, delay ); + + tlm::tlm_sync_enum status; + status = target_socket->nb_transport_bw( trans, phase, delay ); + + if (num_checks) + nb_transport_bw_post_checks( trans, phase, delay, status ); + + return status; + } + + virtual void b_transport( tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay ) + { + if (num_checks) + b_transport_pre_checks( trans, delay ); + + initiator_socket->b_transport( trans, delay ); + + if (num_checks) + b_transport_post_checks( trans, delay ); + } + + virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans, + tlm::tlm_dmi &dmi_data) + { + get_direct_mem_ptr_pre_checks( trans, dmi_data ); + + bool status; + status = initiator_socket->get_direct_mem_ptr( trans, dmi_data ); + + get_direct_mem_ptr_post_checks( trans, dmi_data ); + return status; + } + + virtual void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, + sc_dt::uint64 end_range) + { + target_socket->invalidate_direct_mem_ptr(start_range, end_range); + } + + virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans) + { + transport_dbg_pre_checks( trans ); + + unsigned int count; + count = initiator_socket->transport_dbg( trans ); + + transport_dbg_post_checks( trans, count ); + return count; + } + + +private: + void b_transport_pre_checks( tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); + + void b_transport_post_checks( tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); + + void nb_transport_fw_pre_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, + sc_core::sc_time &delay); + + void nb_transport_fw_post_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &start_phase, + tlm::tlm_phase &phase, + sc_core::sc_time &delay, tlm::tlm_sync_enum status); + + void nb_transport_bw_pre_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, + sc_core::sc_time &delay); + + void nb_transport_bw_post_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay, + tlm::tlm_sync_enum status); + + void nb_transport_response_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay, + const char *txt2, const char *txt3, const char *txt4); + + void check_initial_state( tlm::tlm_generic_payload &trans, + const char *txt2 ); + void check_trans_not_modified( tlm::tlm_generic_payload &trans, + const char *txt2 ); + void check_response_path( tlm::tlm_generic_payload &trans, + const char *txt2 ); + void remember_gp_option( tlm::tlm_generic_payload &trans ); + + void get_direct_mem_ptr_pre_checks( tlm::tlm_generic_payload &trans, + tlm::tlm_dmi &dmi_data ); + + void get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload &trans, + tlm::tlm_dmi &dmi_data ); + + void transport_dbg_pre_checks( tlm::tlm_generic_payload &trans ); + + void transport_dbg_post_checks( tlm::tlm_generic_payload &trans, + unsigned int count ); + + void tlm2error( tlm::tlm_generic_payload &trans, const char *ref, + bool warning = false ); + +private: + + struct state_t { + state_t() + { + b_call = 0; + ph = tlm::UNINITIALIZED_PHASE; + gp = 0; + } + + bool has_mm; + unsigned int b_call; // Number of b_transport calls in progress + tlm::tlm_phase ph; + sc_core::sc_time time; // Current time + annotated delay + tlm::tlm_generic_payload + *gp; // Points to new data and byte enable buffers + uchar_t *data_ptr; // Stores original pointers + uchar_t *byte_enable_ptr; + }; + + // Transaction state for the specific hop where this checker is inlined + std::map m_map; + + // Flags for exclusion rules + tlm::tlm_generic_payload *m_request_in_progress; + tlm::tlm_generic_payload *m_response_in_progress; + + std::ostringstream txt; + +}; + + + +// ******************** MEMBER FUNCTION DEFINITIONS ******************** + + +#define BOILERPLATE \ +template \ +void tlm2_base_protocol_checker:: + + +BOILERPLATE +b_transport_pre_checks( + tlm::tlm_generic_payload &trans, sc_core::sc_time & /*delay*/) +{ + ++ m_map[&trans].b_call; + + if ( trans.has_mm() && trans.get_ref_count() == 0) { + txt << "Transaction passed to b_transport with memory manager and reference count of 0"; + tlm2error(trans, "14.5 t)"); + } + check_initial_state(trans, "b_transport"); + +#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) + if (sc_core::sc_get_current_process_handle().proc_kind() == + sc_core::SC_METHOD_PROC_) { + txt << "b_transport called from method process"; + tlm2error(trans, "11.1.1.4 b)"); + } +#endif + + if (m_map[&trans].ph > 0 && m_map[&trans].ph < 4) { + txt << "b_transport called during a sequence of nb_transport calls"; + tlm2error(trans, "15.2.10 c)"); + } +} + + +BOILERPLATE +b_transport_post_checks( + tlm::tlm_generic_payload &trans, sc_core::sc_time & /*delay*/) +{ + check_response_path(trans, "b_transport"); + check_trans_not_modified(trans, "b_transport"); + -- m_map[&trans].b_call; +} + + +BOILERPLATE +nb_transport_fw_pre_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay) +{ + if ( !trans.has_mm() ) { + txt << "Transaction passed to nb_transport_fw with no memory manager set"; + tlm2error(trans, "14.5 i)"); + } + if ( trans.get_ref_count() == 0) { + txt << "Transaction passed to nb_transport_fw with reference count of 0"; + tlm2error(trans, "14.5 t)"); + } + + switch (phase) { + case tlm::BEGIN_REQ: + check_initial_state(trans, "nb_transport_fw"); + + if (m_map[&trans].ph > 0 + && m_map[&trans].ph < 4) { // END_RESP -> BEGIN_REQ is legal + txt << "Phase " << phase << + " sent out-of-sequence on forward path, detected in nb_transport_fw"; + tlm2error(trans, "15.2.4"); + } + + if (m_request_in_progress) { + txt << "Transaction violates BEGIN_REQ exclusion rule, detected in nb_transport_fw"; + tlm2error(trans, "15.2.6 e)"); + } + m_request_in_progress = &trans; + + if (m_map[&trans].b_call) { + txt << "nb_transport_fw called during a b_transport call"; + tlm2error(trans, "15.2.10 c)"); + } + break; + + case tlm::END_REQ: + case tlm::BEGIN_RESP: + case tlm::UNINITIALIZED_PHASE: + txt << "Phase " << phase << + " sent on forward path, detected in nb_transport_fw"; + tlm2error(trans, " 15.2.3 c)"); + break; + + case tlm::END_RESP: + if (m_map[&trans].ph != tlm::BEGIN_RESP) { + txt << "Phase " << phase << + " sent out-of-sequence on forward path, detected in nb_transport_fw"; + tlm2error(trans, "15.2.4"); + } + m_response_in_progress = 0; + break; + } + + if (phase < 5) // Ignore extended phases + m_map[&trans].ph = phase; + + if (sc_core::sc_time_stamp() + delay < m_map[&trans].time) { + txt << "nb_transport_fw called with decreasing timing annotation:" + << " delay = " << delay + << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time; + tlm2error(trans, "15.2.7 c)"); + } + m_map[&trans].time = sc_core::sc_time_stamp() + delay; +} + + +BOILERPLATE +nb_transport_fw_post_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &start_phase, + tlm::tlm_phase &phase, + sc_core::sc_time &delay, tlm::tlm_sync_enum status) +{ + if (status == tlm::TLM_UPDATED) { + nb_transport_response_checks( + trans, phase, delay, "(forward) return", "Return from nb_transport_fw", + "nb_transport_fw"); + } else if (status == tlm::TLM_COMPLETED) { + if (start_phase == tlm::BEGIN_REQ) + check_response_path(trans, "nb_transport_fw"); + m_request_in_progress = 0; + m_map[&trans].ph = tlm::UNINITIALIZED_PHASE; + } + + // Transaction object should not be re-allocated, even during the END_RESP phase + //if (phase != tlm::END_RESP) + { + std::ostringstream txt; + txt << "nb_transport_fw, phase = " << phase; + check_trans_not_modified(trans, txt.str().c_str()); + } +} + + +BOILERPLATE +nb_transport_bw_pre_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay) +{ + if ( !trans.has_mm() ) { + txt << "Transaction passed to nb_transport_bw with no memory manager set"; + tlm2error(trans, "14.5 i)"); + } + if ( trans.get_ref_count() == 0) { + txt << "Transaction passed to nb_transport_bw with reference count of 0"; + tlm2error(trans, "14.5 t)"); + } + nb_transport_response_checks( + trans, phase, delay, "backward", "nb_transport_bw called", "nb_transport_bw"); +} + + +BOILERPLATE +nb_transport_bw_post_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay, + tlm::tlm_sync_enum status) +{ + if (status == tlm::TLM_UPDATED) { + switch (phase) { + case tlm::BEGIN_REQ: + txt << "Phase " << phase << + " sent out-of-sequence on (backward) return path, detected in nb_transport_bw"; + tlm2error(trans, "15.2.4"); + break; + + case tlm::END_REQ: + case tlm::BEGIN_RESP: + case tlm::UNINITIALIZED_PHASE: + txt << "Phase " << phase << + " sent on (backward) return path, detected in nb_transport_bw"; + tlm2error(trans, "15.2.3 c)"); + break; + + case tlm::END_RESP: + if (m_map[&trans].ph != tlm::BEGIN_RESP) { + txt << "Phase " << phase << + " sent out-of-sequence on (backward) return path, detected in nb_transport_bw"; + tlm2error(trans, "15.2.4"); + } + + m_response_in_progress = 0; + break; + } + + if (phase < 5) // Ignore extended phases + m_map[&trans].ph = phase; + + if (sc_core::sc_time_stamp() + delay < m_map[&trans].time) { + txt << "Return from nb_transport_bw with decreasing timing annotation:" + << " delay = " << delay + << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time; + tlm2error(trans, "15.2.7 c)"); + } + m_map[&trans].time = sc_core::sc_time_stamp() + delay; + } else if (status == tlm::TLM_COMPLETED) { + m_response_in_progress = 0; + m_map[&trans].ph = tlm::UNINITIALIZED_PHASE; + } + + // Transaction object should not be re-allocated, even during the END_RESP phase + //if (phase != tlm::END_RESP) + { + std::ostringstream txt; + txt << "nb_transport_bw, phase = " << phase; + check_trans_not_modified(trans, txt.str().c_str()); + } +} + + +BOILERPLATE +nb_transport_response_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &delay, + const char *txt2, const char *txt3, const char *txt4) +{ + if (trans.is_response_ok()) + if (shared_map[&trans].response_in_progress + && !shared_map[&trans].ok_response) { + txt << "Interconnect component sets response status attribute to TLM_OK_RESPONSE" + << ", detected in " << txt4; + tlm2error(trans, "14.7"); + + } + + switch (phase) { + case tlm::BEGIN_REQ: + case tlm::END_RESP: + case tlm::UNINITIALIZED_PHASE: + txt << "Phase " << phase << " sent on " << txt2 << " path" + << ", detected in " << txt4; + tlm2error(trans, "15.2.3 c)"); + break; + + case tlm::END_REQ: + if (m_map[&trans].ph != tlm::BEGIN_REQ) { + txt << "Phase " << phase << " sent out-of-sequence on " << txt2 << " path" + << ", detected in " << txt4; + tlm2error(trans, "15.2.4"); + } + + m_request_in_progress = 0; + break; + + case tlm::BEGIN_RESP: + if (m_map[&trans].ph != tlm::BEGIN_REQ && m_map[&trans].ph != tlm::END_REQ) { + txt << "Phase " << phase << " sent out-of-sequence on " << txt2 << " path" + << ", detected in " << txt4; + tlm2error(trans, "15.2.4"); + } + + if (&trans == m_request_in_progress) + m_request_in_progress = 0; + + if (m_response_in_progress) { + txt << "Transaction violates BEGIN_RESP exclusion rule" + << ", detected in " << txt4; + tlm2error(trans, "15.2.6 f)"); + } + m_response_in_progress = &trans; + + check_response_path(trans, txt4); + break; + } + + if (phase < 5) // Ignore extended phases + m_map[&trans].ph = phase; + + if (sc_core::sc_time_stamp() + delay < m_map[&trans].time) { + txt << txt3 << " with decreasing timing annotation:" + << " delay = " << delay + << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time; + tlm2error(trans, "15.2.7 c)"); + } + m_map[&trans].time = sc_core::sc_time_stamp() + delay; +} + + +BOILERPLATE +check_initial_state( + tlm::tlm_generic_payload &trans, const char *txt2 ) +{ + if (num_checks > 0) { + --num_checks; + if (num_checks == 0) + SC_REPORT_INFO("tlm2_protocol_checker", + "Checkers deactivated after executing the set number of checks"); + } + + if ( trans.has_mm() && trans.get_ref_count() > 1 + && shared_map[&trans].path.empty() ) { + txt << "New transaction passed to " << txt2 << " with reference count = " + << trans.get_ref_count(); + tlm2error(trans, "14.5 t)", true); + } + if (trans.get_data_ptr() == 0 + && trans.get_command() != tlm::TLM_IGNORE_COMMAND) { + txt << "Transaction not properly initialized: data_ptr == 0, detected in " << + txt2; + tlm2error(trans, "14.11 e)"); + } + if (trans.get_data_length() == 0 + && trans.get_command() != tlm::TLM_IGNORE_COMMAND) { + txt << "Transaction not properly initialized: data_langth == 0, detected in " << + txt2; + tlm2error(trans, "14.12 d)"); + } + if (trans.get_byte_enable_ptr() != 0 && trans.get_byte_enable_length() == 0) { + txt << "Transaction not properly initialized: " + << "byte_enable_ptr != 0 and byte_enable_length == 0, detected in " << txt2; + tlm2error(trans, "14.14 f)"); + } + if (trans.get_streaming_width() == 0) { + txt << "Transaction not properly initialized: streaming_width == 0, detected in " + << txt2; + tlm2error(trans, "14.15 f)"); + } + if (trans.is_dmi_allowed()) { + txt << "Transaction not properly initialized: dmi_allowed == true, detected in " + << txt2; + tlm2error(trans, "14.16"); + } + if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE) { + txt << "Transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE, detected in " + << txt2; + tlm2error(trans, "14.17 e)"); + } + if (trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) { + txt << "Transaction not properly initialized: gp_option != TLM_MIN_PAYLOAD, detected in " + << txt2; + tlm2error(trans, "14.8 g)"); + } + + // Setup clones of transaction and buffers in map + tlm::tlm_generic_payload *gp = m_map[&trans].gp; + if (gp == 0) + gp = new tlm::tlm_generic_payload; // Memory leak: transactions are never cleared from map + else { + delete [] gp->get_data_ptr(); + gp->free_all_extensions(); + } + gp->set_data_ptr( new uchar_t[trans.get_data_length()] ); + m_map[&trans].data_ptr = trans.get_data_ptr(); + + if (gp->get_byte_enable_ptr()) + delete [] gp->get_byte_enable_ptr(); + if (trans.get_byte_enable_ptr()) + gp->set_byte_enable_ptr( new uchar_t[trans.get_byte_enable_length()] ); + else + gp->set_byte_enable_ptr(0); + m_map[&trans].byte_enable_ptr = trans.get_byte_enable_ptr(); + + gp->deep_copy_from(trans); + m_map[&trans].gp = gp; + m_map[&trans].time = sc_core::SC_ZERO_TIME; + m_map[&trans].has_mm = trans.has_mm(); + + // Store request path checker sequence + if (shared_map[&trans].resp_data_ptr) { + delete [] shared_map[&trans].resp_data_ptr; + shared_map[&trans].resp_data_ptr = 0; + } + if (shared_map[&trans].response_in_progress) { + txt << "Transaction object sent with BEGIN_REQ while still being used on a previous response path, detected in " + << txt2; + tlm2error(trans, "14.5 x)"); + } + shared_map[&trans].ok_response = false; + shared_map[&trans].path.push_back(this); +} + + +BOILERPLATE +remember_gp_option( + tlm::tlm_generic_payload &trans) +{ + // Setup clone of transaction in map in order to check gp_option only + tlm::tlm_generic_payload *gp = m_map[&trans].gp; + if (gp == 0) + gp = new tlm::tlm_generic_payload; // Memory leak: transactions are never cleared from map + gp->set_gp_option( trans.get_gp_option() ); + m_map[&trans].gp = gp; +} + + +BOILERPLATE +check_trans_not_modified( + tlm::tlm_generic_payload &trans, const char *txt2 ) +{ + tlm::tlm_generic_payload *init = m_map[&trans].gp; + + if (trans.get_command() != init->get_command()) { + txt << "Command attribute modified during transaction lifetime, detected in " << + txt2; + tlm2error(trans, "14.7"); + } + if (trans.get_data_ptr() != m_map[&trans].data_ptr) { + txt << "Data pointer attribute modified during transaction lifetime, detected in " + << txt2; + tlm2error(trans, "14.7"); + } + if (trans.get_data_length() != init->get_data_length()) { + txt << "Data length attribute modified during transaction lifetime, detected in " + << txt2; + tlm2error(trans, "14.7"); + } + if (trans.get_command() == tlm::TLM_WRITE_COMMAND) + for (unsigned int i = 0; i < init->get_data_length(); i++) + if (trans.get_data_ptr()[i] != init->get_data_ptr()[i]) { + txt << "Data array modified during transaction lifetime, detected in " << txt2; + tlm2error(trans, "14.7"); + } + if (trans.get_byte_enable_ptr() != m_map[&trans].byte_enable_ptr) { + txt << "Byte enable pointer attribute modified during transaction lifetime, detected in " + << txt2; + tlm2error(trans, "14.7"); + } + if (trans.get_byte_enable_length() != init->get_byte_enable_length()) { + txt << "Byte enable length attribute modified during transaction lifetime, detected in " + << txt2; + tlm2error(trans, "14.7"); + } + if (trans.get_byte_enable_ptr()) + for (unsigned int i = 0; i < init->get_byte_enable_length(); i++) + if (trans.get_byte_enable_ptr()[i] != init->get_byte_enable_ptr()[i]) { + txt << "Byte enable array modified during transaction lifetime, detected in " << + txt2; + tlm2error(trans, "14.7"); + } + if (trans.get_streaming_width() != init->get_streaming_width()) { + txt << "Streaming width attribute modified during transaction lifetime, detected in " + << txt2; + tlm2error(trans, "14.7"); + } + if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD + && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) { + txt << "Generic payload option attribute modified during transaction lifetime, detected in " + << txt2; + tlm2error(trans, "14.8 g)"); + } + if ( !m_map[&trans].has_mm ) { + if (trans.has_mm()) { + txt << "Interconnect component sets a memory manager, but does not clear it on return, detected in " + << txt2; + tlm2error(trans, "14.5 aa)"); + } + + for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) + // Exclude tlm_endian_context extension from the check because it is not cloned in m_map + if (i != tlm::tlm_endian_context::ID) + if (trans.get_extension(i)) + if ( !m_map[&trans].gp->get_extension(i) ) { + txt << "Extension set (index = " << i << + ") without also being deleted in the absence of a memory manager, detected in " + << txt2; + tlm2error(trans, "14.5 aa)"); + } + } + + uchar_t *resp_data_ptr = shared_map[&trans].resp_data_ptr; + if (resp_data_ptr) + for (unsigned int i = 0; i < trans.get_data_length(); i++) + if (trans.get_data_ptr()[i] != resp_data_ptr[i]) { + txt << "Transaction data array modified in interconnect component on response path, detected in " + << txt2; + tlm2error(trans, "14.7"); + } +} + + +BOILERPLATE +check_response_path( + tlm::tlm_generic_payload &trans, const char *txt2 ) +{ + if ( !shared_map[&trans].path.empty() ) { + if ( this != shared_map[&trans].path.back() ) { + txt << "BEGIN_RESP path is not the reverse of the BEGIN_REQ path."; + txt << "\nBEGIN_REQ path includes these checkers: -> "; + deque_t path = shared_map[&trans].path; + for (deque_t::iterator i = path.begin(); i < path.end(); i++) + txt << (*i)->name() << " -> "; + txt << "\nDetected in " << txt2; + tlm2error(trans, "15.2.11 a)"); + } + shared_map[&trans].path.pop_back(); + shared_map[&trans].response_in_progress = !shared_map[&trans].path.empty(); + shared_map[&trans].ok_response = trans.is_response_ok(); + + // Create a copy of the data array for comparison on the response path + if ( !shared_map[&trans].resp_data_ptr ) { + shared_map[&trans].resp_data_ptr = new uchar_t[trans.get_data_length()]; + memcpy(shared_map[&trans].resp_data_ptr, trans.get_data_ptr(), + trans.get_data_length()); + } + } +} + + +BOILERPLATE +get_direct_mem_ptr_pre_checks( + tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data ) +{ + remember_gp_option(trans); + + if (dmi_data.get_dmi_ptr() != 0) { + txt << "DMI descriptor not properly initialized: dmi_ptr != 0"; + tlm2error(trans, "11.2.5 f)"); + } + if (!dmi_data.is_none_allowed()) { + txt << "DMI descriptor not properly initialized: granted_access != DMI_ACCESS_NONE"; + tlm2error(trans, "11.2.5 a)"); + } + if (dmi_data.get_start_address() != 0) { + txt << "DMI descriptor not properly initialized: start_address != 0"; + tlm2error(trans, "11.2.5 u)"); + } + if (dmi_data.get_end_address() != (sc_dt::uint64)(-1)) { + txt << "DMI descriptor not properly initialized: end_address != 0"; + tlm2error(trans, "11.2.5 u)"); + } + if (dmi_data.get_read_latency() != sc_core::SC_ZERO_TIME) { + txt << "DMI descriptor not properly initialized: read_latency != SC_ZERO_TIME"; + tlm2error(trans, "11.2.5 ac)"); + } + if (dmi_data.get_write_latency() != sc_core::SC_ZERO_TIME) { + txt << "DMI descriptor not properly initialized: write_latency != SC_ZERO_TIME"; + tlm2error(trans, "11.2.5 ac)"); + } + + if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD) { + /* + if (trans.is_dmi_allowed()) // Would be rather brutal to flag dmi_allowed as an arror for a DMI transaction! + { + txt << "DMI transaction not properly initialized: dmi_allowed == true"; + tlm2error(trans, "14.8 e) & 14.16"); + } + */ + if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE) { + txt << "DMI transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE"; + tlm2error(trans, "14.8 e) & 14.17 e)"); + } + } else if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD_ACCEPTED) { + txt << "DMI transaction not properly initialized: gp_option == TLM_FULL_PAYLOAD_ACCEPTED"; + tlm2error(trans, "14.8 c) & e) & j)"); + } +} + + +BOILERPLATE +get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload &trans, + tlm::tlm_dmi & /*dmi_data*/ ) +{ + tlm::tlm_generic_payload *init = m_map[&trans].gp; + + if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD + && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) { + txt << "DMI transaction gp_option attribute value TLM_MIN_PAYLOAD modified during transaction lifetime"; + tlm2error(trans, "14.8 h)"); + } else if (init->get_gp_option() == tlm::TLM_FULL_PAYLOAD + && trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD) { + txt << "DMI transaction gp_option attribute value changed from TLM_FULL_PAYLOAD to TLM_MIN_PAYLOAD"; + tlm2error(trans, "14.8 j)"); + } +} + + +BOILERPLATE +transport_dbg_pre_checks( tlm::tlm_generic_payload &trans ) +{ + remember_gp_option(trans); + + if (trans.get_data_length() > 0 && trans.get_data_ptr() == 0) { + txt << "Debug transaction has data_ptr == 0"; + tlm2error(trans, "11.3.4 l)"); + } + + if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD) { + if (trans.get_byte_enable_ptr() != 0 && trans.get_byte_enable_length() == 0) { + txt << "Debug transaction not properly initialized: " + << "byte_enable_ptr != 0 and byte_enable_length == 0"; + tlm2error(trans, "14.8 f) & 14.14 f)"); + } + if (trans.get_streaming_width() == 0) { + txt << "Debug transaction not properly initialized: streaming_width == 0"; + tlm2error(trans, "14.8 f) & 14.15 f)"); + } + if (trans.is_dmi_allowed()) { + txt << "Debug transaction not properly initialized: dmi_allowed == true"; + tlm2error(trans, "14.8 f) & 14.16"); + } + if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE) { + txt << "Debug transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE"; + tlm2error(trans, "14.8 f) & 14.17 e)"); + } + } else if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD_ACCEPTED) { + txt << "Debug transaction not properly initialized: gp_option == TLM_FULL_PAYLOAD_ACCEPTED"; + tlm2error(trans, "14.8 c) & f) & l)"); + } +} + + +BOILERPLATE +transport_dbg_post_checks( tlm::tlm_generic_payload &trans, unsigned int count ) +{ + tlm::tlm_generic_payload *init = m_map[&trans].gp; + + if (trans.get_data_length() > 0 && trans.get_data_ptr() == 0) { + txt << "Debug transaction has data_ptr == 0"; + tlm2error(trans, "11.3.4 l)"); + } + if (count > trans.get_data_length()) { + txt << "Count returned from transport_dbg is greater than data_length"; + tlm2error(trans, "11.3.4 s)"); + } + + if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD + && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) { + txt << "Debug transaction gp_option attribute value TLM_MIN_PAYLOAD modified during transaction lifetime"; + tlm2error(trans, "14.8 h)"); + } else if (init->get_gp_option() == tlm::TLM_FULL_PAYLOAD + && trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD) { + txt << "Debug transaction gp_option attribute value changed from TLM_FULL_PAYLOAD to TLM_MIN_PAYLOAD"; + tlm2error(trans, "14.8 l)"); + } +} + + +BOILERPLATE +tlm2error( tlm::tlm_generic_payload &trans, const char *ref, bool warning ) +{ + txt << "\n\nRefer to IEEE Std 1666-2011, clause " << ref; + txt << "\n\nChecker instance: " << this->name(); + txt << "\n\nTransaction details:"; + txt << "\n has_mm = " << dec << trans.has_mm() << " (bool)"; + txt << "\n ref_count = " << dec << trans.get_ref_count() << " (int)"; + txt << "\n\n gp_option = " << + (trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD ? "TLM_MIN_PAYLOAD" + : trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD ? "TLM_FULL_PAYLOAD" + : "TLM_FULL_PAYLOAD_ACCEPTED"); + txt << "\n command = " << + (trans.get_command() == tlm::TLM_READ_COMMAND ? "TLM_READ_COMMAND" + : trans.get_command() == tlm::TLM_WRITE_COMMAND ? "TLM_WRITE_COMMAND" + : "TLM_IGNORE_COMMAND"); + txt << "\n address = " << hex << trans.get_address() << " (hex)"; + txt << "\n data_ptr = " << hex + << reinterpret_cast(trans.get_data_ptr()) << " (hex)"; + txt << "\n data_length = " << hex << trans.get_data_length() << + " (hex)"; + txt << "\n streaming_width = " << hex << trans.get_streaming_width() << + " (hex)"; + txt << "\n byte_enable_ptr = " << hex + << reinterpret_cast(trans.get_byte_enable_ptr()) << " (hex)"; + txt << "\n byte_enable_length = " << hex << trans.get_byte_enable_length() << + " (hex)"; + txt << "\n dmi_allowed = " << dec << trans.is_dmi_allowed() << + " (bool)"; + txt << "\n response_status = " << trans.get_response_string(); + + bool extensions_present = false; + for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) { + tlm::tlm_extension_base *ext = trans.get_extension(i); + if (ext) { + if (!extensions_present) + txt << "\n\n extensions:"; + txt << "\n index = " << i << " type = " << typeid(*ext).name(); + extensions_present = true; + } + } + + txt << "\n\n"; + if (warning) + SC_REPORT_WARNING("tlm2_protocol_checker", txt.str().c_str()); + else + SC_REPORT_ERROR("tlm2_protocol_checker", txt.str().c_str()); +} + + + +} // namespace tlm_utils + +#endif // __tlm2_base_protocol_checker__ \ No newline at end of file diff --git a/src/python/SConscript b/src/python/SConscript index ab711fb668..05828f6b63 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -51,6 +51,7 @@ PySource('gem5.components.boards', 'gem5/components/boards/simple_board.py') PySource('gem5.components.boards', 'gem5/components/boards/test_board.py') PySource('gem5.components.boards', 'gem5/components/boards/x86_board.py') PySource('gem5.components.boards', 'gem5/components/boards/arm_board.py') +PySource('gem5.components.boards', 'gem5/components/boards/arm_baremetal_board.py') PySource('gem5.components.boards', "gem5/components/boards/kernel_disk_workload.py") PySource('gem5.components.boards', diff --git a/src/python/gem5/components/boards/arm_baremetal_board.py b/src/python/gem5/components/boards/arm_baremetal_board.py new file mode 100644 index 0000000000..6794613697 --- /dev/null +++ b/src/python/gem5/components/boards/arm_baremetal_board.py @@ -0,0 +1,298 @@ +# Copyright (c) 2022 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from m5.objects import ( + Port, + IOXBar, + Bridge, + BadAddr, + Terminal, + AddrRange, + ArmSystem, + ArmRelease, + ArmFsWorkload, + VoltageDomain, + SrcClockDomain, + ArmDefaultRelease, + VExpress_GEM5_Base, + VExpress_GEM5_Foundation, + SimObject, + VncServer, +) + +from abc import ABCMeta +from ...isas import ISA +from ...utils.requires import requires +from ...utils.override import overrides +from typing import List, Sequence, Tuple +from .abstract_board import AbstractBoard +from ...resources.resource import AbstractResource, BinaryResource +from .kernel_disk_workload import KernelDiskWorkload +from ..cachehierarchies.classic.no_cache import NoCache +from ..processors.abstract_processor import AbstractProcessor +from ..memory.abstract_memory_system import AbstractMemorySystem +from ..cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy + + +class ArmBareMetalBoard(ArmSystem, AbstractBoard): + __metaclass__ = ABCMeta + + def __init__( + self, + clk_freq: str, + processor: AbstractProcessor, + memory: AbstractMemorySystem, + cache_hierarchy: AbstractCacheHierarchy, + platform: VExpress_GEM5_Base = VExpress_GEM5_Foundation(), + release: ArmRelease = ArmDefaultRelease(), + ) -> None: + # The platform and the clk has to be set before calling the super class + self._platform = platform + self._clk_freq = clk_freq + + super().__init__() + AbstractBoard.__init__( + self, + clk_freq=clk_freq, + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, + ) + + # This board requires ARM ISA to work. + requires(isa_required=ISA.ARM) + + # Setting up ARM release here. We use the ARM default release, which + # corresponds to an ARMv8 system. + self.release = release + + # Setting multi_proc of ArmSystem by counting the number of processors. + if processor.get_num_cores() == 1: + self.multi_proc = False + else: + self.multi_proc = True + + @overrides(AbstractBoard) + def _setup_board(self) -> None: + # This board is expected to run full-system simulation. + # Loading ArmFsWorkload() from `src/arch/arm/ArmFsWorkload.py` + self.workload = ArmFsWorkload() + + # We are fixing the following variable for the ArmSystem to work. The + # security extension is checked while generating the dtb file in + # realview. This board does not have security extension enabled. + self._have_psci = False + + # highest_el_is_64 is set to True. True if the register width of the + # highest implemented exception level is 64 bits. + self.highest_el_is_64 = True + + # Setting up the voltage and the clock domain here for the ARM board. + # The ArmSystem/RealView expects voltage_domain to be a parameter. + # The voltage and the clock frequency are taken from the devices.py + # file from configs/example/arm. We set the clock to the same frequency + # as the user specified in the config script. + self.voltage_domain = VoltageDomain(voltage="1.0V") + self.clk_domain = SrcClockDomain( + clock=self._clk_freq, voltage_domain=self.voltage_domain + ) + + # The ARM board supports both Terminal and VncServer. + self.terminal = Terminal() + self.vncserver = VncServer() + + # Incoherent I/O Bus + self.iobus = IOXBar() + self.iobus.badaddr_responder = BadAddr() + self.iobus.default = self.iobus.badaddr_responder.pio + + # We now need to setup the dma_ports. + self._dma_ports = None + + # RealView sets up most of the on-chip and off-chip devices and GIC + # for the ARM board. These devices' information is also used to + # generate the dtb file. We then connect the I/O devices to the + # I/O bus. + self._setup_io_devices() + + # Once the realview is setup, we can continue setting up the memory + # ranges. ArmBoard's memory can only be setup once realview is + # initialized. + memory = self.get_memory() + mem_size = memory.get_size() + + # The following code is taken from configs/example/arm/devices.py. It + # sets up all the memory ranges for the board. + self.mem_ranges = [] + success = False + for mem_range in self.realview._mem_regions: + size_in_range = min(mem_size, mem_range.size()) + self.mem_ranges.append( + AddrRange(start=mem_range.start, size=size_in_range) + ) + + mem_size -= size_in_range + if mem_size == 0: + success = True + break + + if success: + memory.set_memory_range(self.mem_ranges) + else: + raise ValueError("Memory size too big for platform capabilities") + + def _setup_io_devices(self) -> None: + """ + This method first sets up the platform. ARM uses `realview` platform. + Most of the on-chip and off-chip devices are setup by the realview + platform. Once realview is setup, we connect the I/O devices to the + I/O bus. + """ + + # Currently, the ArmBoard supports VExpress_GEM5_V1, + # VExpress_GEM5_V1_HDLcd and VExpress_GEM5_Foundation. + # VExpress_GEM5_V2 and VExpress_GEM5_V2_HDLcd are not supported by the + # ArmBoard. + self.realview = self._platform + + # We need to setup the global interrupt controller (GIC) addr for the + # realview system. + if hasattr(self.realview.gic, "cpu_addr"): + self.gic_cpu_addr = self.realview.gic.cpu_addr + + # IO devices has to setup before incorporating the caches in the case + # of ruby caches. Otherwise the DMA controllers are incorrectly + # created. The IO device has to be attached first. This is done in the + # realview class. + if self.get_cache_hierarchy().is_ruby(): + # All the on-chip devices are attached in this method. + self.realview.attachOnChipIO( + self.iobus, + dma_ports=self.get_dma_ports(), + mem_ports=self.get_memory().get_mem_ports(), + ) + self.realview.attachIO(self.iobus, dma_ports=self.get_dma_ports()) + + else: + # We either have iocache or dmabridge depending upon the + # cache_hierarchy. If we have "NoCache", then we use the dmabridge. + # Otherwise, we use the iocache on the board. + + # We setup the iobridge for the ARM Board. The default + # cache_hierarchy's NoCache class has an iobridge has a latency + # of 10. We are using an iobridge with latency = 50ns, taken + # from the configs/example/arm/devices.py. + self.iobridge = Bridge(delay="50ns") + self.iobridge.mem_side_port = self.iobus.cpu_side_ports + self.iobridge.cpu_side_port = ( + self.cache_hierarchy.get_mem_side_port() + ) + + if isinstance(self.cache_hierarchy, NoCache) is True: + # This corresponds to a machine without caches. We have a DMA + # bridge in this case. Parameters of this bridge are also taken + # from the common/example/arm/devices.py file. + self.dmabridge = Bridge(delay="50ns", ranges=self.mem_ranges) + self.dmabridge.mem_side_port = ( + self.cache_hierarchy.get_cpu_side_port() + ) + self.dmabridge.cpu_side_port = self.iobus.mem_side_ports + + # The classic caches are setup in the _setup_io_cache() method + # defined under the cachehierarchy class. Verified it with both + # PrivateL1PrivateL2CacheHierarchy and PrivateL1CacheHierarchy + # classes. + self.realview.attachOnChipIO( + self.cache_hierarchy.membus, self.iobridge + ) + self.realview.attachIO(self.iobus) + + @overrides(AbstractBoard) + def has_io_bus(self) -> bool: + return True + + @overrides(AbstractBoard) + def get_io_bus(self) -> IOXBar: + return self.iobus + + @overrides(AbstractBoard) + def has_coherent_io(self) -> bool: + # The setup of the caches gets a little tricky here. We need to + # override the default cache_hierarchy.iobridge due to different delay + # values (see method _setup_io_devices()). One way to do it would be to + # prevent creating cache_hierarchy.iobridge altogether. We trick + # NoCache() to assume that this board has no coherent_io and we we + # simply setup our own iobridge in the _setup_io_devices() method. + if isinstance(self.cache_hierarchy, NoCache): + return False + # In all other cases, we use the default values setup in the + # respective cache hierarchy class. + return True + + @overrides(AbstractBoard) + def get_mem_side_coherent_io_port(self) -> Port: + return self.iobus.mem_side_ports + + @overrides(AbstractBoard) + def has_dma_ports(self) -> bool: + return True + + @overrides(AbstractBoard) + def get_dma_ports(self) -> List[Port]: + # The DMA ports differ depending upon the cache hierarchy. The method + # self.set_dma_ports takes care of that. In the case of ruby caches, + # this method should initially return an empty list. + if self.cache_hierarchy.is_ruby(): + if self._dma_ports is None: + self._dma_ports = [] + + # _dma_ports should always be empty for classic caches. + return self._dma_ports + + @overrides(AbstractBoard) + def connect_system_port(self, port: Port) -> None: + self.system_port = port + + @overrides(AbstractBoard) + def _setup_memory_ranges(self) -> None: + """ + The ArmBoard's memory can only be setup after realview is setup. We set + this up in the `_setup_board` function. + """ + pass + + def set_baremetal_workload(self, kernel: BinaryResource) -> None: + self._set_fullsystem(True) + self.workload.object_file = kernel.get_local_path() + + @overrides(SimObject) + def createCCObject(self): + """We override this function as it is called in `m5.instantiate`. This + means we can insert a check to ensure the `_connect_things` function + has been run. + """ + super()._connect_things_check() + super().createCCObject() diff --git a/src/systemc/tlm_bridge/gem5_to_tlm.cc b/src/systemc/tlm_bridge/gem5_to_tlm.cc index 51c9f24923..747eeb30b0 100644 --- a/src/systemc/tlm_bridge/gem5_to_tlm.cc +++ b/src/systemc/tlm_bridge/gem5_to_tlm.cc @@ -67,6 +67,7 @@ #include "params/Gem5ToTlmBridge512.hh" #include "sim/eventq.hh" #include "sim/system.hh" +#include "systemc/ext/tlm_core/2/generic_payload/gp.hh" #include "systemc/tlm_bridge/sc_ext.hh" #include "systemc/tlm_bridge/sc_mm.hh" @@ -479,7 +480,6 @@ Gem5ToTlmBridge::recvRespRetry() tlm::tlm_generic_payload *trans = blockingResponse; blockingResponse = nullptr; - PacketPtr packet = packetMap[trans]; sc_assert(packet);