TEMU  4.2
The Terma Emulator
Memory.h
Go to the documentation of this file.
1 //===------------------------------------------------------------*- C++ -*-===//
2 //
3 // TEMU: The Terma Emulator
4 // (c) Terma 2015
5 // Authors: Mattias Holm <maho (at) terma.com>
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef TEMU_MEMORY_IF_H
10 #define TEMU_MEMORY_IF_H
11 
12 #include "temu-c/Support/Memory.h"
13 #include "temu-c/Support/Objsys.h"
14 #include <stdbool.h>
15 #include <stdint.h>
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 typedef enum {
22  teIT_Cpu, //!< Memory transaction initiated by CPU
23  teIT_Device, //!< Memory transaction initiated by device
24  teIT_Unknown, //!< Memory transaction initiator unknown
25 } temu_InitiatorType;
26 typedef enum {
27  teME_BigEndian, //!< Memory access interface in big endian
28  teME_LittleEndian, //!< Memory access interface in little endian
29  teME_UnspecifiedEndian, //!< Memory access interface in undefined endian
30 } temu_MemoryEndianness;
31 // Memory transaction flags
32 #define TEMU_MT_CACHEABLE 1
33 #define TEMU_MT_BYPASS_CACHE (1 << 1)
34 #define TEMU_MT_FORCE_CACHE_MISS (1 << 2)
35 #define TEMU_MT_FAILED (1 << 3)
36 #define TEMU_MT_CACHE_HIT (1 << 4)
37 
38 #define TEMU_MT_PRIV_SHIFT (5)
39 
40 #define TEMU_MT_PRIV_MASK (7 << 5)
41 #define TEMU_MT_PRIV_USER (0 << 5)
42 #define TEMU_MT_PRIV_SUPER (1 << 5)
43 #define TEMU_MT_PRIV_HYPER (2 << 5)
44 // Note that we reserve an extra privilege level bit for future extension
45 
46 // Probing memory transaction, this is used to probe the memory system without
47 // actually triggering any faults
48 #define TEMU_MT_PROBE (1 << 8)
49 #define TEMU_MT_SELF_MODIFYING (1 << 9)
50 
51 // Bit 10 is used to indicate the endianness of the transaction.
52 // The memory space will automatically swap the bytes when it arrives at a
53 // device that is mapped as the opposite endianness. Note that swapping is done
54 // when arriving at the end point device, not when passing through nested memory
55 // spaces. Swapping is only done for small transactions, larger transactions
56 // must be swapped by the the target device itself. For large transactions we
57 // also need a "target endianness" / "host endianness".
58 
59 // Small transactions (i.e. those where the payload fit in Value):
60 // Always in host endianness when initiating, but have a "virtual endianness".
61 // Memory space swaps the endianness automatically.
62 // Large transactions:
63 // The value actually contains a pointer to a datablock
64 // The datablock may be in host endianness, or in target endianness
65 // Used for for example DMA transfers or transfers of bytes in the sim (image loading etc)
66 // Usually:
67 // - Data transfer in bytes of target endianness (image loading)
68 // - Transfers of memory blocks of words which the sim need to interpret (send lists)
69 // - Transfers of memory blocks of words of data
70 #define TEMU_MT_ENDIAN_BIT 10
71 #define TEMU_MT_BIG_ENDIAN (0 << 10)
72 #define TEMU_MT_LITTLE_ENDIAN (1 << 10)
73 static inline bool
74 temu_hasDifferentEndianness(uint32_t a, uint32_t b)
75 {
76  return ((a ^ b) >> 10) & 1;
77 }
78 
79 #define TEMU_MT_ISA_0 (0 << 11)
80 #define TEMU_MT_ISA_1 (1 << 11)
81 #define TEMU_MT_ISA_2 (2 << 11)
82 
83 #define TEMU_MT_GET_ISA(flags) ((flags >> 11) & 7)
84 
85 #define TEMU_MT_PROF_ACCESS (1 << 13)
86 #define TEMU_MT_PROF_ACCESS_BIT 13
87 
88 // Bypass builtin protections (e.g. write protections for ROM memories)
89 // This simplifies the use of large transactions for implementing ROM loading functionality
90 #define TEMU_MT_BYPASS_PROT (1 << 14)
91 
92 #define TEMU_MT_READ (1 << 15)
93 #define TEMU_MT_WRITE (1 << 16)
94 
95 // Lock flags controlling split memory transaction locks.
96 // These are especially important for atomics, where the read op should lock,
97 // and the write op should release.
98 #define TEMU_MT_LOCK_ACQUIRE (1 << 17)
99 #define TEMU_MT_LOCK_RELEASE (1 << 18)
100 #define TEMU_MT_LOCK_ACQUIRE_AND_RELEASE (3 << 17)
101 #define TEMU_MT_CHECK_FETCH_ATTRIBS (1 << 19)
102 
103 //! Generic memory transaction.
104 //!
105 //! This type is kept in sync with the emulator core. The layout is guaranteed.
106 //! and will remain as is, although more fields may be added (at the bottom).
107 //!
108 //! When the emulator core issues a memory transaction (assuming no ATC hit),
109 //! the core allocates this structure on the stack and fills in some of the
110 //! fields with default values. The memory transaction is passed by pointer or
111 //! reference. By filling in the different fields you can adapt the result of
112 //! the memory transaction.
113 typedef struct temu_MemTransaction {
114  uint64_t Va; //!< 64 bit virtual for unified 32/64 bit interface.
115  uint64_t Pa; //!< 64 bit physical address
116 
117  //! Resulting value (or written value). On MMIO Reads the model
118  //! fills in this value, and on writes the written value will be
119  //! stored here.
120  uint64_t Value;
121 
122  //! Two-logarithm of the size of the transaction in bytes it is at
123  //! most the size of the CPUs max bus size. In case of SPARCv8, this
124  //! is 4 bytes (double words are issued as two accesses). As this
125  //! is the 2-log of the size in bytes, a single byte access will
126  //! have a size of 0, a 2 byte transaction will have size 1, a 4
127  //! byte transaction will have size 2 and an 8 byte transaction will
128  //! have size 3.
129  //!
130  //! In TEMU3 this field was changed to an uint64_t from uint8_t. This
131  //! as it does not add any additional space. And we can repurpose value and
132  //! size as follows:
133  //! - The lower 2 bits define the base unit of the transaction (same as
134  //! before), 0 => 1 byte, 1 => 2 bytes, 2 => 4 bytes, 3 => 8 bytes.
135  //! - The upper bits define the number of transferred units 0 implies
136  //! one unit.
137  //! If the transferred units is more than 0, we are dealing with a large
138  //! transaction. These can be used by e.g. RAM models for block transfers etc.
139  //! In that case the Value field is to be reinterpreted as a pointer to the
140  //! location of the data. This means that we can use the memory access
141  //! interface to e.g. read out send lists and similar items.
142  //!
143  //! The memory space must thus have a way of determining which type of
144  //! transaction is legal. The MemoryAccessIface has been extended with a
145  //! capability query, which if implemented has the ability to query for
146  //! supported features.
147  uint64_t Size;
148 
149  //! Used for device models, this will be filled in with the offset
150  //! from the start address of the device (note it is in practice
151  //! possible to add a device at multiple locations (which happens in
152  //! some rare cases)).
153  uint64_t Offset;
154 
155  //! InitiatorType identifies the type of object starting the transaction.
156  //! this is only relevant when Initiator is set to non-null, and allows
157  //! for the specification of device pointers in the initator. This field
158  //! is new in TEMU 2.2. The field was introduced to support the
159  //! implementation of I/O MMUs.
160  temu_InitiatorType InitiatorType;
161  //! Initiator of the transaction (a CPU object). It can be null,
162  //! which indicate that the transaction was not initiated by normal
163  //! CPU activity (e.g. fetch, read or write). When the initiator is
164  //! null, models should not attempt to stop the processor core, go
165  //! to idle mode or raise traps (posting events is fine). An example
166  //! when the initiator is null is when an MMU does a table walk. The
167  //! MMU will normally special case handle table walks which access
168  //! un-mapped memory.
170  //! Page pointer (for caching), this can be filled in by a memory
171  //! model to have the emulator core inject the page translation in
172  //! the ATC. If a model sets this, the page pointer will
173  //! automatically be cleared if the page has attributes
174  //! (breakpoints, etc). Models that implement normal memory mapped
175  //! registers should NOT populate the page pointer.
176  void *Page;
177  uint64_t Cycles; //!< Cycle cost for memory access (initialised to 0).
178  uint32_t Flags; //!< Flags for use in the memory hierarchy.
179 
180  void *IR; //!< Intermediate code for interpreter (internally managed do not
181  //!< modify)
182  void *Meta;
183 } temu_MemTransaction;
184 
185 // Fetch capabilities
186 #define TEMU_MEM_ACCESS_CAP_F8 (1 << 0)
187 #define TEMU_MEM_ACCESS_CAP_F16 (1 << 1)
188 #define TEMU_MEM_ACCESS_CAP_F32 (1 << 2)
189 #define TEMU_MEM_ACCESS_CAP_F64 (1 << 3)
190 #define TEMU_MEM_ACCESS_CAP_F_ALL (0xf)
191 
192 // Read
193 #define TEMU_MEM_ACCESS_CAP_R8 (1 << (0 + 4))
194 #define TEMU_MEM_ACCESS_CAP_R16 (1 << (1 + 4))
195 #define TEMU_MEM_ACCESS_CAP_R32 (1 << (2 + 4))
196 #define TEMU_MEM_ACCESS_CAP_R64 (1 << (3 + 4))
197 #define TEMU_MEM_ACCESS_CAP_R_ALL (0xf << 4)
198 
199 // Write
200 #define TEMU_MEM_ACCESS_CAP_W8 (1 << (0 + 8))
201 #define TEMU_MEM_ACCESS_CAP_W16 (1 << (1 + 8))
202 #define TEMU_MEM_ACCESS_CAP_W32 (1 << (2 + 8))
203 #define TEMU_MEM_ACCESS_CAP_W64 (1 << (3 + 8))
204 #define TEMU_MEM_ACCESS_CAP_W_ALL (0xf << 8)
205 
206 // Exchange
207 #define TEMU_MEM_ACCESS_CAP_E8 (1 << (0 + 12))
208 #define TEMU_MEM_ACCESS_CAP_E16 (1 << (1 + 12))
209 #define TEMU_MEM_ACCESS_CAP_E32 (1 << (2 + 12))
210 #define TEMU_MEM_ACCESS_CAP_E64 (1 << (3 + 12))
211 #define TEMU_MEM_ACCESS_CAP_E_ALL (0xf << 12)
212 
213 typedef struct {
214  uint16_t TransactionBaseSizes; //!< Flags indicating legal transaction sizes
215  uint16_t
216  LargeTransactions : 1; //!< Supports large transactions (e.g. RAM/ROM)
217  temu_MemoryKind Kind; //!< Mapping type
218  temu_MemoryEndianness Endianness; //!< Endianess of transaction interface
219 } temu_MemAccessCapabilities;
220 
221 //! Memory access interface implemented by all memory mapped devices
222 //! Exposed to the emulator core by a memory object.
224  //! Function called on fetches. The function can be null in case
225  //! fetches are not allowed from the model.
226  void (*fetch)(void *Obj, temu_MemTransaction *Mt);
227 
228  //! Function called on reads.
229  void (*read)(void *Obj, temu_MemTransaction *Mt);
230 
231  //! Function called on writes.
232  void (*write)(void *Obj, temu_MemTransaction *Mt);
233 
234  //! Function called on atomic exchanges, by default if this is not
235  //! defined, the memory space will call read followed by write in
236  //! order.
237  void (*exchange)(void *Obj, temu_MemTransaction *Mt);
238 
239  //! Optional method, called when interface is mapped
240  void (*mapped)(void *Obj, uint64_t Pa, uint64_t Len);
241 
242  //! Query for supported features
243  //! Function is optional. By default the assumption is that
244  //! the base capabilities are equal to R_ALL | W_ALL, custom memories
245  //! must explicitly register itself as fetchable memory.
246  //! in addition, the default assumption is that the device does not
247  //! support large transactions.
248  const temu_MemAccessCapabilities *(*getCapabilities)(void *Obj);
249 
250  //! Probe access
251  //! Must be implemented for RAM and ROM models
252  //! When probing the memory subsystem,
253  //! the transaction is not supposed to trigger semantics.
254  //! Instead the models should populate the memory transaction contents,
255  //! with metadata.
256  //! Thus a probe should for example fill in the page pointer, IR pointer, etc.
257  //! To support correct probing for atomic transactions, probes should handle
258  //! the TEMU_MT_READ and TEMU_MT_WRITE bits.
259  void (*probe)(void *Obj, temu_MemTransaction *Mt);
260 };
261 #define TEMU_MEM_ACCESS_IFACE_TYPE "MemAccessIface"
262 TEMU_IFACE_REFERENCE_TYPE(temu_MemAccess);
263 
264 //! For objects which have actualm memory (not just registers) This is
265 //! for the simulator (not the emu core). The procedures should write
266 //! the data given in bytes to the given physical offset. The offset
267 //! is a 64 bit uint to support 64 bit targets. The interface is used
268 //! for example by DMA transactions.
269 //!
270 //! The size argument is in bytes.
271 //!
272 //! The swap argument is used to swap bytes to the host
273 //! endianess. Specify the log size of the read data types.
274 //! - 0: We are reading bytes (bytes will be in target memory order)
275 //! - 1: We are reading half words (will be swapped to host order)
276 //! - 2: We are reading words (will be swapped)
277 //! - 3: We are reading double words (will be swapped)
278 //! With 0 for swap, we are basically reading a byte array
279 //!
280 //! readBytes and writeBytes should return the number of bytes
281 //! read / written or negative on error.
282 
283 typedef struct temu_MemoryIface {
284  int (*readBytes)(void *Obj, void *Dest, uint64_t Offs, uint32_t Size,
285  int Swap);
286  int (*writeBytes)(void *Obj, uint64_t Offs, uint32_t Size, const void *Src,
287  int Swap);
288 } temu_MemoryIface;
289 #define TEMU_MEMORY_IFACE_TYPE "MemoryIface"
290 TEMU_IFACE_REFERENCE_TYPE(temu_Memory);
291 
292 /*!
293  * Map memory object into address space
294  * \param Obj The memory space object
295  * \param Addr Physical address where to map the device
296  * \param Len Length in bytes of area where the object is mapped.
297  * \param MemObj The memory object. This object must correspond to the
298  * MemAccessIface
299  * \result Zero on success, other values indicates that the mapping failed
300  */
301 int temu_mapMemorySpace(void *Obj, uint64_t Addr, uint64_t Len,
302  temu_Object_ *MemObj);
303 
304 /*!
305  * Map memory object into address space with flags
306  * \param Obj The memory space object
307  * \param Addr Physical address where to map the device
308  * \param Len Length in bytes of area where the object is mapped.
309  * \param MemObj The memory object. This object must correspond to the
310  * MemAccessIface
311  * \param Flags Sticky flags for memory accesses to that object (e.g. cachable)
312  * \result Zero on success, other values indicates that the mapping failed
313  */
314 int temu_mapMemorySpaceFlags(void *Obj, uint64_t Addr, uint64_t Len,
315  temu_Object_ *MemObj, uint32_t Flags);
316 
317 /*!
318  * Set attribute on memory space location
319  * \param Obj The memory space object
320  * \param Addr Physical address where to map the device
321  * \param Len Length in bytes of area where the attribute should be set.
322  * \param Attr The attribute to set.
323  */
324 
325 void temu_setMemAttr(void *Obj, uint64_t Addr, uint64_t Len,
326  temu_MemoryAttr Attr);
327 
328 /*!
329  * Clear attribute on memory space location
330  * \param Obj The memory space object
331  * \param Addr Physical address where to map the device
332  * \param Len Length in bytes of area where the attribute should be set.
333  * \param Attr The attribute to clear.
334  */
335 void temu_clearMemAttr(void *Obj, uint64_t Addr, uint64_t Len,
336  temu_MemoryAttr Attr);
337 
338 
343 
344 #ifdef __cplusplus
345 }
346 #endif
347 
348 #endif /* ! TEMU_MEMORY_IF_H */
temu_MemAccessIface::exchange
void(* exchange)(void *Obj, temu_MemTransaction *Mt)
Definition: Memory.h:237
temu_MemAccessIface::mapped
void(* mapped)(void *Obj, uint64_t Pa, uint64_t Len)
Optional method, called when interface is mapped.
Definition: Memory.h:240
teME_BigEndian
@ teME_BigEndian
Memory access interface in big endian.
Definition: Memory.h:27
temu_MemAccessIface::probe
void(* probe)(void *Obj, temu_MemTransaction *Mt)
Definition: Memory.h:259
temu_MemAccessIface
struct temu_MemAccessIface temu_MemAccessIface
Definition: Memory.h:51
temu_memoryWriteTransaction
int temu_memoryWriteTransaction(void *Obj, temu_MemTransaction *MT)
temu_MemAccessCapabilities::LargeTransactions
uint16_t LargeTransactions
Supports large transactions (e.g. RAM/ROM)
Definition: Memory.h:216
temu_MemTransaction
struct temu_MemTransaction temu_MemTransaction
Definition: Debugger.h:21
teME_LittleEndian
@ teME_LittleEndian
Memory access interface in little endian.
Definition: Memory.h:28
teIT_Device
@ teIT_Device
Memory transaction initiated by device.
Definition: Memory.h:23
temu_MemTransaction::Page
void * Page
Definition: Memory.h:176
temu_memoryExchangeTransaction
int temu_memoryExchangeTransaction(void *Obj, temu_MemTransaction *MT)
temu_MemAccessCapabilities::Kind
temu_MemoryKind Kind
Mapping type.
Definition: Memory.h:217
temu_MemoryIface
Definition: Memory.h:283
temu_MemTransaction::Cycles
uint64_t Cycles
Cycle cost for memory access (initialised to 0).
Definition: Memory.h:177
temu_MemoryIface::readBytes
int(* readBytes)(void *Obj, void *Dest, uint64_t Offs, uint32_t Size, int Swap)
Definition: Memory.h:284
temu_MemTransaction::Value
uint64_t Value
Definition: Memory.h:120
temu_MemTransaction::Pa
uint64_t Pa
64 bit physical address
Definition: Memory.h:115
temu_mapMemorySpace
int temu_mapMemorySpace(void *Obj, uint64_t Addr, uint64_t Len, temu_Object_ *MemObj)
temu_MemAccessCapabilities::Endianness
temu_MemoryEndianness Endianness
Endianess of transaction interface.
Definition: Memory.h:218
teME_UnspecifiedEndian
@ teME_UnspecifiedEndian
Memory access interface in undefined endian.
Definition: Memory.h:29
temu_MemTransaction::Flags
uint32_t Flags
Flags for use in the memory hierarchy.
Definition: Memory.h:178
temu_MemTransaction::IR
void * IR
Definition: Memory.h:180
teIT_Cpu
@ teIT_Cpu
Memory transaction initiated by CPU.
Definition: Memory.h:22
temu_mapMemorySpaceFlags
int temu_mapMemorySpaceFlags(void *Obj, uint64_t Addr, uint64_t Len, temu_Object_ *MemObj, uint32_t Flags)
temu_MemTransaction::Initiator
temu_Object_ * Initiator
Definition: Memory.h:169
temu_memoryReadTransaction
int temu_memoryReadTransaction(void *Obj, temu_MemTransaction *MT)
temu_MemTransaction::Meta
void * Meta
Definition: Memory.h:182
temu_MemTransaction::Va
uint64_t Va
64 bit virtual for unified 32/64 bit interface.
Definition: Memory.h:114
temu_MemAccessIface::fetch
void(* fetch)(void *Obj, temu_MemTransaction *Mt)
Definition: Memory.h:226
temu_memoryFetchTransaction
int temu_memoryFetchTransaction(void *Obj, temu_MemTransaction *MT)
temu_MemTransaction::Offset
uint64_t Offset
Definition: Memory.h:153
temu_MemAccessIface::read
void(* read)(void *Obj, temu_MemTransaction *Mt)
Function called on reads.
Definition: Memory.h:229
temu_MemTransaction::Size
uint64_t Size
Definition: Memory.h:147
teIT_Unknown
@ teIT_Unknown
Memory transaction initiator unknown.
Definition: Memory.h:24
temu_MemAccessCapabilities::TransactionBaseSizes
uint16_t TransactionBaseSizes
Flags indicating legal transaction sizes.
Definition: Memory.h:214
temu_clearMemAttr
void temu_clearMemAttr(void *Obj, uint64_t Addr, uint64_t Len, temu_MemoryAttr Attr)
temu_setMemAttr
void temu_setMemAttr(void *Obj, uint64_t Addr, uint64_t Len, temu_MemoryAttr Attr)
temu_MemoryIface::writeBytes
int(* writeBytes)(void *Obj, uint64_t Offs, uint32_t Size, const void *Src, int Swap)
Definition: Memory.h:286
temu_MemTransaction::InitiatorType
temu_InitiatorType InitiatorType
Definition: Memory.h:160
temu_MemAccessIface::write
void(* write)(void *Obj, temu_MemTransaction *Mt)
Function called on writes.
Definition: Memory.h:232