TEMU  4.4
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 #define TEMU_MT_ALLOC_IR (1 << 20)
104 #define TEMU_MT_FORCE_REBIND (1 << 21)
105 
106 //! Generic memory transaction.
107 //!
108 //! This type is kept in sync with the emulator core. The layout is guaranteed.
109 //! and will remain as is, although more fields may be added (at the bottom).
110 //!
111 //! When the emulator core issues a memory transaction (assuming no ATC hit),
112 //! the core allocates this structure on the stack and fills in some of the
113 //! fields with default values. The memory transaction is passed by pointer or
114 //! reference. By filling in the different fields you can adapt the result of
115 //! the memory transaction.
116 typedef struct temu_MemTransaction {
117  uint64_t Va; //!< 64 bit virtual for unified 32/64 bit interface.
118  uint64_t Pa; //!< 64 bit physical address
119 
120  //! Resulting value (or written value). On MMIO Reads the model
121  //! fills in this value, and on writes the written value will be
122  //! stored here.
123  uint64_t Value;
124 
125  //! Two-logarithm of the size of the transaction in bytes it is at
126  //! most the size of the CPUs max bus size. In case of SPARCv8, this
127  //! is 4 bytes (double words are issued as two accesses). As this
128  //! is the 2-log of the size in bytes, a single byte access will
129  //! have a size of 0, a 2 byte transaction will have size 1, a 4
130  //! byte transaction will have size 2 and an 8 byte transaction will
131  //! have size 3.
132  //!
133  //! In TEMU3 this field was changed to an uint64_t from uint8_t. This
134  //! as it does not add any additional space. And we can repurpose value and
135  //! size as follows:
136  //! - The lower 2 bits define the base unit of the transaction (same as
137  //! before), 0 => 1 byte, 1 => 2 bytes, 2 => 4 bytes, 3 => 8 bytes.
138  //! - The upper bits define the number of transferred units 0 implies
139  //! one unit.
140  //! If the transferred units is more than 0, we are dealing with a large
141  //! transaction. These can be used by e.g. RAM models for block transfers etc.
142  //! In that case the Value field is to be reinterpreted as a pointer to the
143  //! location of the data. This means that we can use the memory access
144  //! interface to e.g. read out send lists and similar items.
145  //!
146  //! The memory space must thus have a way of determining which type of
147  //! transaction is legal. The MemoryAccessIface has been extended with a
148  //! capability query, which if implemented has the ability to query for
149  //! supported features.
150  uint64_t Size;
151 
152  //! Used for device models, this will be filled in with the offset
153  //! from the start address of the device (note it is in practice
154  //! possible to add a device at multiple locations (which happens in
155  //! some rare cases)).
156  uint64_t Offset;
157 
158  //! InitiatorType identifies the type of object starting the transaction.
159  //! this is only relevant when Initiator is set to non-null, and allows
160  //! for the specification of device pointers in the initator. This field
161  //! is new in TEMU 2.2. The field was introduced to support the
162  //! implementation of I/O MMUs.
163  temu_InitiatorType InitiatorType;
164  //! Initiator of the transaction (a CPU object). It can be null,
165  //! which indicate that the transaction was not initiated by normal
166  //! CPU activity (e.g. fetch, read or write). When the initiator is
167  //! null, models should not attempt to stop the processor core, go
168  //! to idle mode or raise traps (posting events is fine). An example
169  //! when the initiator is null is when an MMU does a table walk. The
170  //! MMU will normally special case handle table walks which access
171  //! un-mapped memory.
173  //! Page pointer (for caching), this can be filled in by a memory
174  //! model to have the emulator core inject the page translation in
175  //! the ATC. If a model sets this, the page pointer will
176  //! automatically be cleared if the page has attributes
177  //! (breakpoints, etc). Models that implement normal memory mapped
178  //! registers should NOT populate the page pointer.
179  void *Page;
180  uint64_t Cycles; //!< Cycle cost for memory access (initialised to 0).
181  uint32_t Flags; //!< Flags for use in the memory hierarchy.
182 
183  void *IR; //!< Intermediate code for interpreter (internally managed do not
184  //!< modify)
185  void *Meta;
186 } temu_MemTransaction;
187 
188 // Fetch capabilities
189 #define TEMU_MEM_ACCESS_CAP_F8 (1 << 0)
190 #define TEMU_MEM_ACCESS_CAP_F16 (1 << 1)
191 #define TEMU_MEM_ACCESS_CAP_F32 (1 << 2)
192 #define TEMU_MEM_ACCESS_CAP_F64 (1 << 3)
193 #define TEMU_MEM_ACCESS_CAP_F_ALL (0xf)
194 
195 // Read
196 #define TEMU_MEM_ACCESS_CAP_R8 (1 << (0 + 4))
197 #define TEMU_MEM_ACCESS_CAP_R16 (1 << (1 + 4))
198 #define TEMU_MEM_ACCESS_CAP_R32 (1 << (2 + 4))
199 #define TEMU_MEM_ACCESS_CAP_R64 (1 << (3 + 4))
200 #define TEMU_MEM_ACCESS_CAP_R_ALL (0xf << 4)
201 
202 // Write
203 #define TEMU_MEM_ACCESS_CAP_W8 (1 << (0 + 8))
204 #define TEMU_MEM_ACCESS_CAP_W16 (1 << (1 + 8))
205 #define TEMU_MEM_ACCESS_CAP_W32 (1 << (2 + 8))
206 #define TEMU_MEM_ACCESS_CAP_W64 (1 << (3 + 8))
207 #define TEMU_MEM_ACCESS_CAP_W_ALL (0xf << 8)
208 
209 // Exchange
210 #define TEMU_MEM_ACCESS_CAP_E8 (1 << (0 + 12))
211 #define TEMU_MEM_ACCESS_CAP_E16 (1 << (1 + 12))
212 #define TEMU_MEM_ACCESS_CAP_E32 (1 << (2 + 12))
213 #define TEMU_MEM_ACCESS_CAP_E64 (1 << (3 + 12))
214 #define TEMU_MEM_ACCESS_CAP_E_ALL (0xf << 12)
215 
216 typedef struct {
217  uint16_t TransactionBaseSizes; //!< Flags indicating legal transaction sizes
218  uint16_t
219  LargeTransactions : 1; //!< Supports large transactions (e.g. RAM/ROM)
220  temu_MemoryKind Kind; //!< Mapping type
221  temu_MemoryEndianness Endianness; //!< Endianess of transaction interface
222 } temu_MemAccessCapabilities;
223 
224 //! Memory access interface implemented by all memory mapped devices
225 //! Exposed to the emulator core by a memory object.
227  //! Function called on fetches. The function can be null in case
228  //! fetches are not allowed from the model.
229  void (*fetch)(void *Obj, temu_MemTransaction *Mt);
230 
231  //! Function called on reads.
232  void (*read)(void *Obj, temu_MemTransaction *Mt);
233 
234  //! Function called on writes.
235  void (*write)(void *Obj, temu_MemTransaction *Mt);
236 
237  //! Function called on atomic exchanges, by default if this is not
238  //! defined, the memory space will call read followed by write in
239  //! order.
240  void (*exchange)(void *Obj, temu_MemTransaction *Mt);
241 
242  //! Optional method, called when interface is mapped
243  void (*mapped)(void *Obj, uint64_t Pa, uint64_t Len);
244 
245  //! Query for supported features
246  //! Function is optional. By default the assumption is that
247  //! the base capabilities are equal to R_ALL | W_ALL, custom memories
248  //! must explicitly register itself as fetchable memory.
249  //! in addition, the default assumption is that the device does not
250  //! support large transactions.
251  const temu_MemAccessCapabilities *(*getCapabilities)(void *Obj);
252 
253  //! Probe access
254  //! Must be implemented for RAM and ROM models
255  //! When probing the memory subsystem,
256  //! the transaction is not supposed to trigger semantics.
257  //! Instead the models should populate the memory transaction contents,
258  //! with metadata.
259  //! Thus a probe should for example fill in the page pointer, IR pointer, etc.
260  //! To support correct probing for atomic transactions, probes should handle
261  //! the TEMU_MT_READ and TEMU_MT_WRITE bits.
262  void (*probe)(void *Obj, temu_MemTransaction *Mt);
263 };
264 #define TEMU_MEM_ACCESS_IFACE_TYPE "MemAccessIface"
265 TEMU_IFACE_REFERENCE_TYPE(temu_MemAccess);
266 
267 //! For objects which have actualm memory (not just registers) This is
268 //! for the simulator (not the emu core). The procedures should write
269 //! the data given in bytes to the given physical offset. The offset
270 //! is a 64 bit uint to support 64 bit targets. The interface is used
271 //! for example by DMA transactions.
272 //!
273 //! The size argument is in bytes.
274 //!
275 //! The swap argument is used to swap bytes to the host
276 //! endianess. Specify the log size of the read data types.
277 //! - 0: We are reading bytes (bytes will be in target memory order)
278 //! - 1: We are reading half words (will be swapped to host order)
279 //! - 2: We are reading words (will be swapped)
280 //! - 3: We are reading double words (will be swapped)
281 //! With 0 for swap, we are basically reading a byte array
282 //!
283 //! readBytes and writeBytes should return the number of bytes
284 //! read / written or negative on error.
285 
286 typedef struct temu_MemoryIface {
287  int (*readBytes)(void *Obj, void *Dest, uint64_t Offs, uint32_t Size,
288  int Swap);
289  int (*writeBytes)(void *Obj, uint64_t Offs, uint32_t Size, const void *Src,
290  int Swap);
291 } temu_MemoryIface;
292 #define TEMU_MEMORY_IFACE_TYPE "MemoryIface"
293 TEMU_IFACE_REFERENCE_TYPE(temu_Memory);
294 
295 /*!
296  * Map memory object into address space
297  * \param Obj The memory space object
298  * \param Addr Physical address where to map the device
299  * \param Len Length in bytes of area where the object is mapped.
300  * \param MemObj The memory object. This object must correspond to the
301  * MemAccessIface
302  * \result Zero on success, other values indicates that the mapping failed
303  */
304 int temu_mapMemorySpace(void *Obj, uint64_t Addr, uint64_t Len,
305  temu_Object_ *MemObj);
306 
307 /*!
308  * Map memory object into address space with flags
309  * \param Obj The memory space object
310  * \param Addr Physical address where to map the device
311  * \param Len Length in bytes of area where the object is mapped.
312  * \param MemObj The memory object. This object must correspond to the
313  * MemAccessIface
314  * \param Flags Sticky flags for memory accesses to that object (e.g. cachable)
315  * \result Zero on success, other values indicates that the mapping failed
316  */
317 int temu_mapMemorySpaceFlags(void *Obj, uint64_t Addr, uint64_t Len,
318  temu_Object_ *MemObj, uint32_t Flags);
319 
320 /*!
321  * Set attribute on memory space location
322  * \param Obj The memory space object
323  * \param Addr Physical address where to map the device
324  * \param Len Length in bytes of area where the attribute should be set.
325  * \param Attr The attribute to set.
326  */
327 
328 void temu_setMemAttr(void *Obj, uint64_t Addr, uint64_t Len,
329  temu_MemoryAttr Attr);
330 
331 /*!
332  * Clear attribute on memory space location
333  * \param Obj The memory space object
334  * \param Addr Physical address where to map the device
335  * \param Len Length in bytes of area where the attribute should be set.
336  * \param Attr The attribute to clear.
337  */
338 void temu_clearMemAttr(void *Obj, uint64_t Addr, uint64_t Len,
339  temu_MemoryAttr Attr);
340 
341 
346 
347 #ifdef __cplusplus
348 }
349 #endif
350 
351 #endif /* ! TEMU_MEMORY_IF_H */
temu_MemAccessIface::exchange
void(* exchange)(void *Obj, temu_MemTransaction *Mt)
Definition: Memory.h:240
temu_MemAccessIface::mapped
void(* mapped)(void *Obj, uint64_t Pa, uint64_t Len)
Optional method, called when interface is mapped.
Definition: Memory.h:243
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:262
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:219
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:179
temu_memoryExchangeTransaction
int temu_memoryExchangeTransaction(void *Obj, temu_MemTransaction *MT)
temu_MemAccessCapabilities::Kind
temu_MemoryKind Kind
Mapping type.
Definition: Memory.h:220
temu_MemoryIface
Definition: Memory.h:286
temu_MemTransaction::Cycles
uint64_t Cycles
Cycle cost for memory access (initialised to 0).
Definition: Memory.h:180
temu_MemoryIface::readBytes
int(* readBytes)(void *Obj, void *Dest, uint64_t Offs, uint32_t Size, int Swap)
Definition: Memory.h:287
temu_MemTransaction::Value
uint64_t Value
Definition: Memory.h:123
temu_MemTransaction::Pa
uint64_t Pa
64 bit physical address
Definition: Memory.h:118
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:221
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:181
temu_MemTransaction::IR
void * IR
Definition: Memory.h:183
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:172
temu_memoryReadTransaction
int temu_memoryReadTransaction(void *Obj, temu_MemTransaction *MT)
temu_MemTransaction::Meta
void * Meta
Definition: Memory.h:185
temu_MemTransaction::Va
uint64_t Va
64 bit virtual for unified 32/64 bit interface.
Definition: Memory.h:117
temu_MemAccessIface::fetch
void(* fetch)(void *Obj, temu_MemTransaction *Mt)
Definition: Memory.h:229
temu_memoryFetchTransaction
int temu_memoryFetchTransaction(void *Obj, temu_MemTransaction *MT)
temu_MemTransaction::Offset
uint64_t Offset
Definition: Memory.h:156
temu_MemAccessIface::read
void(* read)(void *Obj, temu_MemTransaction *Mt)
Function called on reads.
Definition: Memory.h:232
temu_MemTransaction::Size
uint64_t Size
Definition: Memory.h:150
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:217
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:289
temu_MemTransaction::InitiatorType
temu_InitiatorType InitiatorType
Definition: Memory.h:163
temu_MemAccessIface::write
void(* write)(void *Obj, temu_MemTransaction *Mt)
Function called on writes.
Definition: Memory.h:235