Marking of more classes, might get rid of in the future and optimize; Implement shrin...
[SquirrelJME.git] / ratufacoat / src / sjmercvm.c
blobc1950b44df196a27b739d4dc8cd3159776422c32
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // --------------------------------------------------------------------------*/
10 /**
11 * Virtual memory functions.
13 * @since 2019/06/25
16 #include "sjmerc.h"
18 /** Base of virtual memory. */
19 #define SJME_VIRTUAL_MEM_BASE SJME_JINT_C(1048576)
21 /** Rounding of virtual memory. */
22 #define SJME_VIRTUAL_MEM_MASK SJME_JINT_C(1023)
24 /** Virtual memory information. */
25 struct sjme_vmem
27 /** The number of mappings. */
28 sjme_jint count;
30 /** The next address for allocations. */
31 sjme_jint nextaddr;
33 /** Mappings. */
34 sjme_vmemmap** maps;
37 /** Creates a new virtual memory manager. */
38 sjme_vmem* sjme_vmmnew(sjme_error* error)
40 sjme_vmem* rv;
42 /* Try to allocate space. */
43 rv = sjme_malloc(sizeof(*rv));
44 if (rv == NULL)
46 sjme_seterror(error, SJME_ERROR_NOMEMORY, sizeof(*rv));
48 return NULL;
51 /* Initialize. */
52 rv->nextaddr = SJME_VIRTUAL_MEM_BASE;
54 return rv;
57 /** Virtually maps the given region of memory. */
58 sjme_vmemmap* sjme_vmmmap(sjme_vmem* vmem, sjme_jint at, void* ptr,
59 sjme_jint size, sjme_error* error)
61 sjme_vmemmap* rv;
62 sjme_vmemmap** newmaps;
63 sjme_jint i;
65 (void)at;
67 /* Invalid argument. */
68 if (vmem == NULL || ptr == NULL || size <= 0)
70 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
72 return NULL;
75 /* Allocate return value. */
76 rv = sjme_malloc(sizeof(*rv));
77 newmaps = sjme_malloc(sizeof(*newmaps) * (vmem->count + 1));
78 if (rv == NULL)
80 sjme_seterror(error, SJME_ERROR_NOMEMORY, sizeof(*rv));
82 sjme_free(rv);
83 sjme_free(newmaps);
85 return NULL;
88 /* Copy and set new mappings. */
89 for (i = 0; i < vmem->count; i++)
90 newmaps[i] = vmem->maps[i];
91 newmaps[vmem->count] = rv;
93 /* Setup mapping. */
94 rv->realptr = (uintptr_t)ptr;
95 rv->fakeptr = vmem->nextaddr;
96 rv->size = size;
98 /* Store the mappings (remember to free the old ones!). */
99 vmem->nextaddr = (vmem->nextaddr + size + SJME_VIRTUAL_MEM_MASK) &
100 (~SJME_VIRTUAL_MEM_MASK);
101 vmem->count = vmem->count + 1;
102 sjme_free(vmem->maps);
103 vmem->maps = newmaps;
105 return rv;
108 /** Resolves the given true memory address. */
109 void* sjme_vmmresolve(sjme_vmem* vmem, sjme_vmemptr ptr, sjme_jint off,
110 sjme_error* error)
112 sjme_jint i, n, moff;
113 sjme_vmemmap* map;
114 sjme_vmemptr optr;
115 uintptr_t mp;
117 /* Invalid argument. */
118 if (vmem == NULL)
120 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
122 return NULL;
125 /* Get true pointer position. */
126 optr = ptr + off;
128 /* Search for the mapping. */
129 for (i = 0, n = vmem->count; i < n; i++)
131 /* Get mapping. */
132 map = vmem->maps[i];
134 /* Calculate the mapping offset. */
135 moff = optr - map->fakeptr;
137 /* Is in range? */
138 if (moff >= 0 && moff < map->size)
140 /* If this mapping is banked, make sure it is mapped. */
141 if (map->bank != NULL)
143 /* Load the bank into memory. */
144 mp = map->bank(&moff);
146 /* Return from the base mapping using the returned offset. */
147 return (void*)(mp + moff);
150 /* Otherwise, use direct memory access. */
151 return (void*)(map->realptr + moff);
155 /* Address is not valid. */
156 sjme_seterror(error, SJME_ERROR_BADADDRESS, optr);
157 return NULL;
160 /** Convert size to Java type. */
161 sjme_jint sjme_vmmsizetojavatype(sjme_jint size, sjme_error* error)
163 /* Convert. */
164 switch (size)
166 case 1:
167 return SJME_VMMTYPE_BYTE;
169 case 2:
170 return SJME_VMMTYPE_JAVASHORT;
172 case 4:
173 return SJME_VMMTYPE_JAVAINTEGER;
176 /* Not valid. */
177 sjme_seterror(error, SJME_ERROR_INVALIDSIZE, size);
178 return 0;
181 /** Convert size to type. */
182 sjme_jint sjme_vmmsizetotype(sjme_jint size, sjme_error* error)
184 /* Convert. */
185 switch (size)
187 case 1:
188 return SJME_VMMTYPE_BYTE;
190 case 2:
191 return SJME_VMMTYPE_SHORT;
193 case 4:
194 return SJME_VMMTYPE_INTEGER;
197 /* Not valid. */
198 sjme_seterror(error, SJME_ERROR_INVALIDSIZE, size);
199 return 0;
202 /** Reads from virtual memory. */
203 sjme_jint sjme_vmmread(sjme_vmem* vmem, sjme_jint type, sjme_vmemptr ptr,
204 sjme_jint off, sjme_error* error)
206 void* realptr;
207 sjme_error xerror;
209 /* Invalid argument? */
210 if (vmem == NULL)
212 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
214 return 0;
217 /* Need error. */
218 if (error == NULL)
220 memset(&xerror, 0, sizeof(xerror));
221 error = &xerror;
224 /* Resolve address. */
225 realptr = sjme_vmmresolve(vmem, ptr, off, error);
226 if (realptr == NULL)
228 if (error->code == SJME_ERROR_NONE)
229 sjme_seterror(error, SJME_ERROR_ADDRRESFAIL, ptr + off);
231 return 0;
234 /* Depends on the type. */
235 switch (type)
237 case SJME_VMMTYPE_BYTE:
238 return *((sjme_jbyte*)realptr);
240 #if defined(SJME_BIG_ENDIAN)
241 case SJME_VMMTYPE_SHORT:
242 case SJME_VMMTYPE_JAVASHORT:
243 return *((sjme_jshort*)realptr);
244 #else
245 case SJME_VMMTYPE_SHORT:
246 return *((sjme_jshort*)realptr);
248 case SJME_VMMTYPE_JAVASHORT:
249 type = *((sjme_jshort*)realptr);
250 type = (type & SJME_JINT_C(0xFFFF0000)) |
251 (((type << SJME_JINT_C(8)) & SJME_JINT_C(0xFF00)) |
252 ((type >> SJME_JINT_C(8)) & SJME_JINT_C(0x00FF)));
253 return type;
254 #endif
256 #if defined(SJME_BIG_ENDIAN)
257 case SJME_VMMTYPE_INTEGER:
258 case SJME_VMMTYPE_JAVAINTEGER:
259 return *((sjme_jint*)realptr);
260 #else
261 case SJME_VMMTYPE_INTEGER:
262 return *((sjme_jint*)realptr);
264 case SJME_VMMTYPE_JAVAINTEGER:
265 type = *((sjme_jint*)realptr);
266 type = (((type >> SJME_JINT_C(24)) & SJME_JINT_C(0x000000FF)) |
267 ((type >> SJME_JINT_C(8)) & SJME_JINT_C(0x0000FF00)) |
268 ((type << SJME_JINT_C(8)) & SJME_JINT_C(0x00FF0000)) |
269 ((type << SJME_JINT_C(24)) & SJME_JINT_C(0xFF000000)));
270 return type;
271 #endif
273 default:
274 sjme_seterror(error, SJME_ERROR_INVALIDMEMTYPE, type);
275 return 0;
279 /** Reads from virtual memory. */
280 sjme_jint sjme_vmmreadp(sjme_vmem* vmem, sjme_jint type, sjme_vmemptr* ptr,
281 sjme_error* error)
283 sjme_jint rv;
285 /* Read value. */
286 rv = sjme_vmmread(vmem, type, *ptr, 0, error);
288 /* Increment pointer. */
289 switch (type)
291 case SJME_VMMTYPE_BYTE:
292 *ptr = *ptr + 1;
293 break;
295 case SJME_VMMTYPE_SHORT:
296 case SJME_VMMTYPE_JAVASHORT:
297 *ptr = *ptr + 2;
298 break;
300 case SJME_VMMTYPE_INTEGER:
301 case SJME_VMMTYPE_JAVAINTEGER:
302 *ptr = *ptr + 4;
303 break;
306 /* Return value. */
307 return rv;
310 /** Write to virtual memory. */
311 void sjme_vmmwrite(sjme_vmem* vmem, sjme_jint type, sjme_vmemptr ptr,
312 sjme_jint off, sjme_jint val, sjme_error* error)
314 void* realptr;
315 sjme_error xerror;
317 /* Invalid argument? */
318 if (vmem == NULL)
320 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
322 return;
325 /* Need error. */
326 if (error == NULL)
328 memset(&xerror, 0, sizeof(xerror));
329 error = &xerror;
332 /* Resolve address. */
333 realptr = sjme_vmmresolve(vmem, ptr, off, error);
334 if (realptr == NULL)
336 if (error->code == SJME_ERROR_NONE)
337 sjme_seterror(error, SJME_ERROR_ADDRRESFAIL, ptr + off);
339 return;
342 /* Depends on the type. */
343 switch (type)
345 case SJME_VMMTYPE_BYTE:
346 *((sjme_jbyte*)realptr) = (sjme_jbyte)val;
347 return;
349 case SJME_VMMTYPE_JAVASHORT:
350 #if defined(SJME_LITTLE_ENDIAN)
351 val = (val & SJME_JINT_C(0xFFFF0000)) |
352 (((val << SJME_JINT_C(8)) & SJME_JINT_C(0xFF00)) |
353 ((val >> SJME_JINT_C(8)) & SJME_JINT_C(0x00FF)));
354 #endif
355 case SJME_VMMTYPE_SHORT:
356 *((sjme_jshort*)realptr) = (sjme_jshort)val;
357 return;
359 case SJME_VMMTYPE_JAVAINTEGER:
360 #if defined(SJME_LITTLE_ENDIAN)
361 val = (((val >> SJME_JINT_C(24)) & SJME_JINT_C(0x000000FF)) |
362 ((val >> SJME_JINT_C(8)) & SJME_JINT_C(0x0000FF00)) |
363 ((val << SJME_JINT_C(8)) & SJME_JINT_C(0x00FF0000)) |
364 ((val << SJME_JINT_C(24)) & SJME_JINT_C(0xFF000000)));
365 #endif
366 case SJME_VMMTYPE_INTEGER:
367 *((sjme_jint*)realptr) = (sjme_jint)val;
368 return;
370 default:
371 sjme_seterror(error, SJME_ERROR_INVALIDMEMTYPE, type);
372 return;
376 /** Write to virtual memory. */
377 void sjme_vmmwritep(sjme_vmem* vmem, sjme_jint type, sjme_vmemptr* ptr,
378 sjme_jint val, sjme_error* error)
380 sjme_jint rv;
382 /* Write value. */
383 sjme_vmmwrite(vmem, type, *ptr, 0, val, error);
385 /* Increment pointer. */
386 switch (type)
388 case SJME_VMMTYPE_BYTE:
389 *ptr = *ptr + 1;
390 break;
392 case SJME_VMMTYPE_SHORT:
393 case SJME_VMMTYPE_JAVASHORT:
394 *ptr = *ptr + 2;
395 break;
397 case SJME_VMMTYPE_INTEGER:
398 case SJME_VMMTYPE_JAVAINTEGER:
399 *ptr = *ptr + 4;
400 break;
404 /** Atomically reads, checks, and then sets the value. */
405 sjme_jint sjme_vmmatomicintcheckgetandset(sjme_vmem* vmem, sjme_jint check,
406 sjme_jint set, sjme_vmemptr ptr, sjme_jint off, sjme_error* error)
408 sjme_jint rv;
410 /* Invalid argument? */
411 if (vmem == NULL)
413 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
415 return 0;
418 /* Read current value. */
419 rv = sjme_vmmread(vmem, SJME_VMMTYPE_INTEGER, ptr, off, error);
421 /* If value is the same, set it. */
422 if (rv == check)
423 sjme_vmmwrite(vmem, SJME_VMMTYPE_INTEGER, ptr, off, set, error);
425 /* Return the value. */
426 return rv;
429 /** Atomically increments and integer and then gets its value. */
430 sjme_jint sjme_vmmatomicintaddandget(sjme_vmem* vmem,
431 sjme_vmemptr ptr, sjme_jint off, sjme_jint add, sjme_error* error)
433 sjme_jint rv;
435 /* Invalid argument? */
436 if (vmem == NULL)
438 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
440 return 0;
443 /* Read current value. */
444 rv = sjme_vmmread(vmem, SJME_VMMTYPE_INTEGER, ptr, off, error);
446 /* Add value. */
447 rv += add;
449 /* Store new value. */
450 sjme_vmmwrite(vmem, SJME_VMMTYPE_INTEGER, ptr, off, rv, error);
452 /* Return new value. */
453 return rv;