blob: 85d87ff218edb5f87dea60b13faced107f03afce [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 <register/hei_register.hpp>
Zane Shelley995be6c2021-02-24 15:48:55 -06004#include <util/hei_bit_string.hpp>
Zane Shelleyd5073512021-01-14 12:51:18 -06005#include <util/hei_includes.hpp>
Zane Shelley52cb1a92019-08-21 14:38:31 -05006
Zane Shelley871adec2019-07-30 11:01:39 -05007namespace libhei
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -05008{
9
Zane Shelley61565dc2019-09-18 21:57:10 -050010/**
Zane Shelley8deb0902019-10-14 15:52:27 -050011 * @brief An abstract class containing information (e.g. address, type, length,
12 * etc.) for an actual hardware register.
Zane Shelley61565dc2019-09-18 21:57:10 -050013 *
14 * Hardware access:
15 *
16 * Actual hardware access is defined by the user application via the user
17 * interface APIs. In order to tell the user application which chip to target,
Zane Shelley53efc352019-10-03 21:46:39 -050018 * the user application will give the isolator a list of pointers to its
19 * objects. They will then be passed into the public functions of this class
20 * and eventually given back to the user application when hardware access is
21 * needed.
Zane Shelleyd0af3582019-09-19 10:48:59 -050022 *
23 * Register cache:
24 *
25 * In order to save memory space, each instance of this class does not store
26 * the contents of the target hardware register. Instead, that data is stored
Paul Greenwood6574f6e2019-09-17 09:43:22 -050027 * in a register cache, which is a static variable defined in this class. This
Zane Shelleyd0af3582019-09-19 10:48:59 -050028 * allows us to store only what we need. The cache can also be thought of as a
29 * snapshot of the registers at the time of isolation, which can be useful if
30 * the hardware is still running and register values could change.
31 *
32 * In order to ensure stale data isn't used from the cache, call
33 * HardwareRegister::flushAll() before beginning isolation on a new attention.
34 * Also, HardwareRegister::flushAll() should be called when the isolator is
35 * uninitialized before the rest of the isolation objects are deleted.
Zane Shelley61565dc2019-09-18 21:57:10 -050036 */
Zane Shelleycd36f432019-08-30 21:22:07 -050037class HardwareRegister : public Register
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -050038{
Zane Shelley4de8ff82020-05-14 15:39:01 -050039 public: // Aliases
Patrick Williams2f7537d2023-05-10 07:51:39 -050040 using Ptr = std::shared_ptr<HardwareRegister>;
Zane Shelley4de8ff82020-05-14 15:39:01 -050041 using ConstPtr = std::shared_ptr<const HardwareRegister>;
42
43 using Key = std::pair<RegisterId_t, Instance_t>;
44
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -050045 public:
Zane Shelley8deb0902019-10-14 15:52:27 -050046 /** @brief Pure virtual destructor. */
47 virtual ~HardwareRegister() = 0;
48
49 protected:
Zane Shelley8deb0902019-10-14 15:52:27 -050050 /**
51 * @brief Constructor from components.
Zane Shelley7667b712020-05-11 20:45:40 -050052 * @param i_id Unique ID for this register.
53 * @param i_instance Instance of this register
54 * @param i_flags Attribute flags for this register.
Zane Shelley8deb0902019-10-14 15:52:27 -050055 */
Zane Shelley5ec88102020-05-11 21:08:25 -050056 HardwareRegister(RegisterId_t i_id, Instance_t i_instance,
57 RegisterAttributeFlags_t i_flags) :
Zane Shelley7f7a42d2019-10-28 13:28:31 -050058 Register(),
Zane Shelley5ec88102020-05-11 21:08:25 -050059 iv_id(i_id), iv_instance(i_instance), iv_flags(i_flags)
Zane Shelley8deb0902019-10-14 15:52:27 -050060 {}
61
62 private: // Instance variables
Zane Shelley8deb0902019-10-14 15:52:27 -050063 /** The unique ID for this register. */
64 const RegisterId_t iv_id;
65
66 /** A register may have multiple instances. All of which will have the same
67 * ID. This variable is used to distinguish between each instance of the
68 * register. */
Zane Shelley13b182b2020-05-07 20:23:45 -050069 const Instance_t iv_instance;
Zane Shelley8deb0902019-10-14 15:52:27 -050070
71 /** The hardware access level of this register (read/write, read-only,
72 * write-only, etc.). */
Zane Shelley7667b712020-05-11 20:45:40 -050073 const RegisterAttributeFlags_t iv_flags;
Zane Shelley8deb0902019-10-14 15:52:27 -050074
75 public: // Accessor functions
Zane Shelley8deb0902019-10-14 15:52:27 -050076 /* @return The unique ID for this register. */
Zane Shelley7f7a42d2019-10-28 13:28:31 -050077 RegisterId_t getId() const
78 {
79 return iv_id;
80 }
Zane Shelley8deb0902019-10-14 15:52:27 -050081
82 /* @return The instance of this register. */
Zane Shelley13b182b2020-05-07 20:23:45 -050083 Instance_t getInstance() const
Zane Shelley7f7a42d2019-10-28 13:28:31 -050084 {
85 return iv_instance;
86 }
Zane Shelley8deb0902019-10-14 15:52:27 -050087
Zane Shelley4de8ff82020-05-14 15:39:01 -050088 /** @return The register/instance key. */
89 Key getKey() const
90 {
91 return {iv_id, iv_instance};
92 }
93
Zane Shelley7667b712020-05-11 20:45:40 -050094 /** @return True if given flag is enabled, false if disabled. */
95 bool queryAttrFlag(RegisterAttributeFlags_t i_flag) const
Zane Shelley7f7a42d2019-10-28 13:28:31 -050096 {
Zane Shelley7667b712020-05-11 20:45:40 -050097 return (0 != (iv_flags & i_flag));
Zane Shelley7f7a42d2019-10-28 13:28:31 -050098 }
Zane Shelley8deb0902019-10-14 15:52:27 -050099
100 // NOTE: The following are determined by child classes.
101
102 /** @return This register's type. */
Zane Shelley5ec88102020-05-11 21:08:25 -0500103 virtual RegisterType_t getType() const = 0;
Zane Shelley8deb0902019-10-14 15:52:27 -0500104
105 /** @return The address of this register. */
106 virtual RegisterAddress_t getAddress() const = 0;
107
Zane Shelley75e68e92019-10-18 16:16:23 -0500108 public: // Operators
Zane Shelley75e68e92019-10-18 16:16:23 -0500109 /** @brief Equals operator. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500110 bool operator==(const HardwareRegister& i_r) const
Zane Shelley75e68e92019-10-18 16:16:23 -0500111 {
Zane Shelley981e56a2020-05-11 21:24:20 -0500112 // In general, comparing the ID and instance should be enough. However,
113 // no error will be thrown when adding the register to the flyweights
Zane Shelley4de8ff82020-05-14 15:39:01 -0500114 // and any other field differs. Therefore, all fields will be used and
Zane Shelley981e56a2020-05-11 21:24:20 -0500115 // invalid duplicates will be found when adding the register pointers
116 // to the IsolationChip objects.
117 return (getAddress() == i_r.getAddress()) && (getId() == i_r.getId()) &&
118 (getInstance() == i_r.getInstance()) &&
Zane Shelley4de8ff82020-05-14 15:39:01 -0500119 (getType() == i_r.getType()) && (iv_flags == i_r.iv_flags);
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 {
Zane Shelley981e56a2020-05-11 21:24:20 -0500125 // In general, comparing the ID and instance should be enough. However,
126 // no error will be thrown when adding the register to the flyweights
Zane Shelley4de8ff82020-05-14 15:39:01 -0500127 // and any other field differs. Therefore, all fields will be used and
Zane Shelley981e56a2020-05-11 21:24:20 -0500128 // invalid duplicates will be found when adding the register pointers
129 // to the IsolationChip objects.
Zane Shelley5ec88102020-05-11 21:08:25 -0500130 if (getAddress() < i_r.getAddress())
Zane Shelley75e68e92019-10-18 16:16:23 -0500131 {
132 return true;
133 }
Zane Shelley5ec88102020-05-11 21:08:25 -0500134 else if (getAddress() == i_r.getAddress())
Zane Shelley75e68e92019-10-18 16:16:23 -0500135 {
Zane Shelley981e56a2020-05-11 21:24:20 -0500136 if (getId() < i_r.getId())
137 {
138 return true;
139 }
140 else if (getId() == i_r.getId())
141 {
142 if (getInstance() < i_r.getInstance())
143 {
144 return true;
145 }
146 else if (getInstance() == i_r.getInstance())
147 {
Zane Shelley4de8ff82020-05-14 15:39:01 -0500148 if (getType() < i_r.getType())
149 {
150 return true;
151 }
152 else if (getType() == i_r.getType())
153 {
154 return (iv_flags < i_r.iv_flags);
155 }
Zane Shelley981e56a2020-05-11 21:24:20 -0500156 }
157 }
Zane Shelley75e68e92019-10-18 16:16:23 -0500158 }
159
160 return false;
161 }
162
Zane Shelley8deb0902019-10-14 15:52:27 -0500163 public:
Zane Shelley65ed96a2019-10-14 13:06:11 -0500164 /** Function overloaded from parent Register class. */
Zane Shelley5a78fa82022-09-16 16:49:58 -0500165 const BitString* getBitString(const Chip& i_chip) const override;
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500166
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500167 /**
Zane Shelley61565dc2019-09-18 21:57:10 -0500168 * @brief Reads a register from hardware via the user interface APIs.
Zane Shelley53efc352019-10-03 21:46:39 -0500169 * @param i_chip The target chip in which this register belongs.
Zane Shelley61565dc2019-09-18 21:57:10 -0500170 * @param i_force When false, this function will only read from hardware if
171 * an entry for this instance does not already exist in the
172 * register cache. When true, the entry in the register
173 * cache is flushed, if it exists. Then this function will
174 * read from hardware and update the cache.
175 * @return See the return code from the registerRead() user interface API.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500176 */
Zane Shelley2f4aa912020-05-08 14:28:18 -0500177 bool read(const Chip& i_chip, bool i_force = false) const;
Zane Shelley61565dc2019-09-18 21:57:10 -0500178
Ben Tyner7b3420b2020-05-11 10:52:07 -0500179#ifdef __HEI_ENABLE_HW_WRITE
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500180
181 /**
Zane Shelley61565dc2019-09-18 21:57:10 -0500182 * @brief Writes the value stored in the register cache to hardware via the
183 * user interface APIs.
Zane Shelley53efc352019-10-03 21:46:39 -0500184 * @param i_chip The target chip in which this register belongs.
Zane Shelley61565dc2019-09-18 21:57:10 -0500185 * @return See the return code from the registerWrite() user interface API.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500186 */
Zane Shelley2f4aa912020-05-08 14:28:18 -0500187 bool write(const Chip& i_chip) const;
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500188
Ben Tyner7b3420b2020-05-11 10:52:07 -0500189#endif // __HEI_ENABLE_HW_WRITE
Zane Shelley61565dc2019-09-18 21:57:10 -0500190
Zane Shelleyafa669a2019-10-15 13:23:17 -0500191 protected:
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500192 /**
Zane Shelleyafa669a2019-10-15 13:23:17 -0500193 * @brief Provides access to this register's BitString.
194 *
195 * WARNING: Allowing public access to this function may be dangerous. For
196 * now it should be left as protected.
197 *
Zane Shelley53efc352019-10-03 21:46:39 -0500198 * @param i_chip The target chip in which this register belongs.
Zane Shelleyafa669a2019-10-15 13:23:17 -0500199 * @return A reference to the BitString.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500200 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500201 BitString& accessBitString(const Chip& i_chip);
Zane Shelley61565dc2019-09-18 21:57:10 -0500202
Zane Shelleyd0af3582019-09-19 10:48:59 -0500203 private: // Register cache class variable
Zane Shelleyd0af3582019-09-19 10:48:59 -0500204 /**
205 * @brief Caches the contents of registers read from hardware.
206 *
207 * The goal is to create a snapshot of the hardware register contents as
208 * close to the reported attention as possible. This snapshot is then used
209 * for additional analysis/debug when needed.
210 */
211 class Cache
212 {
213 public:
Zane Shelleyd0af3582019-09-19 10:48:59 -0500214 /** @brief Default constructor. */
215 Cache() = default;
216
217 /** @brief Destructor. */
218 ~Cache() = default;
219
220 /** @brief Copy constructor. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500221 Cache(const Cache&) = delete;
Zane Shelleyd0af3582019-09-19 10:48:59 -0500222
223 /** @brief Assignment operator. */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500224 Cache& operator=(const Cache&) = delete;
Zane Shelleyd0af3582019-09-19 10:48:59 -0500225
226 /**
227 * @brief Queries if a specific entry exists in the cache.
228 * @param i_chip The target chip.
229 * @param i_hwReg The target register.
230 * @return True if the entry exists, false otherwise.
231 */
Zane Shelley7f7a42d2019-10-28 13:28:31 -0500232 bool query(const Chip& i_chip, const HardwareRegister* i_hwReg) const;
Zane Shelleyd0af3582019-09-19 10:48:59 -0500233
234 /**
235 * @brief Returns the data buffer for the given chip and register.
236 * @param i_chip The target chip.
237 * @param i_hwReg The target register.
238 * @return A reference to the BitString containing the register data.
239 * @note If an entry does not exist in the cache, an entry will be
240 * created and the BitString will be initialized to 0.
241 */
Zane Shelley7f7a42d2019-10-28 13:28:31 -0500242 BitString& access(const Chip& i_chip, const HardwareRegister* i_hwReg);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500243
244 /** @brief Flushes entire contents from cache. */
245 void flush();
246
247 /**
248 * @brief Removes a single register from the cache.
249 * @param i_chip The target chip.
250 * @param i_hwReg The target register.
251 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500252 void flush(const Chip& i_chip, const HardwareRegister* i_hwReg);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500253
254 private:
Zane Shelleyd0af3582019-09-19 10:48:59 -0500255 /**
256 * @brief Stores a BitStringBuffer for each HardwareRegister per Chip.
257 *
258 * The HardwareRegister keys will just be pointers to the isolation
259 * objects created in the main initialize() API. Those should exist
260 * until the main uninitialize() API is called. It is important that the
261 * cache is flushed at the beginning of the uninitialize() API before
262 * the rest of the isolation objects are deleted.
263 *
264 * The Chip keys are copies of the objects passed to the isolator
265 * because the user application is responsible for storage of the
266 * objects passed to the isolator. We don't want to chance a Chip was
267 * created as a local variable that goes out of scope, or other similar
268 * situations.
269 */
270 std::map<Chip, std::map<const HardwareRegister*, BitString*>> iv_cache;
271 };
272
273 /** This allows all HardwareRegister objects access to the cache. */
274 static Cache cv_cache;
275
276 public: // Register cache management functions.
Zane Shelleyd0af3582019-09-19 10:48:59 -0500277 /** @brief Flushes the entire register cache. */
Zane Shelley7f7a42d2019-10-28 13:28:31 -0500278 static void flushAll()
279 {
280 cv_cache.flush();
281 }
Zane Shelleyd0af3582019-09-19 10:48:59 -0500282
Zane Shelley53efc352019-10-03 21:46:39 -0500283 /**
284 * @brief Flushes this register from the cache.
285 * @param i_chip The target chip in which this register belongs.
286 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500287 void flush(const Chip& i_chip) const
Zane Shelleyd0af3582019-09-19 10:48:59 -0500288 {
Zane Shelley83da2452019-10-25 15:45:34 -0500289 cv_cache.flush(i_chip, this);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500290 }
291
Zane Shelley53efc352019-10-03 21:46:39 -0500292 private: // Register cache management functions.
Zane Shelley53efc352019-10-03 21:46:39 -0500293 /**
294 * @param i_chip The target chip in which this register belongs.
295 * @return True if an entry for this register exist in this cache.
296 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500297 bool queryCache(const Chip& i_chip) const
Zane Shelleyd0af3582019-09-19 10:48:59 -0500298 {
Zane Shelley83da2452019-10-25 15:45:34 -0500299 return cv_cache.query(i_chip, this);
Zane Shelley53efc352019-10-03 21:46:39 -0500300 }
301
302 /**
303 * @param i_chip The target chip in which this register belongs.
304 * @return A reference to this register's BitString in cache.
305 */
Zane Shelleyfe27b652019-10-28 11:33:07 -0500306 BitString& accessCache(const Chip& i_chip) const
Zane Shelley53efc352019-10-03 21:46:39 -0500307 {
Zane Shelley83da2452019-10-25 15:45:34 -0500308 return cv_cache.access(i_chip, this);
Zane Shelleyd0af3582019-09-19 10:48:59 -0500309 }
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500310};
311
Zane Shelley871adec2019-07-30 11:01:39 -0500312} // end namespace libhei