blob: dfe6c60fc07df2f7b43c420f27bad819aa47d01e [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>
4#include <register/hei_register.hpp>
5#include <util/hei_bit_string.hpp>
6
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,
18 * the user application gives the isolator pointers to its chip objects. As
19 * each chip needs to be accessed, the isolator must store the chip in a
20 * static variable defined in this class. The intended use is:
21 *
22 * - Call HardwareRegister::setAccessor() with the target chip.
23 * - Perform all necessary hardware accesses to that chip.
24 * - Call HardwareRegister::clearAccessor() to remove the chip access. This
25 * helps ensure we don't try to access the wrong chip.
Zane Shelleyd0af3582019-09-19 10:48:59 -050026 *
27 * Register cache:
28 *
29 * In order to save memory space, each instance of this class does not store
30 * the contents of the target hardware register. Instead, that data is stored
Paul Greenwood6574f6e2019-09-17 09:43:22 -050031 * in a register cache, which is a static variable defined in this class. This
Zane Shelleyd0af3582019-09-19 10:48:59 -050032 * allows us to store only what we need. The cache can also be thought of as a
33 * snapshot of the registers at the time of isolation, which can be useful if
34 * the hardware is still running and register values could change.
35 *
36 * In order to ensure stale data isn't used from the cache, call
37 * HardwareRegister::flushAll() before beginning isolation on a new attention.
38 * Also, HardwareRegister::flushAll() should be called when the isolator is
39 * uninitialized before the rest of the isolation objects are deleted.
Zane Shelley61565dc2019-09-18 21:57:10 -050040 */
Zane Shelleycd36f432019-08-30 21:22:07 -050041class HardwareRegister : public Register
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -050042{
43 public:
44
Zane Shelley8deb0902019-10-14 15:52:27 -050045 /** @brief Pure virtual destructor. */
46 virtual ~HardwareRegister() = 0;
47
48 protected:
49
50 /**
51 * @brief Constructor from components.
52 * @param i_chipType Type of chip associated with this register.
53 * @param i_id Unique ID for this register.
54 * @param i_instance Instance of this register
55 * @param i_accessLevel Hardware access level for this register.
56 */
57 HardwareRegister( ChipType_t i_chipType, RegisterId_t i_id,
58 RegisterInstance_t i_instance,
59 RegisterAccessLevel_t i_accessLevel ) :
60 Register(), iv_chipType( i_chipType ), iv_id( i_id ),
61 iv_instance( i_instance ), iv_accessLevel( i_accessLevel )
62 {}
63
64 private: // Instance variables
65
66 /** The type of chip associated with register. */
67 const ChipType_t iv_chipType;
68
69 /** The unique ID for this register. */
70 const RegisterId_t iv_id;
71
72 /** A register may have multiple instances. All of which will have the same
73 * ID. This variable is used to distinguish between each instance of the
74 * register. */
75 const RegisterInstance_t iv_instance;
76
77 /** The hardware access level of this register (read/write, read-only,
78 * write-only, etc.). */
79 const RegisterAccessLevel_t iv_accessLevel;
80
81 public: // Accessor functions
82
83 /** @return The type of chip associated with this register. */
84 ChipType_t getChipType() const { return iv_chipType; }
85
86 /* @return The unique ID for this register. */
87 RegisterId_t getId() const { return iv_id; }
88
89 /* @return The instance of this register. */
90 RegisterInstance_t getInstance() const { return iv_instance; }
91
92 /** @return The hardware access level of this register. */
93 RegisterAccessLevel_t getAccessLevel() const { return iv_accessLevel; }
94
95 // NOTE: The following are determined by child classes.
96
97 /** @return This register's type. */
98 virtual RegisterType_t getRegisterType() const = 0;
99
100 /** @return The address of this register. */
101 virtual RegisterAddress_t getAddress() const = 0;
102
103 /** @return The size (in bytes) of this register. */
104 virtual size_t getSize() const = 0;
105
106 public:
107
Zane Shelley65ed96a2019-10-14 13:06:11 -0500108 /** Function overloaded from parent Register class. */
Paul Greenwood6574f6e2019-09-17 09:43:22 -0500109 virtual const BitString * getBitString() const;
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500110
Zane Shelley65ed96a2019-10-14 13:06:11 -0500111#if 0
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500112 /**
113 * @brief Updates bit string contents associated with register
114 * @param i_bs poiner to bit string
115 * @return Nil
116 */
Paul Greenwood6574f6e2019-09-17 09:43:22 -0500117 virtual void setBitString(const BitString * i_bs) ;
Zane Shelley61565dc2019-09-18 21:57:10 -0500118#endif
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500119
120 /**
Zane Shelley61565dc2019-09-18 21:57:10 -0500121 * @brief Reads a register from hardware via the user interface APIs.
122 * @param i_force When false, this function will only read from hardware if
123 * an entry for this instance does not already exist in the
124 * register cache. When true, the entry in the register
125 * cache is flushed, if it exists. Then this function will
126 * read from hardware and update the cache.
127 * @return See the return code from the registerRead() user interface API.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500128 */
Zane Shelley61565dc2019-09-18 21:57:10 -0500129 ReturnCode read( bool i_force = false ) const;
130
131 #ifndef __HEI_READ_ONLY
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500132
133 /**
Zane Shelley61565dc2019-09-18 21:57:10 -0500134 * @brief Writes the value stored in the register cache to hardware via the
135 * user interface APIs.
136 * @return See the return code from the registerWrite() user interface API.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500137 */
Zane Shelley61565dc2019-09-18 21:57:10 -0500138 ReturnCode write() const;
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500139
Zane Shelley61565dc2019-09-18 21:57:10 -0500140 #endif // __HEI_READ_ONLY
141
142#if 0
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500143 protected: // Functions
144
145 /**
Paul Greenwood6574f6e2019-09-17 09:43:22 -0500146 * @return If iv_operationType indicates a register read is possible
147 * (ACCESS_RO or ACCESS_RW), returns a reference to bit string.
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500148 */
Paul Greenwood6574f6e2019-09-17 09:43:22 -0500149 virtual BitString & accessBitString();
Zane Shelleyb77b5732019-08-30 22:01:06 -0500150#endif
Zane Shelley61565dc2019-09-18 21:57:10 -0500151
152 private: // Hardware accessor class variable
153
154 /** @brief A simple class that stores the chip used to access hardware. */
155 class Accessor
156 {
157 public:
158
159 /**
160 * @brief Constructor.
161 * @param i_chip The chip used to access hardware.
162 */
163 explicit Accessor( const Chip & i_chip ) :
164 iv_chip( i_chip )
165 {}
166
167 /** @brief Destructor. */
168 ~Accessor() = default;
169
170 /** @brief Copy constructor. */
171 Accessor( const Accessor & ) = delete;
172
173 /** @brief Assignment operator. */
174 Accessor & operator=( const Accessor & ) = delete;
175
176 /** @return The chip used to access hardware. */
177 const Chip & getChip() const { return iv_chip; }
178
179 private:
180
181 /**
182 * A Chip object provided by the user application. The isolator does not
183 * know anything about this object nor how to use it. Its only purpose
184 * is to get passed back to the user application for hardware access
185 * operations.
186 */
187 const Chip iv_chip;
188
189 }; // end class Accessor
190
191 /**
192 * This allows all HardwareRegister objects access to a chip via the user
193 * interface APIs. It is intentially defined as a pointer. It can be set to
194 * nullptr to signify that access is restricted at this time. This is useful
195 * to prevent users from accidentally accessing registers on the wrong chip.
196 * It is recommended to use setAccessor() and clearAccessor() to manage this
197 * variable.
198 */
199 static Accessor * cv_accessor;
200
201 public: // Hardware accessor management functions.
202
203 /**
204 * @brief Initializes a new hardware accessor.
205 * @param i_chip The chip used to access hardware.
206 */
207 static void setAccessor( const Chip & i_chip )
208 {
209 clearAccessor();
210 cv_accessor = new Accessor( i_chip );
211 }
212
213 /** @brief Deletes the current hardware accessor. */
214 static void clearAccessor()
215 {
216 delete cv_accessor;
217 cv_accessor = nullptr;
218 }
219
220 private: // Hardware accessor management functions.
221
222 /** @return The chip stored in cv_accessor. */
223 const Chip & getAccessorChip() const
224 {
225 HEI_ASSERT( nullptr != cv_accessor );
226
Zane Shelley61565dc2019-09-18 21:57:10 -0500227 // Extra sanity check to verify this register belongs on the target
228 // accessor chip.
Paul Greenwood6574f6e2019-09-17 09:43:22 -0500229 HEI_ASSERT( getChipType() != cv_accessor->getChip().getType() );
Zane Shelley61565dc2019-09-18 21:57:10 -0500230
231 return cv_accessor->getChip();
232 }
Zane Shelleyd0af3582019-09-19 10:48:59 -0500233
234 private: // Register cache class variable
235
236 /**
237 * @brief Caches the contents of registers read from hardware.
238 *
239 * The goal is to create a snapshot of the hardware register contents as
240 * close to the reported attention as possible. This snapshot is then used
241 * for additional analysis/debug when needed.
242 */
243 class Cache
244 {
245 public:
246
247 /** @brief Default constructor. */
248 Cache() = default;
249
250 /** @brief Destructor. */
251 ~Cache() = default;
252
253 /** @brief Copy constructor. */
254 Cache( const Cache & ) = delete;
255
256 /** @brief Assignment operator. */
257 Cache & operator=( const Cache & ) = delete;
258
259 /**
260 * @brief Queries if a specific entry exists in the cache.
261 * @param i_chip The target chip.
262 * @param i_hwReg The target register.
263 * @return True if the entry exists, false otherwise.
264 */
265 bool query( const Chip & i_chip,
266 const HardwareRegister * i_hwReg ) const;
267
268 /**
269 * @brief Returns the data buffer for the given chip and register.
270 * @param i_chip The target chip.
271 * @param i_hwReg The target register.
272 * @return A reference to the BitString containing the register data.
273 * @note If an entry does not exist in the cache, an entry will be
274 * created and the BitString will be initialized to 0.
275 */
276 BitString & access( const Chip & i_chip,
277 const HardwareRegister * i_hwReg );
278
279 /** @brief Flushes entire contents from cache. */
280 void flush();
281
282 /**
283 * @brief Removes a single register from the cache.
284 * @param i_chip The target chip.
285 * @param i_hwReg The target register.
286 */
287 void flush( const Chip & i_chip, const HardwareRegister * i_hwReg );
288
289 private:
290
291 /**
292 * @brief Stores a BitStringBuffer for each HardwareRegister per Chip.
293 *
294 * The HardwareRegister keys will just be pointers to the isolation
295 * objects created in the main initialize() API. Those should exist
296 * until the main uninitialize() API is called. It is important that the
297 * cache is flushed at the beginning of the uninitialize() API before
298 * the rest of the isolation objects are deleted.
299 *
300 * The Chip keys are copies of the objects passed to the isolator
301 * because the user application is responsible for storage of the
302 * objects passed to the isolator. We don't want to chance a Chip was
303 * created as a local variable that goes out of scope, or other similar
304 * situations.
305 */
306 std::map<Chip, std::map<const HardwareRegister*, BitString*>> iv_cache;
307 };
308
309 /** This allows all HardwareRegister objects access to the cache. */
310 static Cache cv_cache;
311
312 public: // Register cache management functions.
313
314 /** @brief Flushes the entire register cache. */
315 static void flushAll() { cv_cache.flush(); }
316
317 private: // Register cache management functions.
318
319 /** @return True if an entry for this register exist in this cache. */
320 bool queryCache() const
321 {
322 return cv_cache.query( getAccessorChip(), this );
323 }
324
325 /** @return A reference to this register's BitString in cache. */
326 BitString & accessCache() const
327 {
328 return cv_cache.access( getAccessorChip(), this );
329 }
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500330};
331
Zane Shelley871adec2019-07-30 11:01:39 -0500332} // end namespace libhei
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500333