blob: d8edfd8c8bcace4743a5b7bdcd72b7b697a9ee82 [file] [log] [blame]
Zane Shelley871adec2019-07-30 11:01:39 -05001#pragma once
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -05002
Zane Shelley52cb1a92019-08-21 14:38:31 -05003#include <hei_includes.hpp>
Ben Tyner032bf9e2020-05-06 21:27:54 -05004#include <hei_macros.hpp>
Zane Shelley52cb1a92019-08-21 14:38:31 -05005#include <register/hei_register.hpp>
6#include <util/hei_bit_string.hpp>
7
Zane Shelley871adec2019-07-30 11:01:39 -05008namespace libhei
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -05009{
10
Zane Shelley61565dc2019-09-18 21:57:10 -050011/**
Zane Shelley8deb0902019-10-14 15:52:27 -050012 * @brief An abstract class containing information (e.g. address, type, length,
13 * etc.) for an actual hardware register.
Zane Shelley61565dc2019-09-18 21:57:10 -050014 *
15 * Hardware access:
16 *
17 * Actual hardware access is defined by the user application via the user
18 * interface APIs. In order to tell the user application which chip to target,
Zane Shelley53efc352019-10-03 21:46:39 -050019 * the user application will give the isolator a list of pointers to its
20 * objects. They will then be passed into the public functions of this class
21 * and eventually given back to the user application when hardware access is
22 * needed.
Zane Shelleyd0af3582019-09-19 10:48:59 -050023 *
24 * Register cache:
25 *
26 * In order to save memory space, each instance of this class does not store
27 * the contents of the target hardware register. Instead, that data is stored
Paul Greenwood6574f6e2019-09-17 09:43:22 -050028 * in a register cache, which is a static variable defined in this class. This
Zane Shelleyd0af3582019-09-19 10:48:59 -050029 * allows us to store only what we need. The cache can also be thought of as a
30 * snapshot of the registers at the time of isolation, which can be useful if
31 * the hardware is still running and register values could change.
32 *
33 * In order to ensure stale data isn't used from the cache, call
34 * HardwareRegister::flushAll() before beginning isolation on a new attention.
35 * Also, HardwareRegister::flushAll() should be called when the isolator is
36 * uninitialized before the rest of the isolation objects are deleted.
Zane Shelley61565dc2019-09-18 21:57:10 -050037 */
Zane Shelleycd36f432019-08-30 21:22:07 -050038class HardwareRegister : public Register
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -050039{
40 public:
Zane Shelley8deb0902019-10-14 15:52:27 -050041 /** @brief Pure virtual destructor. */
42 virtual ~HardwareRegister() = 0;
43
44 protected:
Zane Shelley8deb0902019-10-14 15:52:27 -050045 /**
46 * @brief Constructor from components.
47 * @param i_chipType Type of chip associated with this register.
48 * @param i_id Unique ID for this register.
49 * @param i_instance Instance of this register
50 * @param i_accessLevel Hardware access level for this register.
51 */
Zane Shelley83da2452019-10-25 15:45:34 -050052 HardwareRegister(ChipType_t i_chipType, RegisterId_t i_id,
53 RegisterInstance_t i_instance,
54 RegisterAccessLevel_t i_accessLevel) :
Zane Shelley7f7a42d2019-10-28 13:28:31 -050055 Register(),
56 iv_chipType(i_chipType), iv_id(i_id), iv_instance(i_instance),
57 iv_accessLevel(i_accessLevel)
Zane Shelley8deb0902019-10-14 15:52:27 -050058 {}
59
60 private: // Instance variables
Zane Shelley8deb0902019-10-14 15:52:27 -050061 /** The type of chip associated with register. */
62 const ChipType_t iv_chipType;
63
64 /** The unique ID for this register. */
65 const RegisterId_t iv_id;
66
67 /** A register may have multiple instances. All of which will have the same
68 * ID. This variable is used to distinguish between each instance of the
69 * register. */
70 const RegisterInstance_t iv_instance;
71
72 /** The hardware access level of this register (read/write, read-only,
73 * write-only, etc.). */
74 const RegisterAccessLevel_t iv_accessLevel;
75
76 public: // Accessor functions
Zane Shelley8deb0902019-10-14 15:52:27 -050077 /** @return The type of chip associated with this register. */
Zane Shelley7f7a42d2019-10-28 13:28:31 -050078 ChipType_t getChipType() const
79 {
80 return iv_chipType;
81 }
Zane Shelley8deb0902019-10-14 15:52:27 -050082
83 /* @return The unique ID for this register. */
Zane Shelley7f7a42d2019-10-28 13:28:31 -050084 RegisterId_t getId() const
85 {
86 return iv_id;
87 }
Zane Shelley8deb0902019-10-14 15:52:27 -050088
89 /* @return The instance of this register. */
Zane Shelley7f7a42d2019-10-28 13:28:31 -050090 RegisterInstance_t getInstance() const
91 {
92 return iv_instance;
93 }
Zane Shelley8deb0902019-10-14 15:52:27 -050094
95 /** @return The hardware access level of this register. */
Zane Shelley7f7a42d2019-10-28 13:28:31 -050096 RegisterAccessLevel_t getAccessLevel() const
97 {
98 return iv_accessLevel;
99 }
Zane Shelley8deb0902019-10-14 15:52:27 -0500100
101 // NOTE: The following are determined by child classes.
102
103 /** @return This register's type. */
104 virtual RegisterType_t getRegisterType() const = 0;
105
106 /** @return The address of this register. */
107 virtual RegisterAddress_t getAddress() const = 0;
108
109 /** @return The size (in bytes) of this register. */
110 virtual size_t getSize() const = 0;
111
Zane Shelley75e68e92019-10-18 16:16:23 -0500112 public: // Operators
Zane Shelley75e68e92019-10-18 16:16:23 -0500113 /** @brief Equals operator. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500114 bool operator==(const HardwareRegister& i_r) const
Zane Shelley75e68e92019-10-18 16:16:23 -0500115 {
116 // Comparing register type, chip type, and address should be sufficient.
Zane Shelley83da2452019-10-25 15:45:34 -0500117 return (getRegisterType() == i_r.getRegisterType()) &&
Zane Shelley7c8faa12019-10-28 22:26:28 -0500118 (getChipType() == i_r.getChipType()) &&
119 (getAddress() == i_r.getAddress());
Zane Shelley75e68e92019-10-18 16:16:23 -0500120 }
121
122 /** @brief Less than operator. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500123 bool operator<(const HardwareRegister& i_r) const
Zane Shelley75e68e92019-10-18 16:16:23 -0500124 {
125 // Comparing register type, chip type, and address should be sufficient.
Zane Shelley83da2452019-10-25 15:45:34 -0500126 if (getRegisterType() < i_r.getRegisterType())
Zane Shelley75e68e92019-10-18 16:16:23 -0500127 {
128 return true;
129 }
Zane Shelley83da2452019-10-25 15:45:34 -0500130 else if (getRegisterType() == i_r.getRegisterType())
Zane Shelley75e68e92019-10-18 16:16:23 -0500131 {
Zane Shelley83da2452019-10-25 15:45:34 -0500132 if (getChipType() < i_r.getChipType())
Zane Shelley75e68e92019-10-18 16:16:23 -0500133 {
134 return true;
135 }
Zane Shelley83da2452019-10-25 15:45:34 -0500136 else if (getChipType() == i_r.getChipType())
Zane Shelley75e68e92019-10-18 16:16:23 -0500137 {
Zane Shelley83da2452019-10-25 15:45:34 -0500138 return (getAddress() < i_r.getAddress());
Zane Shelley75e68e92019-10-18 16:16:23 -0500139 }
140 }
141
142 return false;
143 }
144
Zane Shelley8deb0902019-10-14 15:52:27 -0500145 public:
Zane Shelley65ed96a2019-10-14 13:06:11 -0500146 /** Function overloaded from parent Register class. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500147 const BitString* getBitString(const Chip& i_chip) const;
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500148
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500149 /**
Zane Shelley61565dc2019-09-18 21:57:10 -0500150 * @brief Reads a register from hardware via the user interface APIs.
Zane Shelley53efc352019-10-03 21:46:39 -0500151 * @param i_chip The target chip in which this register belongs.
Zane Shelley61565dc2019-09-18 21:57:10 -0500152 * @param i_force When false, this function will only read from hardware if
153 * an entry for this instance does not already exist in the
154 * register cache. When true, the entry in the register
155 * cache is flushed, if it exists. Then this function will
156 * read from hardware and update the cache.
157 * @return See the return code from the registerRead() user interface API.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500158 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500159 ReturnCode read(const Chip& i_chip, bool i_force = false) const;
Zane Shelley61565dc2019-09-18 21:57:10 -0500160
Zane Shelley83da2452019-10-25 15:45:34 -0500161#ifndef __HEI_READ_ONLY
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500162
163 /**
Zane Shelley61565dc2019-09-18 21:57:10 -0500164 * @brief Writes the value stored in the register cache to hardware via the
165 * user interface APIs.
Zane Shelley53efc352019-10-03 21:46:39 -0500166 * @param i_chip The target chip in which this register belongs.
Zane Shelley61565dc2019-09-18 21:57:10 -0500167 * @return See the return code from the registerWrite() user interface API.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500168 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500169 ReturnCode write(const Chip& i_chip) const;
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500170
Zane Shelley83da2452019-10-25 15:45:34 -0500171#endif // __HEI_READ_ONLY
Zane Shelley61565dc2019-09-18 21:57:10 -0500172
Zane Shelleyafa669a2019-10-15 13:23:17 -0500173 protected:
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500174 /**
Zane Shelleyafa669a2019-10-15 13:23:17 -0500175 * @brief Provides access to this register's BitString.
176 *
177 * WARNING: Allowing public access to this function may be dangerous. For
178 * now it should be left as protected.
179 *
Zane Shelley53efc352019-10-03 21:46:39 -0500180 * @param i_chip The target chip in which this register belongs.
Zane Shelleyafa669a2019-10-15 13:23:17 -0500181 * @return A reference to the BitString.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500182 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500183 BitString& accessBitString(const Chip& i_chip);
Zane Shelley61565dc2019-09-18 21:57:10 -0500184
Zane Shelley61565dc2019-09-18 21:57:10 -0500185 private: // Hardware accessor management functions.
Zane Shelley53efc352019-10-03 21:46:39 -0500186 /** @brief Asserts this register belongs on the target accessor chip. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500187 void verifyAccessorChip(const Chip& i_chip) const
Zane Shelley61565dc2019-09-18 21:57:10 -0500188 {
Zane Shelley83da2452019-10-25 15:45:34 -0500189 HEI_ASSERT(getChipType() == i_chip.getType());
Zane Shelley61565dc2019-09-18 21:57:10 -0500190 }
Zane Shelleyd0af3582019-09-19 10:48:59 -0500191
192 private: // Register cache class variable
Zane Shelleyd0af3582019-09-19 10:48:59 -0500193 /**
194 * @brief Caches the contents of registers read from hardware.
195 *
196 * The goal is to create a snapshot of the hardware register contents as
197 * close to the reported attention as possible. This snapshot is then used
198 * for additional analysis/debug when needed.
199 */
200 class Cache
201 {
202 public:
Zane Shelleyd0af3582019-09-19 10:48:59 -0500203 /** @brief Default constructor. */
204 Cache() = default;
205
206 /** @brief Destructor. */
207 ~Cache() = default;
208
209 /** @brief Copy constructor. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500210 Cache(const Cache&) = delete;
Zane Shelleyd0af3582019-09-19 10:48:59 -0500211
212 /** @brief Assignment operator. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500213 Cache& operator=(const Cache&) = delete;
Zane Shelleyd0af3582019-09-19 10:48:59 -0500214
215 /**
216 * @brief Queries if a specific entry exists in the cache.
217 * @param i_chip The target chip.
218 * @param i_hwReg The target register.
219 * @return True if the entry exists, false otherwise.
220 */
Zane Shelley7f7a42d2019-10-28 13:28:31 -0500221 bool query(const Chip& i_chip, const HardwareRegister* i_hwReg) const;
Zane Shelleyd0af3582019-09-19 10:48:59 -0500222
223 /**
224 * @brief Returns the data buffer for the given chip and register.
225 * @param i_chip The target chip.
226 * @param i_hwReg The target register.
227 * @return A reference to the BitString containing the register data.
228 * @note If an entry does not exist in the cache, an entry will be
229 * created and the BitString will be initialized to 0.
230 */
Zane Shelley7f7a42d2019-10-28 13:28:31 -0500231 BitString& access(const Chip& i_chip, const HardwareRegister* i_hwReg);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500232
233 /** @brief Flushes entire contents from cache. */
234 void flush();
235
236 /**
237 * @brief Removes a single register from the cache.
238 * @param i_chip The target chip.
239 * @param i_hwReg The target register.
240 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500241 void flush(const Chip& i_chip, const HardwareRegister* i_hwReg);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500242
243 private:
Zane Shelleyd0af3582019-09-19 10:48:59 -0500244 /**
245 * @brief Stores a BitStringBuffer for each HardwareRegister per Chip.
246 *
247 * The HardwareRegister keys will just be pointers to the isolation
248 * objects created in the main initialize() API. Those should exist
249 * until the main uninitialize() API is called. It is important that the
250 * cache is flushed at the beginning of the uninitialize() API before
251 * the rest of the isolation objects are deleted.
252 *
253 * The Chip keys are copies of the objects passed to the isolator
254 * because the user application is responsible for storage of the
255 * objects passed to the isolator. We don't want to chance a Chip was
256 * created as a local variable that goes out of scope, or other similar
257 * situations.
258 */
259 std::map<Chip, std::map<const HardwareRegister*, BitString*>> iv_cache;
260 };
261
262 /** This allows all HardwareRegister objects access to the cache. */
263 static Cache cv_cache;
264
265 public: // Register cache management functions.
Zane Shelleyd0af3582019-09-19 10:48:59 -0500266 /** @brief Flushes the entire register cache. */
Zane Shelley7f7a42d2019-10-28 13:28:31 -0500267 static void flushAll()
268 {
269 cv_cache.flush();
270 }
Zane Shelleyd0af3582019-09-19 10:48:59 -0500271
Zane Shelley53efc352019-10-03 21:46:39 -0500272 /**
273 * @brief Flushes this register from the cache.
274 * @param i_chip The target chip in which this register belongs.
275 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500276 void flush(const Chip& i_chip) const
Zane Shelleyd0af3582019-09-19 10:48:59 -0500277 {
Zane Shelley83da2452019-10-25 15:45:34 -0500278 cv_cache.flush(i_chip, this);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500279 }
280
Zane Shelley53efc352019-10-03 21:46:39 -0500281 private: // Register cache management functions.
Zane Shelley53efc352019-10-03 21:46:39 -0500282 /**
283 * @param i_chip The target chip in which this register belongs.
284 * @return True if an entry for this register exist in this cache.
285 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500286 bool queryCache(const Chip& i_chip) const
Zane Shelleyd0af3582019-09-19 10:48:59 -0500287 {
Zane Shelley83da2452019-10-25 15:45:34 -0500288 return cv_cache.query(i_chip, this);
Zane Shelley53efc352019-10-03 21:46:39 -0500289 }
290
291 /**
292 * @param i_chip The target chip in which this register belongs.
293 * @return A reference to this register's BitString in cache.
294 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500295 BitString& accessCache(const Chip& i_chip) const
Zane Shelley53efc352019-10-03 21:46:39 -0500296 {
Zane Shelley83da2452019-10-25 15:45:34 -0500297 return cv_cache.access(i_chip, this);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500298 }
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500299};
300
Zane Shelley871adec2019-07-30 11:01:39 -0500301} // end namespace libhei