SH4ZAM! 0.8.0
Fast math library for the Sega Dreamcast's SH4 CPU
Loading...
Searching...
No Matches
shz_mem.h
Go to the documentation of this file.
1/*! \file
2 * \brief Memory API
3 * \ingroup memory
4 *
5 * API built around copying, assigning, and working with memory.
6 *
7 * \todo
8 * - shz_macw()
9 * - shz_memset2()
10 * - shz_memset4()
11 * - shz_memset32()
12 * - shz_memset()
13 * - shz_memmoveN()
14 *
15 * \author 2025, 2026 Falco Girgis
16 * \author 2020 MoopTheHedgehog
17 *
18 * \copyright MIT License
19 */
20
21#ifndef SHZ_MEM_H
22#define SHZ_MEM_H
23
24#include "shz_cdefs.h"
25
26#include <stdbool.h>
27#include <stddef.h>
28
29/*! \defgroup memory Memory
30 \brief Routines for managing memory.
31
32 This API provides the following types of memory routines:
33 - special instruction intrinsics
34 - cache operations
35 - memcpy()-type routines
36
37 \note
38 memcpy()-like routines will typically always check for
39 proper alignment and size increments of parameters using
40 assert(), so make sure to build a release build (-DNDEBUG)
41 for maximal gainz, when not debugging.
42 */
43
44 //! Used to prepopulate the cache line mapping to the given address, before it is used.
45 #define SHZ_PREFETCH(ptr) SHZ_PREFETCH_(ptr)
46
47SHZ_DECLS_BEGIN
48
49/*! \name C stdlib Replacements
50 \brief Routine replacing the C standard library copy/set API.
51 @{
52*/
53
54/*! Generic drop-in fast memcpy() replacement.
55
56 Copies \p bytes from \p src to \p dst, determining the most efficient
57 specialization to call into at run-time, returning \p dst.
58
59 There are no alignment or size requirements for this routine, but it is
60 specifically optimized for 2-, 4-, 8-, and 32-byte alignments, with
61 bigger alignments bringing bigger gainz.
62
63 \note
64 When you know of and can control the \p src and \p dst alignments and
65 batch sizes, you can micro-optimize by calling into the most specific
66 memcpy() specialization for your given scenario, over just using this
67 generic implementation, which must choose which one to use at run-time.
68
69 \warning
70 \p dst and \p src buffers should not be overlapping.
71
72 \sa shz_memcpy1(), shz_memcpy2(), shz_memcpy4(), shz_memcpy8(), shz_memcpy32(),
73 shz_memcpy64(), shz_memcpy128()
74*/
75SHZ_INLINE void* shz_memcpy( void* SHZ_RESTRICT dst,
76 const void* SHZ_RESTRICT src,
77 size_t bytes) SHZ_NOEXCEPT;
78
79/*! Generic drop-in fast memmove() replacement.
80
81 Copies \p bytes from \p src to \p dst, determining the most efficient
82 specialization to call into at run-time, return \p dst. The source and
83 destination buffers are allowed to overlap, making this routine slightly
84 less efficient, but more versatile than shz_memcpy().
85
86 There is no alignment or size requirement for this routine.
87
88 \sa shz_memcpy()
89*/
90SHZ_INLINE void* shz_memmove(void* dst, const void* src, size_t bytes) SHZ_NOEXCEPT;
91
92//! @}
93
94/*! \name Specializations
95 \brief Specialized routines for specific sizes + alignments.
96 @{
97*/
98
99/*! Copies an unaligned buffer to another one byte at a time.
100
101 The \p dst pointer is returned.
102
103 \note
104 Typically, unless you know you are copying a tiny number of
105 definitely unaligned bytes, you want to use shz_memcpy(),
106 which automatically handles arbitrary alignment for you,
107 potentially more efficiently than copying byte-by-byte.
108
109 \warning
110 \p dst and \p src buffers should not be overlapping.
111
112 \sa shz_memcpy()
113*/
114SHZ_INLINE void* shz_memcpy1( void* SHZ_RESTRICT dst,
115 const void* SHZ_RESTRICT src,
116 size_t bytes) SHZ_NOEXCEPT;
117
118/*! Copies from one 2-byte aligned buffer to another two bytes at a time.
119
120 The \p dst pointer is returned.
121
122 \warning
123 \p dst and \p src must both be aligned by at least 2 bytes, and \p bytes
124 must be a multiple of 2.
125
126 \warning
127 \p dst and \p src buffers should not be overlapping.
128*/
129SHZ_INLINE void* shz_memcpy2( void* SHZ_RESTRICT dst,
130 const void* SHZ_RESTRICT src,
131 size_t bytes) SHZ_NOEXCEPT;
132
133/*! Copies a from one 4-byte aligned buffer to another 4 bytes at a time.
134
135 The \p dst buffer is returned.
136
137 \warning
138 \p dst and \p src must both be aligned by at least 4 bytes, and
139 \p bytes must be a multiple of 4.
140
141 \warning
142 \p dst and \p src buffers should not be overlapping.
143*/
144SHZ_INLINE void* shz_memcpy4( void* SHZ_RESTRICT dst,
145 const void* SHZ_RESTRICT src,
146 size_t bytes) SHZ_NOEXCEPT;
147
148/*! Copies a from one 8-byte aligned buffer to another 8 bytes at a time.
149
150 The \p dst buffer is returned.
151
152 \warning
153 \p dst and \p src must both be aligned by at least 8 bytes, and
154 \p bytes must be a multiple of 8.
155
156 \warning
157 \p src and \p dst should not overlap.
158*/
159SHZ_INLINE void* shz_memcpy8( void* SHZ_RESTRICT dst,
160 const void* SHZ_RESTRICT src,
161 size_t bytes) SHZ_NOEXCEPT;
162
163/*! Assigns the given 8-byte \p value to the \p bytes in \p dst.
164
165 \warning
166 \p dst should be at least 8-byte aligned, and \p bytes should be
167 a multiple of 8!
168*/
169SHZ_INLINE void* shz_memset8(void* dst, uint64_t value, size_t bytes) SHZ_NOEXCEPT;
170
171/*! Copies \p bytes from the \p src to the \p dst buffer in 32-byte chunks.
172
173 Transfers from 8-byte aligned buffer, \p src to 32-byte aligned buffer, \p dst,
174 32 bytes at a time. Returns the \p dst address.
175
176 \warning
177 \p dst must be 32-byte aligned, while \p src can be only 8-byte aligned. \p bytes must
178 be a multiple of 32.
179
180 \warning
181 \p src and \p dst buffers must not overlap.
182
183 \note
184 This is the quickest way to move 32-byte chunks of data around *within memory*, but
185 the shz_sq_memcpy32() will be faster when writing through the cache to external memory.
186
187 \sa shz_sq_memcpy32()
188*/
189SHZ_INLINE void* shz_memcpy32( void* SHZ_RESTRICT dst,
190 const void* SHZ_RESTRICT src,
191 size_t bytes) SHZ_NOEXCEPT;
192
193/*! Copies \p bytes from \p src to \p dst in 32-byte chunks, using the Store Queues.
194
195 Transfers from 8-byte aligned buffer, \p src to 4-byte aligned address, \p dst,
196 32 bytes at a time, writing through the cache, using the SH4's Store Queues.
197 Returns the \p dst address.
198
199 \warning
200 \p src must be at least 8-byte aligned, while \p dst can be only 4-byte aligned.
201 \p bytes must be a multiple of 32.
202
203 \note
204 This is the quickest way to move 32-byte chunks of data to *external memory*.
205 When copying to cached memory, you must invalidate the cache lines containing
206 \p dst before initiating the copy... Which means this routine becomes slower
207 than doing memory-to-memory copies with shz_memcpy32().
208
209 \sa shz_memcpy32(), shz_sq_memcpy32_1()
210*/
211SHZ_INLINE void* shz_sq_memcpy32( void* SHZ_RESTRICT dst,
212 const void* SHZ_RESTRICT src,
213 size_t bytes) SHZ_NOEXCEPT;
214
215/*! Copies \p bytes from \p src to \p dst in 32-byte chunks, using the Store Queues and XMTRX.
216
217 Equiavalent to shz_sq_memcpy32(), except copying is done through XMTRX.
218
219 \warning
220 This routine clobbers XMTRX.
221*/
222SHZ_INLINE void* shz_sq_memcpy32_xmtrx( void* SHZ_RESTRICT dst,
223 const void* SHZ_RESTRICT src,
224 size_t bytes) SHZ_NOEXCEPT;
225
226/*! Specialized memcpy() variant for copying multiples of 64-bytes.
227
228 Copies a from an 8-byte aligned buffer to a 32-byte aligned buffer, 64 bytes at a time.
229 Returns the \p dst address.
230
231 \warning
232 \p src and \p dst buffers must not overlap.
233
234 \warning
235 \p dst must be 32-byte aligned, while \p src can be only 8-byte aligned. \p bytes must
236 be a multiple of 64.
237*/
238SHZ_INLINE void* shz_memcpy64( void* SHZ_RESTRICT dst,
239 const void* SHZ_RESTRICT src,
240 size_t bytes) SHZ_NOEXCEPT;
241
242/*! Specialized memcpy() variant for copying multiples of 128 bytes.
243
244 Copies a from an 8-byte aligned buffer to a 32-byte aligned buffer, 128 bytes at a time.
245 Returns the \p dst address.
246
247 \warning
248 \p src and \p dst buffers must not overlap.
249
250 \warning
251 \p dst must be 32-byte aligned, while \p src can be only 8-byte aligned. \p bytes must
252 be a multiple of 128.
253*/
254SHZ_INLINE void* shz_memcpy128( void* SHZ_RESTRICT dst,
255 const void* SHZ_RESTRICT src,
256 size_t bytes) SHZ_NOEXCEPT;
257
258//! @}
259
260/*! \name Constant-sized Operations
261 \brief Specialized routines for operating on statically sized buffers.
262 @{
263*/
264
265/*! Copies 8 shorts from \p src to \p dst.
266
267 \warning
268 \p src and \p dst buffers must not overlap.
269
270 \warning
271 \p dst and \p src must both be aligned by at least two bytes.
272*/
273SHZ_INLINE void shz_memcpy2_8( void* SHZ_RESTRICT dst,
274 const void* SHZ_RESTRICT src) SHZ_NOEXCEPT;
275
276/*! Copies 16 shorts from \p src to \p dst.
277
278 \warning
279 \p src and \p dst buffers must not overlap.
280
281 \warning
282 \p dst and \p src must both be aligned by at least two bytes.
283*/
284SHZ_INLINE void shz_memcpy2_16( void* SHZ_RESTRICT dst,
285 const void* SHZ_RESTRICT src) SHZ_NOEXCEPT;
286
287/*! Sets the values of the 16 shorts pointed to by \p dst to the given \p value.
288
289 \warning
290 \p dst must be aligned by at least two bytes.
291*/
292SHZ_INLINE void shz_memset2_16(void* dst, uint16_t value) SHZ_NOEXCEPT;
293
294/*! Copies 16 4-byte, long values from \p src to \p dst.
295
296 \warning
297 \p src and \p dst buffers must not overlap.
298
299 \warning
300 The \p src and \p dst buffers must both be at least 4-byte aligned.
301*/
302SHZ_INLINE void shz_memcpy4_16( void* SHZ_RESTRICT dst,
303 const void* SHZ_RESTRICT src) SHZ_NOEXCEPT;
304
305/*! Copies 32 bytes from \p p1 to \p p2 as a single chunk.
306
307 \warning
308 \p dst must be 32-byte aligned, while \p src can be only 8-byte aligned.
309*/
310SHZ_INLINE void shz_memcpy32_1( void* SHZ_RESTRICT dst,
311 const void* SHZ_RESTRICT src) SHZ_NOEXCEPT;
312
313/*! Swaps the values within the given 32-byte buffers.
314
315 \warning
316 \p p1 and \p p2 must be at least 8-byte aligned.
317*/
318SHZ_INLINE void shz_memswap32_1(void* SHZ_RESTRICT p1,
319 void* SHZ_RESTRICT p2) SHZ_NOEXCEPT;
320
321/*! Swaps the values within the given 32-byte buffers, using XMTRX.
322
323 Equivalent to shz_memcpy32_1(), except copying is done through XMTRX.
324
325 \warning
326 This routine clobbers XMTRX!
327*/
328SHZ_INLINE void shz_memswap32_1_xmtrx(void* SHZ_RESTRICT p1,
329 void* SHZ_RESTRICT p2) SHZ_NOEXCEPT;
330
331/*! Copies \p src to \p dst in a single 32-byte transaction using the Store Queues.
332
333 \note
334 The Store Queues bypass the SH4's data-cache! They are typically used to
335 transfer to *external memory* and are slower for memory-to-memory transactions.
336
337 \warning
338 \p dst must be at least 4-byte aligned, while \p src must be at least 8-byte aligned.
339
340 \sa shz_memcpy32()
341*/
342SHZ_INLINE void* shz_sq_memcpy32_1( void* SHZ_RESTRICT dst,
343 const void* SHZ_RESTRICT src) SHZ_NOEXCEPT;
344
345
346/*! Copies \p src to \p dst in a single 32-byte transaction using the Store Queues and XMTRX.
347
348 Equivalent to shz_sq_memcpy32_1(), except copying is done through XMTRX.
349
350 \warning
351 This routine clobberx XMTRX.
352
353 \sa shz_memcpy32()
354*/
355SHZ_INLINE void* shz_sq_memcpy32_1_xmtrx( void* SHZ_RESTRICT dst,
356 const void* SHZ_RESTRICT src) SHZ_NOEXCEPT;
357
358/*! Intrinsic around the SH4 `MOVCA.L` instruction.
359
360 Preallocates the cache-line containing \p src.
361
362 Zero-initializes all 32-bytes within the \p src cache-line,
363 setting the valid bit to `1`.
364*/
365SHZ_INLINE void shz_dcache_alloc_line(void* src) SHZ_NOEXCEPT;
366
367//! @}
368
369#include "inline/shz_mem.inl.h"
370
371SHZ_DECLS_END
372
373#endif
void * shz_memset8(void *dst, uint64_t value, size_t bytes) SHZ_NOEXCEPT
Assigns the given 8-byte value to the bytes in dst.
void * shz_memcpy4(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Copies a from one 4-byte aligned buffer to another 4 bytes at a time.
void * shz_sq_memcpy32_xmtrx(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Copies bytes from src to dst in 32-byte chunks, using the Store Queues and XMTRX.
void * shz_sq_memcpy32(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Copies bytes from src to dst in 32-byte chunks, using the Store Queues.
void shz_memcpy2_16(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src) SHZ_NOEXCEPT
Copies 16 shorts from src to dst.
void shz_memswap32_1_xmtrx(void *SHZ_RESTRICT p1, void *SHZ_RESTRICT p2) SHZ_NOEXCEPT
Swaps the values within the given 32-byte buffers, using XMTRX.
void * shz_sq_memcpy32_1(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src) SHZ_NOEXCEPT
Copies src to dst in a single 32-byte transaction using the Store Queues.
void shz_memcpy2_8(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src) SHZ_NOEXCEPT
Copies 8 shorts from src to dst.
void shz_memswap32_1(void *SHZ_RESTRICT p1, void *SHZ_RESTRICT p2) SHZ_NOEXCEPT
Swaps the values within the given 32-byte buffers.
void shz_dcache_alloc_line(void *src) SHZ_NOEXCEPT
Intrinsic around the SH4 MOVCA.L instruction.
void * shz_memcpy2(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Copies from one 2-byte aligned buffer to another two bytes at a time.
void * shz_sq_memcpy32_1_xmtrx(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src) SHZ_NOEXCEPT
Copies src to dst in a single 32-byte transaction using the Store Queues and XMTRX.
void * shz_memmove(void *dst, const void *src, size_t bytes) SHZ_NOEXCEPT
Generic drop-in fast memmove() replacement.
void * shz_memcpy64(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Specialized memcpy() variant for copying multiples of 64-bytes.
void * shz_memcpy1(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Copies an unaligned buffer to another one byte at a time.
void * shz_memcpy(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Generic drop-in fast memcpy() replacement.
void shz_memcpy32_1(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src) SHZ_NOEXCEPT
Copies 32 bytes from p1 to p2 as a single chunk.
void shz_memcpy4_16(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src) SHZ_NOEXCEPT
Copies 16 4-byte, long values from src to dst.
void * shz_memcpy32(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Copies bytes from the src to the dst buffer in 32-byte chunks.
void shz_memset2_16(void *dst, uint16_t value) SHZ_NOEXCEPT
Sets the values of the 16 shorts pointed to by dst to the given value.
void * shz_memcpy8(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Copies a from one 8-byte aligned buffer to another 8 bytes at a time.
void * shz_memcpy128(void *SHZ_RESTRICT dst, const void *SHZ_RESTRICT src, size_t bytes) SHZ_NOEXCEPT
Specialized memcpy() variant for copying multiples of 128 bytes.