Drop parameter annotations since we do not need them.
[SquirrelJME.git] / ratufacoat / src / sjmerc.c
blobd75efb60d3da39820055d39784fc7658ca5df2d3
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 * SquirrelJME RatufaCoat Source.
13 * @since 2019/06/02
16 #include "sjmerc.h"
17 #include "sjmecon.h"
18 #include "sjmebsqf.h"
19 #include "sjmevdef.h"
21 /** Sets the error code. */
22 void sjme_seterror(sjme_error* error, sjme_jint code, sjme_jint value)
24 if (error != NULL)
26 error->code = code;
27 error->value = value;
31 /**
32 * Decodes an integer value from operations which could be unaligned.
34 * @param vmem Virtual memory.
35 * @param ptr The pointer to read from.
36 * @param error Error flag.
37 * @return The resulting read value.
38 * @since 2019/06/16
40 sjme_jint sjme_opdecodejint(sjme_vmem* vmem, sjme_vmemptr* ptr,
41 sjme_error* error)
43 sjme_jint rv;
45 /* Read all values. */
46 rv = (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
47 SJME_JINT_C(0xFF)) << 24;
48 rv |= (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
49 SJME_JINT_C(0xFF)) << 16;
50 rv |= (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
51 SJME_JINT_C(0xFF)) << 8;
52 rv |= (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
53 SJME_JINT_C(0xFF));
55 return rv;
58 /**
59 * Decodes a short value from operations which could be unaligned.
61 * @param vmem Virtual memory.
62 * @param ptr The pointer to read from.
63 * @param error Error flag.
64 * @return The resulting read value.
65 * @since 2019/06/16
67 sjme_jint sjme_opdecodejshort(sjme_vmem* vmem, sjme_vmemptr* ptr,
68 sjme_error* error)
70 sjme_jint rv;
72 /* Read all values. */
73 rv = (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
74 SJME_JINT_C(0xFF)) << 8;
75 rv |= (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
76 SJME_JINT_C(0xFF));
78 /* Sign extend? */
79 if (rv & SJME_JINT_C(0x8000))
80 rv |= SJME_JINT_C(0xFFFF0000);
82 return rv;
85 /**
86 * Decodes a variable unsigned int operation argument.
88 * @param vmem Virtual memory.
89 * @param ptr The pointer to read from.
90 * @param error Error flag.
91 * @return The resulting decoded value.
92 * @since 2019/06/09
94 sjme_jint sjme_opdecodeui(sjme_vmem* vmem, sjme_vmemptr* ptr,
95 sjme_error* error)
97 sjme_jint rv;
99 /* Read single byte value from pointer. */
100 rv = (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
101 SJME_JINT_C(0xFF));
103 /* Encoded as a 15-bit value? */
104 if ((rv & SJME_JINT_C(0x80)) != 0)
106 rv = (rv & SJME_JINT_C(0x7F)) << SJME_JINT_C(8);
107 rv |= (sjme_vmmreadp(vmem, SJME_VMMTYPE_BYTE, ptr, error) &
108 SJME_JINT_C(0xFF));
111 /* Use read value. */
112 return rv;
116 * Decodes register from the virtual machine.
118 * @param vmem Virtual memory.
119 * @param ptr The pointer to read from.
120 * @param error Error flag.
121 * @return The resulting register value.
122 * @since 2019/06/25
124 sjme_jint sjme_opdecodereg(sjme_vmem* vmem, sjme_vmemptr* ptr,
125 sjme_error* error)
127 sjme_jint rv;
129 /* Decode register. */
130 rv = sjme_opdecodeui(vmem, ptr, error);
132 /* Keep within register bound. */
133 if (rv < 0 || rv >= SJME_MAX_REGISTERS)
135 sjme_seterror(error, SJME_ERROR_REGISTEROVERFLOW, rv);
137 return 0;
140 /* Return it. */
141 return rv;
145 * Decodes a relative jump offset.
147 * @param vmem Virtual memory.
148 * @param ptr The pointer to read from.
149 * @param error Error flag.
150 * @return The resulting relative jump.
151 * @since 2019/06/13
153 sjme_jint sjme_opdecodejmp(sjme_vmem* vmem, sjme_vmemptr* ptr,
154 sjme_error* error)
156 sjme_jint rv;
158 /* Decode value. */
159 rv = sjme_opdecodeui(vmem, ptr, error);
161 /* Negative branch? */
162 if ((rv & SJME_JINT_C(0x00004000)) != 0)
163 return rv | SJME_JINT_C(0xFFFF8000);
164 return rv;
167 /** Draws single character onto the console. */
168 void sjme_console_drawplate(sjme_jvm* jvm, sjme_jint x, sjme_jint y,
169 sjme_jbyte ch, sjme_error* error)
171 sjme_jint r, c, cv, i, fontw, fonth, xform;
172 sjme_vmemptr sp;
173 sjme_jbyte* mp;
174 sjme_jbyte bits;
175 sjme_jint bpp, pq, at, mask;
177 /* Check. */
178 if (jvm == NULL)
179 return;
181 /* Ignore if out of bounds. */
182 if (x < 0 || y < 0 || x >= jvm->conw || y >= jvm->conh)
183 return;
185 /* Font dimensions. */
186 fontw = sjme_font.charwidths[0];
187 fonth = sjme_font.pixelheight;
189 /* Normalize to screen space. */
190 x = x * fontw;
191 y = y * fonth;
193 /* Character data to draw. */
194 if (sjme_font.isvalidchar[ch] == 0)
195 ch = 0;
196 mp = &sjme_font.charbmp[((sjme_jint)ch) * fonth * sjme_font.bytesperscan];
198 /* Drawing format for the data value? */
199 bpp = jvm->fbinfo->bitsperpixel;
200 switch (bpp)
202 case 1:
203 case 2:
204 case 4:
205 case 8:
206 xform = SJME_VMMTYPE_BYTE;
207 mask = (SJME_JINT_C(1) << bpp) - 1;
208 break;
210 case 16:
211 xform = SJME_VMMTYPE_SHORT;
212 mask = SJME_JINT_C(0xFFFF);
213 break;
215 case 32:
216 xform = SJME_VMMTYPE_INTEGER;
217 mask = SJME_JINT_C(0xFFFFFFFF);
218 break;
221 /* Draw rows. */
222 for (r = 0; r < fonth; r++)
224 /* Determine screen position. */
225 sp = jvm->framebuffer->fakeptr +
226 ((x * jvm->fbinfo->bitsperpixel) / 8) +
227 ((y + r) * (jvm->fbinfo->scanlenbytes));
229 /* Clear pixel queue. */
230 pq = 0;
231 at = 0;
233 /* Draw all pixel scans. */
234 c = 0;
235 for (cv = 0; cv < sjme_font.bytesperscan; cv++, mp++)
237 /* Get character bits */
238 bits = *mp;
240 /* Draw all of them. */
241 for (i = 0; i < 8 && c < fontw; i++, c++)
243 /* Shift the queue up from the last run. */
244 pq <<= bpp;
246 /* Mask it if the color is set? */
247 if ((bits & sjme_drawcharbitmask[i]) != 0)
248 pq |= mask;
250 /* Queued bits go up. */
251 at += bpp;
253 /* Only write when there is at least 8! */
254 if (at >= 8)
256 /* Write. */
257 sjme_vmmwritep(jvm->vmem, xform, &sp, pq, error);
259 /* Cut down. */
260 pq = (((pq & sjme_sh_umask[bpp])) >> bpp);
261 at -= bpp;
266 /* Force draw any pixels left over. */
267 if (at >= bpp)
268 sjme_vmmwritep(jvm->vmem, xform, &sp, pq, error);
272 /** Writes to the console screen and to the native method as well. */
273 sjme_jint sjme_console_pipewrite(sjme_jvm* jvm,
274 sjme_jint (*writefunc)(sjme_jint b), sjme_jbyte* buf, sjme_jint off,
275 sjme_jint len, sjme_error* error)
277 sjme_jbyte b, donewline;
278 sjme_jint i, code;
280 /* There must be a JVM! */
281 if (jvm == NULL)
282 return -1;
284 /* Write all the bytes to the output. */
285 for (i = 0; i < len; i++, off++)
287 /* Read byte. */
288 b = buf[off];
290 /* Draw to the console in supervisor boot mode or if it was not */
291 /* yet squelched. */
292 if ((jvm->supervisorokay == 0 || jvm->squelchfbconsole == 0) &&
293 jvm->fbinfo != NULL)
295 /* Carriage return? */
296 donewline = 0;
297 if (b == '\r')
298 jvm->conx = 0;
300 /* Newline? */
301 else if (b == '\n')
302 donewline = 1;
304 /* Draw character? */
305 else
307 /* Draw it. */
308 sjme_console_drawplate(jvm, jvm->conx, jvm->cony, b, error);
310 /* Move cursor up. */
311 jvm->conx++;
313 /* New line to print on? */
314 if (jvm->conx >= jvm->conw)
315 donewline = 1;
318 /* Doing a new line? */
319 if (donewline != 0)
321 /* Move the cursor to the start of the next line. */
322 jvm->conx = 0;
323 jvm->cony++;
325 /* Too much text on the screen? Move it up! */
326 if (jvm->cony >= jvm->conh)
328 /* Move framebuffer up. */
329 memmove(
330 SJME_POINTER_OFFSET_LONG(jvm->fbinfo->pixels, 0),
331 SJME_POINTER_OFFSET_LONG(jvm->fbinfo->pixels,
332 sjme_font.pixelheight *
333 (jvm->fbinfo->scanlenbytes)),
334 (jvm->fbinfo->height - sjme_font.pixelheight) *
335 (jvm->fbinfo->scanlenbytes));
337 /* Wipe bytes at the bottom. */
338 memset(
339 SJME_POINTER_OFFSET_LONG(jvm->fbinfo->pixels,
340 (jvm->fbinfo->height - sjme_font.pixelheight) *
341 (jvm->fbinfo->scanlenbytes)), 0,
342 sjme_font.pixelheight * (jvm->fbinfo->scanlenbytes));
344 /* Move the cursor up one line. */
345 jvm->cony--;
349 /* Always flush in debug mode to force screen updates. */
350 if (jvm->fbinfo->flush != NULL)
351 jvm->fbinfo->flush();
354 /* Forward to pipe? */
355 if (writefunc != NULL)
357 code = writefunc(b);
358 if (code < 0)
359 return (i == 0 ? code : i);
363 /* Return written bytes. */
364 return len;
368 * Handles system calls.
370 * @param jvm The JVM.
371 * @param cpu The CPU.
372 * @param error Error state.
373 * @param callid The system call type.
374 * @param args Arguments to the call.
375 * @param rv The return value of the call.
376 * @since 2019/06/09
378 void sjme_syscall(sjme_jvm* jvm, sjme_cpu* cpu, sjme_error* error,
379 sjme_jshort callid, sjme_jint* args, sjme_jlong_combine* rv)
381 sjme_jint* syserr;
382 sjme_jint ia, ib, ic;
383 sjme_jbyte ba;
384 sjme_vmemptr pa;
385 sjme_cpustate* cpustate;
387 /* Called wrong? */
388 if (jvm == NULL || cpu == NULL || args == NULL || rv == NULL)
390 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
392 return;
395 /* Start here. */
396 cpustate = &cpu->state;
398 /* Calculate index to set for system call errors. */
399 syserr = ((callid < 0 || callid >= SJME_SYSCALL_NUM_SYSCALLS) ?
400 &cpu->syscallerr[SJME_SYSCALL_QUERY_INDEX] : &cpu->syscallerr[callid]);
402 /* Depends on the system call. */
403 switch (callid)
405 /* Query support for system call. */
406 case SJME_SYSCALL_QUERY_INDEX:
407 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
408 switch (args[0])
410 case SJME_SYSCALL_BYTE_ORDER_LITTLE:
411 case SJME_SYSCALL_CALL_STACK_HEIGHT:
412 case SJME_SYSCALL_CALL_STACK_ITEM:
413 case SJME_SYSCALL_ERROR_GET:
414 case SJME_SYSCALL_ERROR_SET:
415 case SJME_SYSCALL_EXCEPTION_LOAD:
416 case SJME_SYSCALL_EXCEPTION_STORE:
417 case SJME_SYSCALL_FRAMEBUFFER_PROPERTY:
418 case SJME_SYSCALL_TIME_MILLI_WALL:
419 case SJME_SYSCALL_TIME_NANO_MONO:
420 case SJME_SYSCALL_MEM_SET:
421 case SJME_SYSCALL_MEM_SET_INT:
422 case SJME_SYSCALL_OPTION_JAR_DATA:
423 case SJME_SYSCALL_OPTION_JAR_SIZE:
424 case SJME_SYSCALL_PD_OF_STDERR:
425 case SJME_SYSCALL_PD_OF_STDOUT:
426 case SJME_SYSCALL_PD_WRITE_BYTE:
427 case SJME_SYSCALL_SQUELCH_FB_CONSOLE:
428 case SJME_SYSCALL_SUPERVISOR_BOOT_OKAY:
429 case SJME_SYSCALL_SUPERVISOR_PROPERTY_GET:
430 case SJME_SYSCALL_SUPERVISOR_PROPERTY_SET:
431 case SJME_SYSCALL_FRAME_TASK_ID_GET:
432 case SJME_SYSCALL_FRAME_TASK_ID_SET:
433 rv->lo = SJME_JINT_C(1);
434 return;
437 rv->lo = SJME_JINT_C(0);
438 return;
440 /* Is the byte order little endian? */
441 case SJME_SYSCALL_BYTE_ORDER_LITTLE:
442 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
443 #if defined(SJME_LITTLE_ENDIAN)
444 rv->lo = 1;
445 #else
446 rv->lo = 0;
447 #endif
448 break;
450 /* Height of the call stack. */
451 case SJME_SYSCALL_CALL_STACK_HEIGHT:
452 /* Count trace depth. */
453 ia = 0;
454 while (cpustate != NULL)
456 /* Increase the count. */
457 ia++;
459 /* Go to deeper depth. */
460 cpustate = cpustate->parent;
463 /* Does not generate errors. */
464 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
465 rv->lo = ia;
466 return;
468 /* Item within the call stack. */
469 case SJME_SYSCALL_CALL_STACK_ITEM:
470 /* Find the CPU frame to use. */
471 ia = args[0];
472 while (ia > 0)
474 /* End of CPU? */
475 if (cpustate == NULL)
477 *syserr = SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE;
478 return;
481 /* Drop down. */
482 cpustate = cpustate->parent;
483 ia--;
486 /* Depends on the requested item.*/
487 switch (args[1])
489 /* The class name. */
490 case SJME_CALLSTACKITEM_CLASS_NAME:
491 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
492 rv->lo = cpustate->debugclassname;
493 break;
495 /* The method name. */
496 case SJME_CALLSTACKITEM_METHOD_NAME:
497 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
498 rv->lo = cpustate->debugmethodname;
499 break;
501 /* The method type. */
502 case SJME_CALLSTACKITEM_METHOD_TYPE:
503 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
504 rv->lo = cpustate->debugmethodtype;
505 break;
507 /* Source file. */
508 case SJME_CALLSTACKITEM_SOURCE_FILE:
509 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
510 rv->lo = cpustate->debugsourcefile;
511 break;
513 /* Source line. */
514 case SJME_CALLSTACKITEM_SOURCE_LINE:
515 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
516 rv->lo = cpustate->debugline;
517 break;
519 /* The PC address. */
520 case SJME_CALLSTACKITEM_PC_ADDRESS:
521 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
522 rv->lo = cpustate->pc;
523 break;
525 /* Java operation. */
526 case SJME_CALLSTACKITEM_JAVA_OPERATION:
527 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
528 rv->lo = cpustate->debugjop;
529 break;
531 /* Java PC address. */
532 case SJME_CALLSTACKITEM_JAVA_PC_ADDRESS:
533 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
534 rv->lo = cpustate->debugjpc;
535 break;
537 /* Current Task ID. */
538 case SJME_CALLSTACKITEM_TASK_ID:
539 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
540 rv->lo = cpustate->taskid;
541 break;
543 /* Unknown. */
544 default:
545 *syserr = SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE;
546 return;
548 return;
550 /* Get error state. */
551 case SJME_SYSCALL_ERROR_GET:
552 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
554 ia = args[0];
555 if (ia < 0 || ia >= SJME_SYSCALL_NUM_SYSCALLS)
556 ia = SJME_SYSCALL_QUERY_INDEX;
558 rv->lo = cpu->syscallerr[ia];
559 return;
561 /* Set error state, return old one. */
562 case SJME_SYSCALL_ERROR_SET:
563 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
565 ia = args[0];
566 if (ia < 0 || ia >= SJME_SYSCALL_NUM_SYSCALLS)
567 ia = SJME_SYSCALL_QUERY_INDEX;
569 ib = cpu->syscallerr[ia];
570 cpu->syscallerr[ia] = args[1];
572 rv->lo = ib;
573 return;
575 /* Load IPC Exception. */
576 case SJME_SYSCALL_EXCEPTION_LOAD:
577 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
578 rv->lo = cpu->ipcexception;
579 return;
581 /* Store IPC Exception */
582 case SJME_SYSCALL_EXCEPTION_STORE:
583 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
584 rv->lo = cpu->ipcexception;
585 cpu->ipcexception = args[0];
586 return;
588 /* Gets/sets property of the framebuffer. */
589 case SJME_SYSCALL_FRAMEBUFFER_PROPERTY:
590 /* No framebuffer is defined? */
591 if (jvm->fbinfo == NULL)
593 *syserr = SJME_SYSCALL_ERROR_NO_FRAMEBUFFER;
594 return;
597 /* Depends on the property. */
598 switch (args[0])
600 /* Framebuffer address. */
601 case SJME_FB_CONTROL_ADDRESS:
602 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
603 rv->lo = jvm->framebuffer->fakeptr;
604 break;
606 /* Width of the framebuffer. */
607 case SJME_FB_CONTROL_WIDTH:
608 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
609 rv->lo = jvm->fbinfo->width;
610 break;
612 /* Height of the framebuffer. */
613 case SJME_FB_CONTROL_HEIGHT:
614 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
615 rv->lo = jvm->fbinfo->height;
616 break;
618 /* Scanline length of the framebuffer. */
619 case SJME_FB_CONTROL_SCANLEN:
620 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
621 rv->lo = jvm->fbinfo->scanlen;
622 break;
624 /* Flush the framebuffer. */
625 case SJME_FB_CONTROL_FLUSH:
626 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
627 if (jvm->fbinfo->flush != NULL)
628 jvm->fbinfo->flush();
629 break;
631 /* Frame-buffer format. */
632 case SJME_FB_CONTROL_FORMAT:
633 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
634 rv->lo = jvm->fbinfo->format;
635 break;
637 /* Scanline length in bytes. */
638 case SJME_FB_CONTROL_SCANLEN_BYTES:
639 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
640 rv->lo = jvm->fbinfo->scanlenbytes;
641 break;
643 /* Bytes per pixel. */
644 case SJME_FB_CONTROL_BYTES_PER_PIXEL:
645 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
646 rv->lo = jvm->fbinfo->bitsperpixel / 8;
647 break;
649 /* The number of pixels. */
650 case SJME_FB_CONTROL_NUM_PIXELS:
651 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
652 rv->lo = jvm->fbinfo->numpixels;
653 break;
655 /* Bits per pixels. */
656 case SJME_FB_CONTROL_BITS_PER_PIXEL:
657 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
658 rv->lo = jvm->fbinfo->bitsperpixel;
659 break;
661 /* Unknown property, but there is a framebuffer. */
662 default:
663 *syserr = SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE;
664 return;
667 return;
669 /* Get Task ID. */
670 case SJME_SYSCALL_FRAME_TASK_ID_GET:
671 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
672 rv->lo = cpustate->taskid;
673 return;
675 /* Set Task ID. */
676 case SJME_SYSCALL_FRAME_TASK_ID_SET:
677 cpustate->taskid = args[0];
678 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
679 rv->lo = SJME_JINT_C(1);
680 return;
682 /* Set memory to byte value. */
683 case SJME_SYSCALL_MEM_SET:
684 /* Get address to wipe. */
685 pa = args[0];
687 /* The value to store. */
688 ic = args[1] & SJME_JINT_C(0xFF);
690 /* Wipe these values! */
691 ib = args[2];
692 for (ia = 0; ia < ib; ia++)
693 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_BYTE, pa, ia, ic, error);
695 /* Is okay. */
696 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
697 rv->lo = ib;
698 return;
700 /* Set memory in integer values. */
701 case SJME_SYSCALL_MEM_SET_INT:
702 /* Get address to wipe. */
703 pa = args[0];
705 /* The value to store, is full integer. */
706 ic = args[1];
708 /* Wipe these values! */
709 ib = args[2] & ~SJME_JINT_C(3);
710 for (ia = 0; ia < ib; ia += 4)
711 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_INTEGER, pa, ia, ic,
712 error);
714 /* Is okay. */
715 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
716 rv->lo = ib;
717 return;
719 /* Return pointer to the OptionJAR. */
720 case SJME_SYSCALL_OPTION_JAR_DATA:
721 if (jvm->optionjar == NULL)
723 *syserr = SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE;
724 return;
727 /* Is available. */
728 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
729 rv->lo = jvm->optionjar->fakeptr;
730 return;
732 /* Return size of the OptionJAR. */
733 case SJME_SYSCALL_OPTION_JAR_SIZE:
734 if (jvm->optionjar == NULL)
736 *syserr = SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE;
737 return;
740 /* Is available. */
741 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
742 rv->lo = jvm->optionjar->size;
743 return;
745 /* Pipe descriptor of standard error. */
746 case SJME_SYSCALL_PD_OF_STDERR:
747 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
748 rv->lo = SJME_JINT_C(SJME_PIPE_FD_STDERR);
749 return;
751 /* Pipe descriptor of standard output. */
752 case SJME_SYSCALL_PD_OF_STDOUT:
753 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
754 rv->lo = SJME_JINT_C(SJME_PIPE_FD_STDOUT);
755 return;
757 /* Write single byte to a stream. */
758 case SJME_SYSCALL_PD_WRITE_BYTE:
759 ia = SJME_JINT_C(-1);
761 /* The byte to write. */
762 ba = (sjme_jbyte)args[1];
764 /* Depends on the pipe target. */
765 switch (args[0])
767 /* Standard output. */
768 case SJME_PIPE_FD_STDOUT:
769 ia = sjme_console_pipewrite(jvm,
770 (jvm->nativefuncs != NULL &&
771 jvm->nativefuncs->stdout_write != NULL ?
772 jvm->nativefuncs->stdout_write : NULL), &ba, 0, 1,
773 error);
774 break;
776 /* Standard error. */
777 case SJME_PIPE_FD_STDERR:
778 ia = sjme_console_pipewrite(jvm,
779 (jvm->nativefuncs != NULL &&
780 jvm->nativefuncs->stderr_write != NULL ?
781 jvm->nativefuncs->stderr_write : NULL), &ba, 0, 1,
782 error);
783 break;
785 /* Unknown descriptor. */
786 default:
787 *syserr = SJME_SYSCALL_ERROR_PIPE_DESCRIPTOR_INVALID;
788 rv->lo = SJME_JINT_C(-1);
789 return;
792 /* Write error? */
793 if (ia < 0)
795 *syserr = SJME_SYSCALL_ERROR_PIPE_DESCRIPTOR_INVALID;
796 rv->lo = SJME_JINT_C(-1);
797 return;
800 /* Success. */
801 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
802 rv->lo = SJME_JINT_C(1);
803 return;
805 /* Squelch the framebuffer console. */
806 case SJME_SYSCALL_SQUELCH_FB_CONSOLE:
807 if (jvm->squelchfbconsole == 0)
809 jvm->squelchfbconsole = 1;
810 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
811 rv->lo = SJME_JINT_C(0);
813 return;
815 /* The supervisor booted okay! */
816 case SJME_SYSCALL_SUPERVISOR_BOOT_OKAY:
817 if (jvm->supervisorokay == 0)
819 jvm->supervisorokay = 1;
820 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
821 rv->lo = SJME_JINT_C(0);
823 return;
825 /* Get supervisor property. */
826 case SJME_SYSCALL_SUPERVISOR_PROPERTY_GET:
827 ia = args[0];
828 if (ia < 0 || ia >= SJME_SUPERPROP_NUM_PROPERTIES)
830 *syserr = SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE;
831 return;
833 else
835 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
836 rv->lo = cpu->supervisorprops[ia];
837 return;
840 /* Set supervisor property. */
841 case SJME_SYSCALL_SUPERVISOR_PROPERTY_SET:
842 ia = args[0];
843 if (ia < 0 || ia >= SJME_SUPERPROP_NUM_PROPERTIES)
845 *syserr = SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE;
846 return;
848 else
850 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
851 rv->lo = cpu->supervisorprops[ia] = args[1];
852 return;
855 /* Returns the millisecond wall clock. */
856 case SJME_SYSCALL_TIME_MILLI_WALL:
857 if (jvm->nativefuncs == NULL ||
858 jvm->nativefuncs->millitime == NULL)
860 *syserr = SJME_SYSCALL_ERROR_UNSUPPORTED_SYSTEM_CALL;
861 return;
863 else
865 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
867 rv->lo = jvm->nativefuncs->millitime(&rv->hi);
868 return;
871 /* Returns the nanosecond wall clock. */
872 case SJME_SYSCALL_TIME_NANO_MONO:
873 if (jvm->nativefuncs == NULL ||
874 jvm->nativefuncs->nanotime == NULL)
876 *syserr = SJME_SYSCALL_ERROR_UNSUPPORTED_SYSTEM_CALL;
877 return;
879 else
881 *syserr = SJME_SYSCALL_ERROR_NO_ERROR;
883 rv->lo = jvm->nativefuncs->nanotime(&rv->hi);
884 return;
887 /* Unknown or unsupported system call. */
888 default:
889 *syserr = SJME_SYSCALL_ERROR_UNSUPPORTED_SYSTEM_CALL;
890 return;
894 /** Divides two numbers. */
895 sjme_jint_div sjme_div(sjme_jint anum, sjme_jint aden)
897 /* From Wikipedia (http://en.wikipedia.org/wiki/Division_%28digital%29) */
898 /* if D == 0 then throw DivisionByZeroException end*/
899 /* Q := 0 # initialize quotient and remainder to Zero */
900 /* R := 0 */
901 /* for i = n-1...0 do # " where n is no of bits " */
902 /* R := R << 1 # left-shift R by 1 bit */
903 /* R(0) := N(i) # set the least-significant bit */
904 /* # of R equal to bit i of the numerator */
905 /* if R >= D then */
906 /* R = R - D */
907 /* Q(i) := 1 */
908 /* end */
909 /* end */
910 sjme_jint_div rv = {0, 0};
911 struct
913 sjme_juint quot;
914 sjme_juint rem;
915 } interm = {0, 0};
916 sjme_juint i;
917 sjme_jbyte isneg;
919 /* Disallow division by zero */
920 if (aden == 0)
921 return rv;
923 /* Negative? */
924 isneg = 0;
925 if ((anum < 0 && aden >= 0) || (anum >= 0 && aden < 0))
926 isneg |= 1;
928 /* Force Positive */
929 anum = (anum < 0 ? -anum : anum);
930 aden = (aden < 0 ? -aden : aden);
932 /* Perform Math */
933 for (i = SJME_JUINT_C(31);; i--)
935 interm.rem <<= SJME_JUINT_C(1);
936 interm.rem &= SJME_JUINT_C(0xFFFFFFFE);
937 interm.rem |= (((sjme_juint)anum) >> i) & SJME_JUINT_C(1);
939 if (interm.rem >= (sjme_juint)aden)
941 interm.rem -= (sjme_juint)aden;
942 interm.quot |= (SJME_JUINT_C(1) << i);
945 if (i == 0)
946 break;
949 /* Restore Integers */
950 rv.quot = interm.quot;
951 rv.rem = interm.rem;
953 /* Make Negative */
954 if (isneg & 1)
955 rv.quot = -rv.quot;
957 /* Return */
958 return rv;
962 * Executes single CPU state.
964 * @param jvm JVM state.
965 * @param cpu CPU state.
966 * @param error Execution error.
967 * @param cycles The number of cycles to execute, a negative value means
968 * forever.
969 * @return The number of remaining cycles.
970 * @since 2019/06/08
972 sjme_jint sjme_cpuexec(sjme_jvm* jvm, sjme_cpu* cpu, sjme_error* error,
973 sjme_jint cycles)
975 sjme_jint op, enc;
976 sjme_vmemptr nextpc;
977 sjme_vmemptr tempp;
978 sjme_jint* r;
979 sjme_jint ia, ib, ic, id, ie;
980 sjme_cpustate* oldcpu;
981 sjme_jlong_combine longcombine;
983 /* Invalid argument? */
984 if (jvm == NULL || cpu == NULL)
986 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
988 return cycles;
991 /* Quick register access. */
992 r = cpu->state.r;
994 /* Near-Infinite execution loop. */
995 for (;;)
997 /* Check if we ran out of cycles. */
998 if (cycles >= 0)
1000 if (cycles == 0)
1001 break;
1002 if ((--cycles) <= 0)
1003 break;
1006 /* Increase total instruction count. */
1007 jvm->totalinstructions++;
1009 /* The zero register always must be zero. */
1010 r[0] = 0;
1012 /* Seed next PC address. */
1013 nextpc = cpu->state.pc;
1015 /* Read operation and determine encoding. */
1016 op = (sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_BYTE, &nextpc, error) &
1017 SJME_JINT_C(0xFF));
1018 enc = ((op >= SJME_ENC_SPECIAL_A) ? op : (op & SJME_ENC_MASK));
1020 /* Temporary debug. */
1021 #if defined(SJME_DEBUG)
1022 fprintf(stderr,
1023 "ti=%d tk%d pc=%p op=%X cl=%s mn=%s mt=%s ln=%d jo=%x ja=%d\n",
1024 jvm->totalinstructions,
1025 cpu->state.taskid,
1026 cpu->state.pc,
1027 (unsigned int)op,
1028 sjme_vmmresolve(jvm->vmem, cpu->state.debugclassname, 2, NULL),
1029 sjme_vmmresolve(jvm->vmem, cpu->state.debugmethodname, 2, NULL),
1030 sjme_vmmresolve(jvm->vmem, cpu->state.debugmethodtype, 2, NULL),
1031 (int)cpu->state.debugline,
1032 (unsigned int)cpu->state.debugjop,
1033 (int)cpu->state.debugjpc);
1034 #endif
1036 /* Depends on the operation. */
1037 switch (enc)
1039 /* Compare two register values. */
1040 case SJME_ENC_IF_ICMP:
1042 /* Values to compare. */
1043 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1044 ib = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1046 /* Target PC address. */
1047 ic = sjme_opdecodejmp(jvm->vmem, &nextpc, error);
1048 tempp = cpu->state.pc + ic;
1050 /* Check depends. */
1051 ic = 0;
1052 switch (op & SJME_ENC_COMPARE_MASK)
1054 case SJME_COMPARETYPE_EQUALS:
1055 if (ia == ib)
1056 ic = 1;
1057 break;
1059 case SJME_COMPARETYPE_NOT_EQUALS:
1060 if (ia != ib)
1061 ic = 1;
1062 break;
1064 case SJME_COMPARETYPE_LESS_THAN:
1065 if (ia < ib)
1066 ic = 1;
1067 break;
1069 case SJME_COMPARETYPE_LESS_THAN_OR_EQUALS:
1070 if (ia <= ib)
1071 ic = 1;
1072 break;
1074 case SJME_COMPARETYPE_GREATER_THAN:
1075 if (ia > ib)
1076 ic = 1;
1077 break;
1079 case SJME_COMPARETYPE_GREATER_THAN_OR_EQUALS:
1080 if (ia >= ib)
1081 ic = 1;
1082 break;
1084 case SJME_COMPARETYPE_TRUE:
1085 ic = 1;
1086 break;
1088 case SJME_COMPARETYPE_FALSE:
1089 ic = 0;
1090 break;
1093 /* Branch success? */
1094 if (ic != 0)
1095 nextpc = tempp;
1097 break;
1099 /* Math. */
1100 case SJME_ENC_MATH_REG_INT:
1101 case SJME_ENC_MATH_CONST_INT:
1103 /* A Value. */
1104 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1106 /* B value. */
1107 if (enc == SJME_ENC_MATH_CONST_INT)
1108 ib = sjme_opdecodejint(jvm->vmem, &nextpc, error);
1109 else
1110 ib = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1112 /* Perform the math. */
1113 switch (op & SJME_ENC_MATH_MASK)
1115 case SJME_MATH_ADD:
1116 ic = ia + ib;
1117 break;
1119 case SJME_MATH_SUB:
1120 ic = ia - ib;
1121 break;
1123 case SJME_MATH_MUL:
1124 ic = ia * ib;
1125 break;
1127 case SJME_MATH_DIV:
1128 ic = sjme_div(ia, ib).quot;
1129 break;
1131 case SJME_MATH_REM:
1132 ic = sjme_div(ia, ib).rem;
1133 break;
1135 case SJME_MATH_NEG:
1136 ic = -ia;
1137 break;
1139 case SJME_MATH_SHL:
1140 /* Shift is truncated. */
1141 ib = (ib & SJME_JINT_C(0x1F));
1143 /* Shifting values off the type is undefined, */
1144 /* so only keep the part of the value which is */
1145 /* not shifted off! */
1146 if (ib == 0)
1147 ic = ia;
1148 else
1149 ic = ((ia & sjme_sh_lmask[ib]) << ib);
1150 break;
1152 case SJME_MATH_SHR:
1153 case SJME_MATH_USHR:
1154 /* Shift is truncated. */
1155 ib = (ib & SJME_JINT_C(0x1F));
1157 /* Shifting values off the type is undefined, */
1158 /* so only keep the part of the value which is */
1159 /* not shifted off! */
1160 if (ib == 0)
1161 ic = ia;
1162 else
1163 ic = (((ia & sjme_sh_umask[ib])) >> ib);
1165 /* Mask in or mask out the dragged sign bit. */
1166 if (((ia & SJME_JINT_C(0x80000000)) != 0) &&
1167 ((op & SJME_ENC_MATH_MASK) == SJME_MATH_SHR))
1168 ic |= sjme_sh_umask[ib];
1169 else
1170 ic &= sjme_sh_lmask[31 - ib];
1171 break;
1173 case SJME_MATH_AND:
1174 ic = ia & ib;
1175 break;
1177 case SJME_MATH_OR:
1178 ic = ia | ib;
1179 break;
1181 case SJME_MATH_XOR:
1182 ic = ia ^ ib;
1183 break;
1185 case SJME_MATH_SIGNX8:
1186 if (ia & SJME_JINT_C(0x80))
1187 ic = (ia | SJME_JINT_C(0xFFFFFF00));
1188 else
1189 ic = (ia & SJME_JINT_C(0x000000FF));
1190 break;
1192 case SJME_MATH_SIGNX16:
1193 if (ia & SJME_JINT_C(0x8000))
1194 ic = (ia | SJME_JINT_C(0xFFFF0000));
1195 else
1196 ic = (ia & SJME_JINT_C(0x0000FFFF));
1197 break;
1199 case SJME_MATH_CMPL:
1200 case SJME_MATH_CMPG:
1201 ic = (ia < ib ? SJME_JINT_C(-1) :
1202 (ia > ib ? SJME_JINT_C(1) : SJME_JINT_C(0)));
1203 break;
1206 /* Store result. */
1207 r[sjme_opdecodereg(jvm->vmem, &nextpc, error)] = ic;
1209 break;
1211 /* Memory (native byte order). */
1212 case SJME_ENC_MEMORY_OFF_REG:
1213 case SJME_ENC_MEMORY_OFF_ICONST:
1214 case SJME_ENC_MEMORY_OFF_REG_JAVA:
1215 case SJME_ENC_MEMORY_OFF_ICONST_JAVA:
1217 /* Destination/source register. */
1218 ic = sjme_opdecodereg(jvm->vmem, &nextpc, error);
1220 /* The address and offset to access. */
1221 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1222 if (enc == SJME_ENC_MEMORY_OFF_ICONST ||
1223 enc == SJME_ENC_MEMORY_OFF_ICONST_JAVA)
1224 ib = sjme_opdecodejint(jvm->vmem, &nextpc, error);
1225 else
1226 ib = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1227 tempp = ia;
1229 /* Java types? */
1230 id = 0;
1231 if (enc == SJME_ENC_MEMORY_OFF_REG_JAVA ||
1232 enc == SJME_ENC_MEMORY_OFF_ICONST_JAVA)
1233 switch (op & SJME_MEM_DATATYPE_MASK)
1235 case SJME_DATATYPE_BYTE:
1236 id = SJME_VMMTYPE_BYTE;
1237 break;
1239 case SJME_DATATYPE_CHARACTER:
1240 case SJME_DATATYPE_SHORT:
1241 id = SJME_VMMTYPE_JAVASHORT;
1242 break;
1244 case SJME_DATATYPE_OBJECT:
1245 case SJME_DATATYPE_INTEGER:
1246 case SJME_DATATYPE_FLOAT:
1247 id = SJME_VMMTYPE_JAVAINTEGER;
1248 break;
1251 /* Native types? */
1252 else
1253 switch (op & SJME_MEM_DATATYPE_MASK)
1255 case SJME_DATATYPE_BYTE:
1256 id = SJME_VMMTYPE_BYTE;
1257 break;
1259 case SJME_DATATYPE_CHARACTER:
1260 case SJME_DATATYPE_SHORT:
1261 id = SJME_VMMTYPE_SHORT;
1262 break;
1264 case SJME_DATATYPE_OBJECT:
1265 case SJME_DATATYPE_INTEGER:
1266 case SJME_DATATYPE_FLOAT:
1267 id = SJME_VMMTYPE_INTEGER;
1268 break;
1271 /* Load value */
1272 if ((op & SJME_MEM_LOAD_MASK) != 0)
1274 /* Read. */
1275 r[ic] = sjme_vmmread(jvm->vmem, id, tempp, ib, error);
1277 /* Mask character? */
1278 if ((op & SJME_MEM_DATATYPE_MASK) ==
1279 SJME_DATATYPE_CHARACTER)
1280 r[ic] = r[ic] & SJME_JINT_C(0xFFFF);
1282 #if defined(SJME_DEBUG)
1283 fprintf(stderr, "r[%d] = *(%08x + %d) = %d/%08x\n",
1284 (int)ic, (int)tempp, (int)ib,
1285 (int)r[ic], (int)r[ic]);
1286 #endif
1289 /* Store value */
1290 else
1292 sjme_vmmwrite(jvm->vmem, id, tempp, ib, r[ic], error);
1294 #if defined(SJME_DEBUG)
1295 fprintf(stderr, "*(%08x + %d) = r[%d] = %d/%08x\n",
1296 (int)tempp, (int)ib, (int)ic,
1297 (int)r[ic], (int)r[ic]);
1298 #endif
1301 break;
1303 /* Atomic compare, get, and set. */
1304 case SJME_OP_ATOMIC_COMPARE_GET_AND_SET:
1306 /* Check. */
1307 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1309 /* Get. */
1310 ib = sjme_opdecodereg(jvm->vmem, &nextpc, error);
1312 /* Set. */
1313 ic = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1315 /* Address. */
1316 id = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1318 /* Offset. */
1319 ie = sjme_opdecodeui(jvm->vmem, &nextpc, error);
1321 /* Perform the operation. */
1322 r[ib] = sjme_vmmatomicintcheckgetandset(
1323 jvm->vmem, ia, ic, id, ie, error);
1325 break;
1327 /* Atomic decrement and get. */
1328 case SJME_OP_ATOMIC_INT_DECREMENT_AND_GET:
1330 /* Target register. */
1331 id = sjme_opdecodereg(jvm->vmem, &nextpc, error);
1333 /* Load address and offset. */
1334 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1335 ib = sjme_opdecodeui(jvm->vmem, &nextpc, error);
1337 /* Modify the value accordingly. */
1338 r[id] = sjme_vmmatomicintaddandget(jvm->vmem, ia, ib,
1339 SJME_JINT_C(-1), error);
1341 break;
1343 /* Atomic increment. */
1344 case SJME_OP_ATOMIC_INT_INCREMENT:
1346 /* Load address and offset. */
1347 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1348 ib = sjme_opdecodeui(jvm->vmem, &nextpc, error);
1350 /* Modify the value accordingly. */
1351 sjme_vmmatomicintaddandget(jvm->vmem, ia, ib,
1352 SJME_JINT_C(1), error);
1354 break;
1356 /* Breakpoint, only if debugging enabled. */
1357 case SJME_OP_BREAKPOINT:
1358 if (jvm->enabledebug != 0)
1360 sjme_seterror(error, SJME_ERROR_CPUBREAKPOINT,
1361 jvm->totalinstructions);
1363 return cycles;
1366 break;
1368 /* Copy value. */
1369 case SJME_OP_COPY:
1371 ia = sjme_opdecodereg(jvm->vmem, &nextpc, error);
1372 ib = sjme_opdecodereg(jvm->vmem, &nextpc, error);
1374 r[ib] = r[ia];
1376 break;
1378 /* Debug entry. */
1379 case SJME_OP_DEBUG_ENTRY:
1381 tempp = r[SJME_POOL_REGISTER];
1383 /* Get pointers to the real values. */
1384 cpu->state.debugclassname = sjme_vmmread(jvm->vmem,
1385 SJME_VMMTYPE_INTEGER, tempp, sjme_opdecodeui(jvm->vmem,
1386 &nextpc, error) * SJME_JINT_C(4), error);
1387 cpu->state.debugmethodname = sjme_vmmread(jvm->vmem,
1388 SJME_VMMTYPE_INTEGER, tempp, sjme_opdecodeui(jvm->vmem,
1389 &nextpc, error) * SJME_JINT_C(4), error);
1390 cpu->state.debugmethodtype = sjme_vmmread(jvm->vmem,
1391 SJME_VMMTYPE_INTEGER, tempp, sjme_opdecodeui(jvm->vmem,
1392 &nextpc, error) * SJME_JINT_C(4), error);
1393 cpu->state.debugsourcefile = sjme_vmmread(jvm->vmem,
1394 SJME_VMMTYPE_INTEGER, tempp, sjme_opdecodeui(jvm->vmem,
1395 &nextpc, error) * SJME_JINT_C(4), error);
1397 break;
1399 /* Exit method. */
1400 case SJME_OP_DEBUG_EXIT:
1401 break;
1403 /* Debug point. */
1404 case SJME_OP_DEBUG_POINT:
1406 cpu->state.debugline =
1407 sjme_opdecodeui(jvm->vmem, &nextpc, error);
1408 cpu->state.debugjop =
1409 (sjme_opdecodeui(jvm->vmem, &nextpc, error) &
1410 SJME_JINT_C(0xFF));
1411 cpu->state.debugjpc =
1412 sjme_opdecodeui(jvm->vmem, &nextpc, error);
1414 break;
1416 /* If equal to constant? */
1417 case SJME_OP_IFEQ_CONST:
1419 /* A value. */
1420 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1422 /* B value. */
1423 ib = sjme_opdecodejint(jvm->vmem, &nextpc, error);
1425 /* Target PC address. */
1426 ic = sjme_opdecodejmp(jvm->vmem, &nextpc, error);
1427 tempp = cpu->state.pc + ic;
1429 /* Jump on equals? */
1430 if (ia == ib)
1431 nextpc = tempp;
1433 break;
1435 /* Invoke method. */
1436 case SJME_OP_INVOKE:
1438 /* Allocate to store old CPU state. */
1439 oldcpu = sjme_malloc(sizeof(*oldcpu));
1440 if (oldcpu == NULL)
1442 sjme_seterror(error, SJME_ERROR_NOMEMORY,
1443 sizeof(*oldcpu));
1445 return cycles;
1448 /* Copy and store state. */
1449 *oldcpu = cpu->state;
1450 cpu->state.parent = oldcpu;
1452 /* Setup CPU state for invoke run, move pool up. */
1453 for (ia = SJME_LOCAL_REGISTER_BASE;
1454 ia < SJME_MAX_REGISTERS; ia++)
1455 r[ia] = 0;
1456 r[SJME_POOL_REGISTER] = oldcpu->r[SJME_NEXT_POOL_REGISTER];
1457 r[SJME_NEXT_POOL_REGISTER] = 0;
1459 /* Inherit the task ID. */
1460 cpu->state.taskid = oldcpu->taskid;
1462 /* The address to execute. */
1463 ia = oldcpu->r[
1464 sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1466 /* Load in register list (wide). */
1467 ib = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_BYTE, &nextpc,
1468 error);
1469 if ((ib & SJME_JINT_C(0x80)) != 0)
1471 /* Skip back and read lower value. */
1472 nextpc--;
1473 ib = sjme_opdecodejshort(jvm->vmem, &nextpc, error);
1475 /* Read values. */
1476 for (ic = 0; ic < ib; ic++)
1477 r[SJME_ARGBASE_REGISTER + ic] = oldcpu->r[
1478 sjme_opdecodejshort(jvm->vmem, &nextpc,
1479 error)];
1482 /* Narrow format list. */
1483 else
1485 /* Read values. */
1486 for (ic = 0; ic < ib; ic++)
1487 r[SJME_ARGBASE_REGISTER + ic] =
1488 oldcpu->r[sjme_vmmreadp(jvm->vmem,
1489 SJME_VMMTYPE_BYTE, &nextpc, error)];
1492 #if defined(SJME_DEBUG)
1493 fprintf(stderr, "Invoke %08x (", (int)ia);
1494 for (ic = 0; ic < ib; ic++)
1496 if (ic > 0)
1497 fprintf(stderr, ", ");
1498 fprintf(stderr, "%d/%08x",
1499 (int)r[SJME_ARGBASE_REGISTER + ic],
1500 (int)r[SJME_ARGBASE_REGISTER + ic]);
1502 fprintf(stderr, ")\n");
1503 #endif
1505 /* Old PC address resumes where this read ended. */
1506 oldcpu->pc = nextpc;
1508 /* Our next PC becomes the target address. */
1509 nextpc = ia;
1510 cpu->state.pc = nextpc;
1512 break;
1514 /* Load value from integer array. */
1515 case SJME_OP_LOAD_FROM_INTARRAY:
1517 /* Destination register. */
1518 ic = sjme_opdecodereg(jvm->vmem, &nextpc, error);
1520 /* Address and index */
1521 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1522 ib = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1524 /* Load from array. */
1525 r[ic] = sjme_vmmread(jvm->vmem, SJME_VMMTYPE_INTEGER,
1526 ia, SJME_ARRAY_BASE_SIZE + (ib * SJME_JINT_C(4)),
1527 error);
1529 break;
1531 /* Load value from constant pool. */
1532 case SJME_OP_LOAD_POOL:
1534 /* The index to read from. */
1535 ia = sjme_opdecodeui(jvm->vmem, &nextpc, error);
1537 /* Write into destination register. */
1538 r[(ib = sjme_opdecodereg(jvm->vmem, &nextpc, error))] =
1539 sjme_vmmread(jvm->vmem, SJME_VMMTYPE_INTEGER,
1540 r[SJME_POOL_REGISTER], (ia * SJME_JINT_C(4)),
1541 error);
1543 #if defined(SJME_DEBUG)
1544 fprintf(stderr, "Load pool %d -> %d/%08x\n",
1545 (int)ia, (int)r[ib], (int)r[ib]);
1546 #endif
1548 break;
1550 /* Return from method. */
1551 case SJME_OP_RETURN:
1553 /* Get parent CPU state. */
1554 oldcpu = cpu->state.parent;
1556 /* Exit must be done through an exit system call! */
1557 if (oldcpu == NULL)
1559 sjme_seterror(error, SJME_ERROR_THREADRETURN,
1560 jvm->totalinstructions);
1562 return cycles;
1565 /* Copy global values back. */
1566 for (ia = 0; ia < SJME_LOCAL_REGISTER_BASE; ia++)
1567 oldcpu->r[ia] = cpu->state.r[ia];
1569 /* Completely restore the old state. */
1570 cpu->state = *oldcpu;
1572 /* Restore continuing PC address. */
1573 nextpc = cpu->state.pc;
1575 /* Free the parent as it is not needed. */
1576 sjme_free(oldcpu);
1578 #if defined(SJME_DEBUG)
1579 fprintf(stderr, "Return: %d/%08x\n",
1580 (int)r[SJME_RETURN_REGISTER],
1581 (int)r[SJME_RETURN_REGISTER]);
1582 #endif
1584 break;
1586 /* Store to constant pool. */
1587 case SJME_OP_STORE_POOL:
1589 /* The index to read from. */
1590 ia = sjme_opdecodeui(jvm->vmem, &nextpc, error);
1592 /* Read from destination register. */
1593 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_INTEGER,
1594 r[SJME_POOL_REGISTER], (ia * SJME_JINT_C(4)),
1595 r[(ib = sjme_opdecodereg(jvm->vmem,
1596 &nextpc, error))],
1597 error);
1599 #if defined(SJME_DEBUG)
1600 fprintf(stderr, "Store pool %d <- %d/%08x\n",
1601 (int)ia, (int)r[ib], (int)r[ib]);
1602 #endif
1604 break;
1606 /* Store value to integer array. */
1607 case SJME_OP_STORE_TO_INTARRAY:
1609 /* Source register. */
1610 ic = sjme_opdecodereg(jvm->vmem, &nextpc, error);
1612 /* Address and index */
1613 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1614 ib = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1616 /* Store to array. */
1617 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_INTEGER,
1618 ia, SJME_ARRAY_BASE_SIZE + (ib * SJME_JINT_C(4)),
1619 r[ic], error);
1621 break;
1623 /* System call. */
1624 case SJME_OP_SYSTEM_CALL:
1626 /* Clear system call arguments. */
1627 for (ia = 0; ia < SJME_MAX_SYSCALLARGS; ia++)
1628 cpu->syscallargs[ia] = 0;
1630 /* Load call type. */
1631 ia = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1633 /* Load call arguments. */
1634 ic = sjme_opdecodeui(jvm->vmem, &nextpc, error);
1635 for (ib = 0; ib < ic; ib++)
1637 /* Get value. */
1638 id = r[sjme_opdecodereg(jvm->vmem, &nextpc, error)];
1640 /* Set but never exceed the system call limit. */
1641 if (ib < SJME_MAX_SYSCALLARGS)
1642 cpu->syscallargs[ib] = id;
1645 /* Call it and place result into the return register. */
1646 /* IPC Exceptions are not forwarded to supervisor. */
1647 /* IPC Calls are always virtualized even in supervisor. */
1648 if ((cpu->state.taskid == 0 ||
1649 ia == SJME_SYSCALL_EXCEPTION_LOAD ||
1650 ia == SJME_SYSCALL_EXCEPTION_STORE) &&
1651 ia != SJME_SYSCALL_IPC_CALL)
1653 /* Reset */
1654 longcombine.lo = 0;
1655 longcombine.hi = 0;
1657 /* Perform the system call. */
1658 sjme_syscall(jvm, cpu, error, ia, cpu->syscallargs,
1659 &longcombine);
1661 /* Extract result. */
1662 r[SJME_RETURN_REGISTER] = longcombine.lo;
1663 r[SJME_RETURN_REGISTER + 1] = longcombine.hi;
1666 /* Otherwise perform supervisor handling of the call. */
1667 else
1669 /* Allocate to store old CPU state. */
1670 oldcpu = sjme_malloc(sizeof(*oldcpu));
1671 if (oldcpu == NULL)
1673 sjme_seterror(error, SJME_ERROR_NOMEMORY,
1674 sizeof(*oldcpu));
1676 return cycles;
1679 /* Copy and store state. */
1680 *oldcpu = cpu->state;
1681 cpu->state.parent = oldcpu;
1683 /* Old PC address resumes where this ended. */
1684 oldcpu->pc = nextpc;
1686 /* Go back to the supervisor task. */
1687 cpu->state.taskid = 0;
1689 /* Setup arguments for this call. */
1690 r[SJME_POOL_REGISTER] = cpu->supervisorprops[
1691 SJME_SUPERPROP_TASK_SYSCALL_METHOD_POOL_POINTER];
1692 r[SJME_STATIC_FIELD_REGISTER] = cpu->supervisorprops[
1693 SJME_SUPERPROP_TASK_SYSCALL_STATIC_FIELD_POINTER];
1694 r[SJME_ARGBASE_REGISTER + 0] =
1695 oldcpu->taskid;
1696 r[SJME_ARGBASE_REGISTER + 1] =
1697 oldcpu->r[SJME_STATIC_FIELD_REGISTER];
1698 r[SJME_ARGBASE_REGISTER + 2] =
1701 /* And arguments for it as well. */
1702 for (ie = 0; ie < SJME_MAX_SYSCALLARGS; ie++)
1703 r[SJME_ARGBASE_REGISTER + 3 + ie] =
1704 cpu->syscallargs[ie];
1706 /* Our next PC is the handler address. */
1707 nextpc = cpu->supervisorprops[
1708 SJME_SUPERPROP_TASK_SYSCALL_METHOD_HANDLER];
1709 cpu->state.pc = nextpc;
1712 /* Stop if an error was set. */
1713 if (error->code != SJME_ERROR_NONE)
1714 return cycles;
1716 break;
1718 /* Invalid operation. */
1719 default:
1720 sjme_seterror(error, SJME_ERROR_INVALIDOP, op);
1722 return cycles;
1725 /* Check for error. */
1726 if (error != NULL)
1727 if (error->code != SJME_ERROR_NONE)
1728 return cycles;
1730 /* Set next PC address. */
1731 cpu->state.pc = nextpc;
1734 /* Return remaining cycles. */
1735 return cycles;
1738 /** Prints the error to the console output. */
1739 void sjme_printerror(sjme_jvm* jvm, sjme_error* error)
1741 sjme_jint i, z;
1742 sjme_jint ec;
1743 sjme_jbyte b;
1744 sjme_jbyte hex[8];
1745 sjme_jint (*po)(sjme_jint b);
1747 /* Get output console. */
1748 po = (jvm->nativefuncs != NULL ? jvm->nativefuncs->stderr_write : NULL);
1750 /* Write the failure message. */
1751 sjme_console_pipewrite(jvm, po, sjme_execfailmessage, 0,
1752 sizeof(sjme_execfailmessage) / sizeof(sjme_jbyte), error);
1754 /* Read in hex bytes, for both forms. */
1755 for (z = 0; z < 2; z++)
1757 /* Form hex value. */
1758 ec = (z == 0 ? error->code : error->value);
1759 for (i = 0; i < 8; i++)
1761 b = (ec >> (4 * i)) & SJME_JINT_C(0xF);
1762 hex[7 - i] = (b < 10 ? 48 : (b - 10) + 97);
1765 /* Print hex. */
1766 sjme_console_pipewrite(jvm, po,
1767 hex, 0, sizeof(hex) / sizeof(sjme_jbyte), error);
1769 /* Extra space? */
1770 if (z == 0)
1772 b = 32;
1773 sjme_console_pipewrite(jvm, po, &b, 0, 1, error);
1777 /* End newline. */
1778 b = 13;
1779 sjme_console_pipewrite(jvm, po, &b, 0, 1, error);
1780 b = 10;
1781 sjme_console_pipewrite(jvm, po, &b, 0, 1, error);
1783 /* Always flush the screen on error. */
1784 if (jvm->fbinfo->flush != NULL)
1785 jvm->fbinfo->flush();
1788 /** Executes code running within the JVM. */
1789 sjme_jint sjme_jvmexec(sjme_jvm* jvm, sjme_error* error, sjme_jint cycles)
1791 sjme_jint threadid;
1792 sjme_cpu* cpu;
1793 sjme_error xerror;
1795 /* Fallback error state. */
1796 if (error == NULL)
1798 memset(&xerror, 0, sizeof(xerror));
1799 error = &xerror;
1802 /* Do nothing. */
1803 if (jvm == NULL)
1805 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
1807 return 0;
1810 /* Run cooperatively threaded style CPU. */
1811 for (threadid = jvm->fairthreadid;;
1812 threadid = ((threadid + 1) & SJME_THREAD_MASK))
1814 /* Have we used all our execution cycles? */
1815 if (cycles >= 0)
1817 if (cycles == 0)
1818 break;
1819 if ((--cycles) <= 0)
1820 break;
1823 /* Ignore CPUs which are not turned on. */
1824 cpu = &jvm->threads[threadid];
1825 if (cpu->threadstate == SJME_THREAD_STATE_NONE)
1826 continue;
1828 /* Execute CPU engine. */
1829 cycles = sjme_cpuexec(jvm, cpu, error, cycles);
1831 /* CPU fault, stop! */
1832 if (error->code != SJME_ERROR_NONE)
1833 break;
1836 /* Start next run on the CPU that was last executing. */
1837 jvm->fairthreadid = (threadid & SJME_THREAD_MASK);
1839 /* Print error state to console? */
1840 if (error->code != SJME_ERROR_NONE)
1842 /* Force error to be on-screen. */
1843 jvm->supervisorokay = 0;
1844 sjme_printerror(jvm, error);
1847 /* Returning remaining number of cycles. */
1848 return cycles;
1852 * Attempts to load a built-in ROM file.
1854 * @param nativefuncs Native functions.
1855 * @param outromsize Output ROM size.
1856 * @param error Error flag.
1857 * @return The loaded ROM data or {@code NULL} if no ROM was loaded.
1858 * @since 2019/06/07
1860 void* sjme_loadrom(sjme_nativefuncs* nativefuncs, sjme_jint* outromsize,
1861 sjme_error* error)
1863 void* rv;
1864 sjme_nativefilename* fn;
1865 sjme_nativefile* file;
1866 sjme_jint romsize, readat, readcount;
1867 sjme_error xerror;
1869 /* Set error if missing. */
1870 if (error == NULL)
1872 memset(&xerror, 0, sizeof(xerror));
1873 error = &xerror;
1876 /* Need native functions. */
1877 if (nativefuncs == NULL || nativefuncs->nativeromfile == NULL ||
1878 nativefuncs->fileopen == NULL || nativefuncs->filesize == NULL ||
1879 nativefuncs->fileread == NULL)
1881 sjme_seterror(error, SJME_ERROR_NOFILES, 0);
1883 return NULL;
1886 /* Load file name used for the native ROM. */
1887 fn = nativefuncs->nativeromfile();
1888 if (fn == NULL)
1890 sjme_seterror(error, SJME_ERROR_NONATIVEROM, 0);
1892 return NULL;
1895 /* Set to nothing. */
1896 rv = NULL;
1898 /* Open ROM. */
1899 file = nativefuncs->fileopen(fn, SJME_OPENMODE_READ, error);
1900 if (file != NULL)
1902 /* Need ROM size. */
1903 romsize = nativefuncs->filesize(file, error);
1905 /* Allocate ROM into memory. */
1906 rv = sjme_malloc(romsize);
1907 if (rv != NULL)
1909 /* Read whatever is possible. */
1910 for (readat = 0; readat < romsize;)
1912 /* Read into raw memory. */
1913 readcount = nativefuncs->fileread(file,
1914 SJME_POINTER_OFFSET_LONG(rv, readat), romsize - readat,
1915 error);
1917 /* EOF or error? */
1918 if (readcount < 0)
1920 /* End of file reached? */
1921 if (error->code == SJME_ERROR_ENDOFFILE)
1923 /* Reached early EOF?? */
1924 if (readat < romsize)
1926 sjme_seterror(error, SJME_ERROR_EARLYEOF, 0);
1928 /* Failed */
1929 sjme_free(rv);
1930 return NULL;
1933 /* Otherwise clear. */
1934 else
1935 sjme_seterror(error, SJME_ERROR_NONE, 0);
1937 break;
1940 /* Otherwise fail */
1941 else
1943 /* Force error to be set. */
1944 sjme_seterror(error, SJME_ERROR_READERROR, 0);
1946 /* Free resources. */
1947 sjme_free(rv);
1948 rv = NULL;
1949 break;
1953 /* Read count goes up. */
1954 readat += readcount;
1958 /* Just set error. */
1959 else
1960 sjme_seterror(error, SJME_ERROR_NOMEMORY, romsize);
1962 /* Close when done. */
1963 if (nativefuncs->fileclose != NULL)
1964 nativefuncs->fileclose(file, NULL);
1967 /* Free file name when done. */
1968 if (nativefuncs->freefilename != NULL)
1969 nativefuncs->freefilename(fn);
1971 /* Output ROM size? */
1972 if (outromsize != NULL)
1973 *outromsize = romsize;
1975 /* Whatever value was used, if possible */
1976 return rv;
1980 * Initializes the BootRAM, loading it from ROM.
1982 * @param jvm The Java VM to initialize.
1983 * @param error Error flag.
1984 * @return Non-zero on success.
1985 * @since 2019/06/07
1987 sjme_jint sjme_initboot(sjme_jvm* jvm, sjme_error* error)
1989 sjme_vmemptr rp;
1990 sjme_vmemptr bootjar;
1991 sjme_jint bootoff, i, n, seedop, seedaddr, seedvalh, seedvall, seedsize;
1992 sjme_jint bootjaroff, vrambase, vrombase, qq;
1993 sjme_cpu* cpu;
1994 sjme_error xerror;
1996 /* Invalid arguments. */
1997 if (jvm == NULL)
1999 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
2001 return 0;
2004 /* Force error to be set. */
2005 if (error == NULL)
2007 memset(&xerror, 0, sizeof(xerror));
2008 error = &xerror;
2011 /* Determine the address the VM sees for some memory types. */
2012 vrambase = jvm->ram->fakeptr;
2013 vrombase = jvm->rom->fakeptr;
2015 /* Set initial CPU (the first). */
2016 cpu = &jvm->threads[0];
2017 cpu->threadstate = SJME_THREAD_STATE_RUNNING;
2019 /* Set boot pointer to start of ROM. */
2020 rp = jvm->rom->fakeptr;
2022 /* Check ROM magic number. */
2023 if ((qq = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error))
2024 != SJME_ROM_MAGIC_NUMBER)
2026 sjme_seterror(error, SJME_ERROR_INVALIDROMMAGIC, qq);
2028 return 0;
2031 /* Ignore numjars, tocoffset, bootjarindex. */
2032 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2033 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2034 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2036 /* Read and calculate BootJAR position. */
2037 bootjaroff = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp,
2038 error);
2039 rp = bootjar = vrombase + bootjaroff;
2041 /* Check JAR magic number. */
2042 if ((qq = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error))
2043 != SJME_JAR_MAGIC_NUMBER)
2045 sjme_seterror(error, SJME_ERROR_INVALIDROMMAGIC, qq);
2047 return 0;
2050 /* Ignore numrc, tocoffset, manifestoff, manifestlen. */
2051 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2052 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2053 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2054 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2056 /* Read boot offset for later. */
2057 bootoff = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2059 /* Ignore bootsize. */
2060 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2062 /* Seed initial CPU state. */
2063 cpu->state.r[SJME_POOL_REGISTER] = vrambase + sjme_vmmreadp(jvm->vmem,
2064 SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2065 cpu->state.r[SJME_STATIC_FIELD_REGISTER] = vrambase +
2066 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2067 cpu->state.pc = (bootjar + sjme_vmmreadp(jvm->vmem,
2068 SJME_VMMTYPE_JAVAINTEGER, &rp, error));
2070 /* Load system call handler information. */
2071 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, jvm->syscallsfp, 0,
2072 vrambase + sjme_vmmreadp(jvm->vmem,
2073 SJME_VMMTYPE_JAVAINTEGER, &rp, error), error);
2074 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, jvm->syscallcode, 0,
2075 bootjar + sjme_vmmreadp(jvm->vmem,
2076 SJME_VMMTYPE_JAVAINTEGER, &rp, error), error);
2077 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, jvm->syscallpool, 0,
2078 vrambase + sjme_vmmreadp(jvm->vmem,
2079 SJME_VMMTYPE_JAVAINTEGER, &rp, error), error);
2081 /* Bootstrap entry arguments. */
2082 /* (int __rambase, int __ramsize, int __rombase, int __romsize, */
2083 /* int __confbase, int __confsize) */
2084 cpu->state.r[SJME_ARGBASE_REGISTER + 0] = jvm->ram->fakeptr;
2085 cpu->state.r[SJME_ARGBASE_REGISTER + 1] = jvm->ram->size;
2086 cpu->state.r[SJME_ARGBASE_REGISTER + 2] = jvm->rom->fakeptr;
2087 cpu->state.r[SJME_ARGBASE_REGISTER + 3] = jvm->rom->size;
2088 cpu->state.r[SJME_ARGBASE_REGISTER + 4] = jvm->config->fakeptr;
2089 cpu->state.r[SJME_ARGBASE_REGISTER + 5] = jvm->config->size;
2091 #if defined(SJME_DEBUG)
2092 fprintf(stderr, "RAM=%08x+%d ROM=%08x+%d CFG=%08x+%d\n",
2093 (int)jvm->ram->fakeptr, (int)jvm->ram->size,
2094 (int)jvm->rom->fakeptr, (int)jvm->rom->size,
2095 (int)jvm->config->fakeptr, (int)jvm->config->size);
2096 #endif
2098 /* Address where the BootRAM is read from. */
2099 rp = bootjar + bootoff;
2101 /* Copy initial base memory bytes, which is pure big endian. */
2102 n = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2103 for (i = 0; i < n; i++)
2104 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_BYTE, vrambase, i,
2105 sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_BYTE, &rp, error), error);
2107 /* Load all seeds, which restores natural byte order. */
2108 n = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error);
2109 for (i = 0; i < n; i++)
2111 /* Read seed information. */
2112 seedop = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_BYTE, &rp, error);
2113 seedsize = (seedop >> SJME_JINT_C(4)) & SJME_JINT_C(0xF);
2114 seedop = (seedop & SJME_JINT_C(0xF));
2115 seedaddr = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp,
2116 error);
2118 /* Wide value. */
2119 if (seedsize == 8)
2121 seedvalh = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp,
2122 error);
2123 seedvall = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp,
2124 error);
2127 /* Narrow value. */
2128 else
2129 seedvalh = sjme_vmmreadp(jvm->vmem, sjme_vmmsizetojavatype(
2130 seedsize, error), &rp, error);
2132 /* Make sure the seed types are correct. */
2133 if ((seedsize != 1 && seedsize != 2 &&
2134 seedsize != 4 && seedsize != 8) ||
2135 (seedop != 0 && seedop != 1 && seedop != 2) ||
2136 (seedsize == 8 && seedop != 0))
2138 sjme_seterror(error, SJME_ERROR_INVALIDBOOTRAMSEED,
2139 seedop | (seedsize << SJME_JINT_C(4)));
2141 return 0;
2144 /* Offset value if it is in RAM or JAR ROM. */
2145 if (seedop == 1)
2146 seedvalh += vrambase;
2147 else if (seedop == 2)
2148 seedvalh += bootjar;
2150 /* Write long value. */
2151 if (seedsize == 8)
2153 #if defined(SJME_BIG_ENDIAN)
2154 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_INTEGER,
2155 vrambase, seedaddr, seedvalh, error);
2156 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_INTEGER,
2157 vrambase + 4, seedaddr, seedvall, error);
2158 #else
2159 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_INTEGER,
2160 vrambase, seedaddr, seedvall, error);
2161 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_INTEGER,
2162 vrambase + 4, seedaddr, seedvalh, error);
2163 #endif
2166 /* Write narrow value. */
2167 else
2168 sjme_vmmwrite(jvm->vmem, sjme_vmmsizetotype(seedsize, error),
2169 vrambase, seedaddr, seedvalh, error);
2171 #if defined(SJME_DEBUG)
2172 fprintf(stderr, "SEED op=%d sz=%d -> @%08x+%08x (R@%08x) = %d/%08x\n",
2173 (int)seedop, (int)seedsize, (int)vrambase, (int)seedaddr,
2174 (int)(vrambase + seedaddr), (int)seedvalh, (int)seedvalh);
2175 #endif
2177 /* Error was reached? */
2178 if (error->code != SJME_ERROR_NONE)
2179 return 0;
2182 /* Check end value. */
2183 if ((qq = sjme_vmmreadp(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &rp, error))
2184 != (~SJME_JINT_C(0)))
2186 sjme_seterror(error, SJME_ERROR_INVALIDBOOTRAMEND, qq);
2188 return 0;
2191 /* Force failure to happen! */
2192 if (error->code != SJME_ERROR_NONE)
2193 return 0;
2195 /* Okay! */
2196 return 1;
2199 /** Destroys the virtual machine instance. */
2200 sjme_jint sjme_jvmdestroy(sjme_jvm* jvm, sjme_error* error)
2202 sjme_cpustate* cpu;
2203 sjme_cpustate* oldcpu;
2204 sjme_jint i;
2206 /* Missing this? */
2207 if (jvm == NULL)
2209 sjme_seterror(error, SJME_ERROR_INVALIDARG, 0);
2211 return 0;
2214 /* Reset error. */
2215 sjme_seterror(error, SJME_ERROR_NONE, 0);
2217 /* Go through and cleanup CPUs. */
2218 for (i = 0; i < SJME_THREAD_MAX; i++)
2220 /* Get CPU here. */
2221 cpu = &jvm->threads[i].state;
2223 /* Recursively clear CPU stacks. */
2224 while (cpu->parent != NULL)
2226 /* Keep for later free. */
2227 oldcpu = cpu->parent;
2229 /* Copy down. */
2230 *cpu = *oldcpu;
2232 /* Free CPU state. */
2233 if (oldcpu != &jvm->threads[i].state)
2234 sjme_free(oldcpu);
2238 /* Delete major JVM data areas. */
2239 sjme_free(jvm->ram);
2240 sjme_free(jvm->config);
2241 if (jvm->presetrom == NULL)
2242 sjme_free(jvm->rom);
2244 /* Destroyed okay. */
2245 return 1;
2248 /** Initializes the configuration space. */
2249 void sjme_configinit(sjme_jvm* jvm, sjme_jvmoptions* options,
2250 sjme_nativefuncs* nativefuncs, sjme_error* error)
2252 #define SJME_CONFIG_FORMAT_INTEGER SJME_JINT_C(1)
2253 #define SJME_CONFIG_FORMAT_KEYVALUE SJME_JINT_C(2)
2254 #define SJME_CONFIG_FORMAT_STRING SJME_JINT_C(3)
2255 #define SJME_CONFIG_FORMAT_STRINGS SJME_JINT_C(4)
2256 sjme_vmemptr wp;
2257 sjme_vmemptr basep;
2258 sjme_vmemptr sizep;
2259 sjme_jint opt, format, iv, it, wlen;
2260 sjme_vmemptr* setpointer;
2261 char* sa;
2263 (void)options;
2264 (void)nativefuncs;
2266 /* Write pointer starts at the base area. */
2267 wp = jvm->config->fakeptr;
2269 /* Go through all possible options to make a value. */
2270 for (opt = SJME_JINT_C(1); opt < SJME_CONFIG_NUM_OPTIONS; opt++)
2272 /* Used to specify the format. */
2273 format = 0;
2275 /* Reset. */
2276 sa = NULL;
2277 iv = 0;
2278 setpointer = NULL;
2280 /* Depends on the option. */
2281 switch (opt)
2283 /* Java VM Version. */
2284 case SJME_CONFIG_JAVA_VM_VERSION:
2285 format = SJME_CONFIG_FORMAT_STRING;
2286 sa = "0.3.0";
2287 break;
2289 /* Java VM Name. */
2290 case SJME_CONFIG_JAVA_VM_NAME:
2291 format = SJME_CONFIG_FORMAT_STRING;
2292 sa = "SquirrelJME RatufaCoat";
2293 break;
2295 /* Java VM Vendor. */
2296 case SJME_CONFIG_JAVA_VM_VENDOR:
2297 format = SJME_CONFIG_FORMAT_STRING;
2298 sa = "Stephanie Gawroriski";
2299 break;
2301 /* Java VM E-Mail. */
2302 case SJME_CONFIG_JAVA_VM_EMAIL:
2303 format = SJME_CONFIG_FORMAT_STRING;
2304 sa = "xerthesquirrel@gmail.com";
2305 break;
2307 /* Java VM URL. */
2308 case SJME_CONFIG_JAVA_VM_URL:
2309 format = SJME_CONFIG_FORMAT_STRING;
2310 sa = "https://squirreljme.cc/";
2311 break;
2313 /* The guest depth. */
2314 case SJME_CONFIG_GUEST_DEPTH:
2315 break;
2317 /* Main class. */
2318 case SJME_CONFIG_MAIN_CLASS:
2319 break;
2321 /* Main program arguments. */
2322 case SJME_CONFIG_MAIN_ARGUMENTS:
2323 break;
2325 /* Is this a MIDlet? */
2326 case SJME_CONFIG_IS_MIDLET:
2327 break;
2329 /* Define system propertly. */
2330 case SJME_CONFIG_DEFINE_PROPERTY:
2331 break;
2333 /* Classpath to use. */
2334 case SJME_CONFIG_CLASS_PATH:
2335 break;
2337 /* System Call: Static field pointer. */
2338 case SJME_CONFIG_SYSCALL_STATIC_FIELD_POINTER:
2339 format = SJME_CONFIG_FORMAT_INTEGER;
2340 setpointer = &jvm->syscallsfp;
2341 break;
2343 /* System Call: Code Pointer. */
2344 case SJME_CONFIG_SYSCALL_CODE_POINTER:
2345 format = SJME_CONFIG_FORMAT_INTEGER;
2346 setpointer = &jvm->syscallcode;
2347 break;
2349 /* System Call: Pool Pointer. */
2350 case SJME_CONFIG_SYSCALL_POOL_POINTER:
2351 format = SJME_CONFIG_FORMAT_INTEGER;
2352 setpointer = &jvm->syscallpool;
2353 break;
2355 /* Unknown, ignore. */
2356 default:
2357 continue;
2360 /* No known way to write this? */
2361 if (format == 0)
2362 continue;
2364 /* Write option key. */
2365 sjme_vmmwritep(jvm->vmem, SJME_VMMTYPE_JAVASHORT, &wp, opt, error);
2367 /* Store size location for later write. */
2368 sizep = wp;
2369 sjme_vmmwritep(jvm->vmem, SJME_VMMTYPE_JAVASHORT, &wp, 0, error);
2371 /* Base write pointer. */
2372 basep = wp;
2374 /* Set pointer as needed. */
2375 if (setpointer != NULL)
2376 *setpointer = basep;
2378 /* Depends on the format. */
2379 switch (format)
2381 /* Integer. */
2382 case SJME_CONFIG_FORMAT_INTEGER:
2383 sjme_vmmwritep(jvm->vmem, SJME_VMMTYPE_JAVAINTEGER, &wp, iv,
2384 error);
2385 break;
2387 /* Key/value pair. */
2388 case SJME_CONFIG_FORMAT_KEYVALUE:
2389 break;
2391 /* String value. */
2392 case SJME_CONFIG_FORMAT_STRING:
2394 // Record string length
2395 int iv = strlen(sa);
2396 sjme_vmmwritep(jvm->vmem, SJME_VMMTYPE_JAVASHORT, &wp, iv,
2397 error);
2399 // Record characters
2400 for (it = 0; it < iv; it++)
2401 sjme_vmmwritep(jvm->vmem, SJME_VMMTYPE_BYTE, &wp,
2402 (sjme_jint)sa[it], error);
2404 break;
2406 /* Multiple strings. */
2407 case SJME_CONFIG_FORMAT_STRINGS:
2408 break;
2411 /* Determine length and round it to 4 bytes. */
2412 wlen = wp - basep;
2413 while ((wlen & SJME_JINT_C(3)) != 0)
2415 /* Write padding. */
2416 sjme_vmmwritep(jvm->vmem, SJME_VMMTYPE_BYTE, &wp, 0, error);
2417 wlen++;
2420 /* Write to the actual size! */
2421 sjme_vmmwrite(jvm->vmem, SJME_VMMTYPE_JAVASHORT, sizep, 0, wlen,
2422 error);
2425 /* Write end of config. */
2426 sjme_vmmwritep(jvm->vmem, SJME_VMMTYPE_BYTE, &wp, SJME_CONFIG_END, error);
2428 #undef SJME_CONFIG_FORMAT_INTEGER
2429 #undef SJME_CONFIG_FORMAT_KEYVALUE
2430 #undef SJME_CONFIG_FORMAT_STRING
2431 #undef SJME_CONFIG_FORMAT_STRINGS
2434 /** Creates a new instance of the JVM. */
2435 sjme_jvm* sjme_jvmnew(sjme_jvmoptions* options, sjme_nativefuncs* nativefuncs,
2436 sjme_error* error)
2438 sjme_jvmoptions nulloptions;
2439 void* ram;
2440 void* rom;
2441 void* conf;
2442 void* optionjar;
2443 sjme_jvm* rv;
2444 sjme_jint i, l, romsize;
2445 sjme_framebuffer* fbinfo;
2446 sjme_vmem* vmem;
2448 /* We need native functions. */
2449 if (nativefuncs == NULL)
2450 return NULL;
2452 /* Allocate virtual memory manager. */
2453 vmem = sjme_vmmnew(error);
2454 if (vmem == NULL)
2456 sjme_seterror(error, SJME_ERROR_VMMNEWFAIL, error->code);
2458 return NULL;
2461 /* Allocate VM state. */
2462 rv = sjme_malloc(sizeof(*rv));
2463 conf = sjme_malloc(SJME_DEFAULT_CONF_SIZE);
2464 if (rv == NULL || conf == NULL)
2466 sjme_seterror(error, SJME_ERROR_NOMEMORY,
2467 sizeof(*rv) + SJME_DEFAULT_CONF_SIZE);
2469 sjme_free(rv);
2470 sjme_free(conf);
2472 return NULL;
2475 /* Store virtual memory area. */
2476 rv->vmem = vmem;
2478 /* Virtual map config. */
2479 rv->config = sjme_vmmmap(vmem, 0, conf, SJME_DEFAULT_CONF_SIZE, error);
2480 if (rv->config == NULL)
2481 return NULL;
2483 /* If there were no options specified, just use a null set. */
2484 if (options == NULL)
2486 memset(&nulloptions, 0, sizeof(nulloptions));
2487 options = &nulloptions;
2490 /* If no RAM size was specified then use the default. */
2491 if (options->ramsize <= 0)
2492 options->ramsize = SJME_DEFAULT_RAM_SIZE;
2494 /* Allocate RAM, or at least keep trying to. */
2495 while (options->ramsize >= SJME_MINIMUM_RAM_SIZE)
2497 /* Attempt to allocate the RAM. */
2498 ram = sjme_malloc(options->ramsize);
2500 /* Ram allocated! So stop. */
2501 if (ram != NULL)
2502 break;
2504 /* Cut RAM allocation size down in half. */
2505 options->ramsize /= 2;
2508 /* Failed to allocate the RAM. */
2509 if (ram == NULL)
2511 sjme_seterror(error, SJME_ERROR_NOMEMORY, options->ramsize);
2513 sjme_free(rv);
2514 sjme_free(conf);
2516 return NULL;
2519 /* Virtual map RAM. */
2520 rv->ram = sjme_vmmmap(vmem, 0, ram, options->ramsize, error);
2521 if (rv->ram == NULL)
2523 sjme_seterror(error, SJME_ERROR_VMMMAPFAIL, 0);
2525 sjme_free(rv);
2526 sjme_free(conf);
2528 return NULL;
2531 /* Set native functions. */
2532 rv->nativefuncs = nativefuncs;
2534 /* Initialize the framebuffer info, if available. */
2535 fbinfo = NULL;
2536 if (nativefuncs->framebuffer != NULL)
2537 fbinfo = nativefuncs->framebuffer();
2539 /* Initialize framebuffer, done a bit early to show errors. */
2540 rv->fbinfo = fbinfo;
2541 if (fbinfo != NULL)
2543 /* If scan-line is not specified, default to the display width. */
2544 if (fbinfo->scanlen == 0)
2545 fbinfo->scanlen = fbinfo->width;
2547 /* Number of available pixels. */
2548 if (fbinfo->numpixels == 0)
2549 fbinfo->numpixels = fbinfo->scanlen * fbinfo->height;
2551 /* Bytes per pixel must be specified. */
2552 if (fbinfo->bitsperpixel == 0)
2553 switch (fbinfo->format)
2555 case SJME_PIXELFORMAT_PACKED_ONE:
2556 fbinfo->bitsperpixel = 1;
2557 break;
2559 case SJME_PIXELFORMAT_PACKED_TWO:
2560 fbinfo->bitsperpixel = 2;
2561 break;
2563 case SJME_PIXELFORMAT_PACKED_FOUR:
2564 fbinfo->bitsperpixel = 4;
2565 break;
2567 case SJME_PIXELFORMAT_BYTE_INDEXED:
2568 fbinfo->bitsperpixel = 8;
2569 break;
2571 case SJME_PIXELFORMAT_SHORT_RGB565:
2572 fbinfo->bitsperpixel = 16;
2573 break;
2575 default:
2576 case SJME_PIXELFORMAT_INTEGER_RGB888:
2577 fbinfo->bitsperpixel = 32;
2578 break;
2581 /* Scan line in bytes is based on the bytes per pixel. */
2582 if (fbinfo->scanlenbytes == 0)
2583 fbinfo->scanlenbytes =
2584 (fbinfo->scanlen * fbinfo->bitsperpixel) / 8;
2586 /* Console positions and size. */
2587 rv->conx = 0;
2588 rv->cony = 0;
2589 rv->conw = fbinfo->width / sjme_font.charwidths[0];
2590 rv->conh = fbinfo->height / sjme_font.pixelheight;
2593 /* Virtual map framebuffer, if available. */
2594 if (fbinfo != NULL)
2596 rv->framebuffer = sjme_vmmmap(vmem, 0, fbinfo->pixels,
2597 (fbinfo->numpixels * fbinfo->bitsperpixel) / 8, error);
2598 if (rv->framebuffer == NULL)
2600 sjme_seterror(error, SJME_ERROR_VMMMAPFAIL, 0);
2602 sjme_free(rv);
2603 sjme_free(ram);
2604 sjme_free(conf);
2606 return NULL;
2610 /* Needed by destruction later. */
2611 rv->presetrom = options->presetrom;
2613 /* Load the ROM? */
2614 rom = options->presetrom;
2615 if (rom == NULL)
2617 /* Call sub-routine which can load the ROM. */
2618 rom = sjme_loadrom(nativefuncs, &romsize, error);
2620 /* Could not load the ROM? */
2621 if (rom == NULL)
2623 /* Write the ROM failure message! */
2624 sjme_console_pipewrite(rv, (nativefuncs != NULL ?
2625 nativefuncs->stderr_write : NULL), sjme_romfailmessage, 0,
2626 sizeof(sjme_romfailmessage) / sizeof(sjme_jbyte), error);
2628 /* Clear resources */
2629 sjme_free(rv);
2630 sjme_free(ram);
2631 sjme_free(conf);
2633 /* Fail */
2634 return NULL;
2638 /* If we are copying from the preset ROM, duplicate it. */
2639 if (options->presetrom != NULL && options->copyrom != 0)
2641 /* Use this ROM size. */
2642 romsize = options->romsize;
2644 /* Allocate space to fit ROM. */
2645 rom = sjme_malloc(options->romsize);
2646 if (rom == NULL)
2648 sjme_seterror(error, SJME_ERROR_NOMEMORY, options->romsize);
2650 sjme_free(ram);
2651 sjme_free(conf);
2653 return NULL;
2656 /* Copy large chunks at a time. */
2657 for (i = 0; i < options->romsize;)
2659 /* Byte left to move? */
2660 l = options->romsize - i;
2662 /* Function uses a size_t which may be limited on this platform. */
2663 if (sizeof(sjme_jint) > sizeof(size_t) && l > (sjme_jint)SIZE_MAX)
2664 l = (sjme_jint)SIZE_MAX;
2666 /* Copy the data. */
2667 memmove(SJME_POINTER_OFFSET(rom, i),
2668 SJME_POINTER_OFFSET(options->presetrom, i), l);
2670 /* Offset up. */
2671 i += l;
2674 /* We copied it, so never make a preset ROM. */
2675 rv->presetrom = NULL;
2678 /* If we are using a preset ROM then just use the size. */
2679 if (rv->presetrom != NULL)
2680 romsize = options->romsize;
2682 /* Virtual map ROM. */
2683 rv->rom = sjme_vmmmap(vmem, 0, rom, romsize, error);
2684 if (rv->rom == NULL)
2686 sjme_seterror(error, SJME_ERROR_VMMMAPFAIL, 0);
2688 sjme_free(rv);
2689 sjme_free(ram);
2690 sjme_free(conf);
2691 if (rv->presetrom == NULL)
2692 sjme_free(rom);
2694 return NULL;
2697 /* Initialize configuration space. */
2698 sjme_configinit(rv, options, nativefuncs, error);
2700 /* Initialize the BootRAM and boot the CPU. */
2701 if (sjme_initboot(rv, error) == 0)
2703 /* Write the Boot failure message! */
2704 sjme_console_pipewrite(rv, (nativefuncs != NULL ?
2705 nativefuncs->stderr_write : NULL), sjme_bootfailmessage, 0,
2706 sizeof(sjme_bootfailmessage) / sizeof(sjme_jbyte), error);
2708 /* Force error to be on-screen. */
2709 rv->supervisorokay = 0;
2710 sjme_printerror(rv, error);
2712 /* Cleanup. */
2713 sjme_free(rv);
2714 sjme_free(ram);
2715 sjme_free(conf);
2717 /* If a pre-set ROM is not being used, make sure it gets cleared. */
2718 if (rv->presetrom == NULL)
2719 sjme_free(rom);
2721 return NULL;
2724 /* Memory map the option JAR, if available. */
2725 if (nativefuncs->optional_jar != NULL)
2726 if (nativefuncs->optional_jar(&optionjar, &i) != 0)
2728 rv->optionjar = sjme_vmmmap(vmem, 0, optionjar, i, error);
2729 if (rv->rom == NULL)
2731 sjme_seterror(error, SJME_ERROR_VMMMAPFAIL, 0);
2733 sjme_free(rv);
2734 sjme_free(ram);
2735 sjme_free(conf);
2736 if (rv->presetrom == NULL)
2737 sjme_free(rom);
2739 return NULL;
2743 /* The JVM is ready to use. */
2744 return rv;