| /* |
| * Copyright (c) 2017-2020 Advanced Micro Devices, Inc. |
| * All rights reserved. |
| * |
| * For use for simulation and test purposes only |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. 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. |
| * |
| * 3. Neither the name of the copyright holder 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 HOLDER 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. |
| */ |
| |
| #ifndef CPU_TESTERS_PROTOCOL_TESTER_ADDRESS_MANAGER_HH_ |
| #define CPU_TESTERS_PROTOCOL_TESTER_ADDRESS_MANAGER_HH_ |
| |
| #include <unordered_map> |
| #include <unordered_set> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/types.hh" |
| #include "sim/eventq.hh" |
| |
| /* |
| * --- AddressManager has 3 main tasks --- |
| * (1) generate DRF request sequences |
| * (2) maintain internal log table |
| * (3) validate return values against ones in the log table |
| * |
| * A location is an abstract index of a unique real address. |
| * It's used internally within the tester only. |
| * randAddressMap has the mapping between a location and its real address. |
| * |
| * A value is an integer that a location in real memory can store. |
| * for now, we assume a value is 4-byte |
| * |
| * The location range (randAddressMap) has two distinct parts: |
| * Atomic locations: in the 1st part of randAddressMap & |
| * Non-atomic locations (or just locations): in the 2nd part |
| */ |
| |
| /* |
| * --- DRF request sequence generation --- |
| * Each lane of an episode starts selecting its location by calling: |
| * (1) getAtomicLoc |
| * (2) getLoadLoc/getStoreLoc |
| * (3) finishLocSelection |
| * |
| * Each lane of an episode completes its executing by calling: |
| * releaseLocation for all locations it selected |
| */ |
| |
| /* |
| * --- Internal structures --- |
| * There are multiple atomic structures, each of which corresponds |
| * to an atomic location. |
| * |
| * Each atomic structure manages a distinct range of locations in locArray |
| * This array is partitioned into 3 parts that are used to select locations |
| * for LDs and STs. Here is the location selecting rule: |
| * | (1) | (2) | (3) | |
| * - all locations in (1) cannot be picked for any LD and ST action |
| * - all locations in (2) can be picked for either LD or ST action |
| * - all locations in (3) can be picked for LD action only |
| * |
| * We maintain the 3 parts by 2 indices firstMark and secondMark. |
| * As locations are moved between partitions, both indices are updated |
| * accordingly. |
| * [0 .. firstMark-1] part (1) |
| * [firstMark .. secondMark-1] part (2) |
| * [secondMark .. arraySize-1] part (3) |
| * |
| * Each location has its context/property. locProps maintains |
| * contexts/properties of all locations. Context/property includes |
| * - current index of a location in locArray |
| * - the number of owners who are currently using the location |
| * |
| * To guarantee DRF constraints, the following conditions must hold |
| * - all locations in (1) have exactly 1 owner |
| * - all locations in (2) have exactly 0 owner |
| * - all locations in (3) have at least 1 owner |
| * - A LD request can randomly pick any location in (2) & (3) |
| * - A ST request can randomly pick any location in (2) |
| * |
| * loadStoreMap maintains all locations already selected for LDs/STs so far |
| * |
| * When endLocSelection is called (i.e., we've picked all locations for an |
| * episode), we need to move each selected location to its right partition. |
| * if LD_bit == 1 && ST_bit == 0 (i.e., picked for LDs), then move the |
| * location to (3) -> future LDs can pick it. |
| * if LD_bit == 0 && ST_bit == 1, then move the location to (1) -> NO future |
| * action can pick it until this episode is done. |
| * if LD_bit == 1 && ST_bit == 1, then move the location to (1) -> NO future |
| * action can pick it until this episode is done. |
| * clear the loadStoreMap |
| */ |
| |
| class AddressManager |
| { |
| public: |
| AddressManager(int n_atomic_locs, int numNormalLocsPerAtomic); |
| ~AddressManager(); |
| |
| typedef int32_t Value; |
| typedef int32_t Location; |
| |
| // return the unique address mapped to a location |
| Addr getAddress(Location loc); |
| // return a unique atomic location & start picking locations |
| Location getAtomicLoc(); |
| // return a random location for LD |
| Location getLoadLoc(Location atomic_loc); |
| // return a random location for ST |
| Location getStoreLoc(Location atomic_loc); |
| // finish picking locations |
| void finishLocSelection(Location atomic_loc); |
| // an episode is done, release location I've picked |
| void releaseLocation(Location atomic_loc, Location loc); |
| // update a log table entry with a given set of values |
| void updateLogTable(Location loc, int threadId, int episodeId, |
| Value new_value, Tick curTick, int cuId = -1); |
| // return the current value in the log table |
| Value getLoggedValue(Location loc) const; |
| // validate atomic response |
| bool validateAtomicResp(Location loc, Value ret_val); |
| |
| std::string printLastWriter(Location loc) const; |
| |
| static const int INVALID_VALUE; |
| static const int INVALID_LOCATION; |
| |
| private: |
| class LastWriter |
| { |
| public: |
| LastWriter() |
| : threadId(-1), cuId(-1), episodeId(-1), value(0), |
| writeTick(0) |
| { } |
| |
| const std::string print() const |
| { |
| return "(GpuThread ID " + std::to_string(threadId) + |
| ", CU ID " + std::to_string(cuId) + |
| ", Episode ID " + std::to_string(episodeId) + |
| ", Value " + std::to_string(value) + |
| ", Tick " + std::to_string(writeTick) + |
| ")"; |
| } |
| |
| void update(int _thread, int _cu, int _episode, Value _value, |
| Tick _tick) |
| { |
| threadId = _thread; |
| cuId = _cu; |
| episodeId = _episode; |
| value = _value; |
| writeTick = _tick; |
| } |
| |
| Value getLastStoredValue() const { return value; } |
| |
| private: |
| int threadId; |
| int cuId; |
| int episodeId; |
| Value value; |
| Tick writeTick; |
| }; |
| |
| class AtomicStruct |
| { |
| public: |
| AtomicStruct(Location atom_loc, Location loc_begin, Location loc_end); |
| ~AtomicStruct(); |
| |
| // functions picking locations for LD/ST/ATOMIC ops |
| void startLocSelection(); |
| Location getLoadLoc(); |
| Location getStoreLoc(); |
| void endLocSelection(); |
| |
| // an episode completed its actions |
| // return locations to their correct positions |
| void releaseLoc(Location loc); |
| // is the value what we expect? |
| bool isExpectedValue(Value val); |
| |
| private: |
| Location atomicLoc; |
| Location locationBase; |
| |
| // array storing all locations this structure is managing |
| Location* locArray; |
| int firstMark, secondMark; |
| int arraySize; |
| |
| // a vector of location's properties |
| typedef std::pair<int, int> LocProperty; |
| typedef std::vector<LocProperty> LocPropTable; |
| LocPropTable locProps; |
| |
| // a temporary map of location and its LD/ST selection |
| typedef std::pair<bool, bool> LdStBits; |
| typedef std::unordered_map<Location, LdStBits> LdStMap; |
| LdStMap loadStoreMap; |
| |
| // number of atomic requests at this location so far |
| int requestCount; |
| // a set of expected values |
| // when we request the first n atomic ops, we expect to receive n |
| // return values from [0 .. n-1] |
| typedef std::unordered_set<Value> ExpectedValueSet; |
| ExpectedValueSet expectedValues; |
| |
| // swap two locations in locArray |
| void swap(LocProperty& prop_1, LocProperty& prop_2); |
| |
| bool inFirstRegion(int idx) const |
| { |
| return (idx >= 0 && idx < firstMark); |
| } |
| bool inSecondRegion(int idx) const |
| { |
| return (idx >= firstMark && idx < secondMark); |
| } |
| bool inThirdRegion(int idx) const |
| { |
| return (idx >= secondMark && idx < arraySize); |
| } |
| }; |
| |
| // number of atomic locations |
| int numAtomicLocs; |
| // number of normal/non-atomic locations per atomic structure |
| int numLocsPerAtomic; |
| // total number of non-atomic locations |
| int numNormalLocs; |
| |
| // location - address mapping |
| typedef std::vector<Addr> AddressMap; |
| AddressMap randAddressMap; |
| |
| // a list of atomic structures |
| typedef std::vector<AtomicStruct*> AtomicStructTable; |
| AtomicStructTable atomicStructs; |
| |
| // internal log table |
| typedef std::vector<LastWriter*> LogTable; |
| LogTable logTable; |
| }; |
| |
| #endif /* CPU_TESTERS_PROTOCOL_TESTER_ADDRESS_MANAGER_HH_ */ |