1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
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 // --------------------------------------------------------------------------*/
11 * SquirrelJME RatufaCoat Source.
21 /** Sets the error code. */
22 void sjme_seterror(sjme_error
* error
, sjme_jint code
, sjme_jint value
)
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.
40 sjme_jint
sjme_opdecodejint(sjme_vmem
* vmem
, sjme_vmemptr
* ptr
,
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
) &
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.
67 sjme_jint
sjme_opdecodejshort(sjme_vmem
* vmem
, sjme_vmemptr
* ptr
,
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
) &
79 if (rv
& SJME_JINT_C(0x8000))
80 rv
|= SJME_JINT_C(0xFFFF0000);
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.
94 sjme_jint
sjme_opdecodeui(sjme_vmem
* vmem
, sjme_vmemptr
* ptr
,
99 /* Read single byte value from pointer. */
100 rv
= (sjme_vmmreadp(vmem
, SJME_VMMTYPE_BYTE
, ptr
, error
) &
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
) &
111 /* Use read value. */
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.
124 sjme_jint
sjme_opdecodereg(sjme_vmem
* vmem
, sjme_vmemptr
* ptr
,
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
);
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.
153 sjme_jint
sjme_opdecodejmp(sjme_vmem
* vmem
, sjme_vmemptr
* ptr
,
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);
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
;
175 sjme_jint bpp
, pq
, at
, mask
;
181 /* Ignore if out of bounds. */
182 if (x
< 0 || y
< 0 || x
>= jvm
->conw
|| y
>= jvm
->conh
)
185 /* Font dimensions. */
186 fontw
= sjme_font
.charwidths
[0];
187 fonth
= sjme_font
.pixelheight
;
189 /* Normalize to screen space. */
193 /* Character data to draw. */
194 if (sjme_font
.isvalidchar
[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
;
206 xform
= SJME_VMMTYPE_BYTE
;
207 mask
= (SJME_JINT_C(1) << bpp
) - 1;
211 xform
= SJME_VMMTYPE_SHORT
;
212 mask
= SJME_JINT_C(0xFFFF);
216 xform
= SJME_VMMTYPE_INTEGER
;
217 mask
= SJME_JINT_C(0xFFFFFFFF);
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. */
233 /* Draw all pixel scans. */
235 for (cv
= 0; cv
< sjme_font
.bytesperscan
; cv
++, mp
++)
237 /* Get character bits */
240 /* Draw all of them. */
241 for (i
= 0; i
< 8 && c
< fontw
; i
++, c
++)
243 /* Shift the queue up from the last run. */
246 /* Mask it if the color is set? */
247 if ((bits
& sjme_drawcharbitmask
[i
]) != 0)
250 /* Queued bits go up. */
253 /* Only write when there is at least 8! */
257 sjme_vmmwritep(jvm
->vmem
, xform
, &sp
, pq
, error
);
260 pq
= (((pq
& sjme_sh_umask
[bpp
])) >> bpp
);
266 /* Force draw any pixels left over. */
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
;
280 /* There must be a JVM! */
284 /* Write all the bytes to the output. */
285 for (i
= 0; i
< len
; i
++, off
++)
290 /* Draw to the console in supervisor boot mode or if it was not */
292 if ((jvm
->supervisorokay
== 0 || jvm
->squelchfbconsole
== 0) &&
295 /* Carriage return? */
304 /* Draw character? */
308 sjme_console_drawplate(jvm
, jvm
->conx
, jvm
->cony
, b
, error
);
310 /* Move cursor up. */
313 /* New line to print on? */
314 if (jvm
->conx
>= jvm
->conw
)
318 /* Doing a new line? */
321 /* Move the cursor to the start of the next line. */
325 /* Too much text on the screen? Move it up! */
326 if (jvm
->cony
>= jvm
->conh
)
328 /* Move framebuffer up. */
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. */
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. */
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
)
359 return (i
== 0 ? code
: i
);
363 /* Return written bytes. */
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.
378 void sjme_syscall(sjme_jvm
* jvm
, sjme_cpu
* cpu
, sjme_error
* error
,
379 sjme_jshort callid
, sjme_jint
* args
, sjme_jlong_combine
* rv
)
382 sjme_jint ia
, ib
, ic
;
385 sjme_cpustate
* cpustate
;
388 if (jvm
== NULL
|| cpu
== NULL
|| args
== NULL
|| rv
== NULL
)
390 sjme_seterror(error
, SJME_ERROR_INVALIDARG
, 0);
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. */
405 /* Query support for system call. */
406 case SJME_SYSCALL_QUERY_INDEX
:
407 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
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);
437 rv
->lo
= SJME_JINT_C(0);
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)
450 /* Height of the call stack. */
451 case SJME_SYSCALL_CALL_STACK_HEIGHT
:
452 /* Count trace depth. */
454 while (cpustate
!= NULL
)
456 /* Increase the count. */
459 /* Go to deeper depth. */
460 cpustate
= cpustate
->parent
;
463 /* Does not generate errors. */
464 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
468 /* Item within the call stack. */
469 case SJME_SYSCALL_CALL_STACK_ITEM
:
470 /* Find the CPU frame to use. */
475 if (cpustate
== NULL
)
477 *syserr
= SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE
;
482 cpustate
= cpustate
->parent
;
486 /* Depends on the requested item.*/
489 /* The class name. */
490 case SJME_CALLSTACKITEM_CLASS_NAME
:
491 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
492 rv
->lo
= cpustate
->debugclassname
;
495 /* The method name. */
496 case SJME_CALLSTACKITEM_METHOD_NAME
:
497 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
498 rv
->lo
= cpustate
->debugmethodname
;
501 /* The method type. */
502 case SJME_CALLSTACKITEM_METHOD_TYPE
:
503 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
504 rv
->lo
= cpustate
->debugmethodtype
;
508 case SJME_CALLSTACKITEM_SOURCE_FILE
:
509 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
510 rv
->lo
= cpustate
->debugsourcefile
;
514 case SJME_CALLSTACKITEM_SOURCE_LINE
:
515 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
516 rv
->lo
= cpustate
->debugline
;
519 /* The PC address. */
520 case SJME_CALLSTACKITEM_PC_ADDRESS
:
521 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
522 rv
->lo
= cpustate
->pc
;
525 /* Java operation. */
526 case SJME_CALLSTACKITEM_JAVA_OPERATION
:
527 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
528 rv
->lo
= cpustate
->debugjop
;
531 /* Java PC address. */
532 case SJME_CALLSTACKITEM_JAVA_PC_ADDRESS
:
533 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
534 rv
->lo
= cpustate
->debugjpc
;
537 /* Current Task ID. */
538 case SJME_CALLSTACKITEM_TASK_ID
:
539 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
540 rv
->lo
= cpustate
->taskid
;
545 *syserr
= SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE
;
550 /* Get error state. */
551 case SJME_SYSCALL_ERROR_GET
:
552 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
555 if (ia
< 0 || ia
>= SJME_SYSCALL_NUM_SYSCALLS
)
556 ia
= SJME_SYSCALL_QUERY_INDEX
;
558 rv
->lo
= cpu
->syscallerr
[ia
];
561 /* Set error state, return old one. */
562 case SJME_SYSCALL_ERROR_SET
:
563 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
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];
575 /* Load IPC Exception. */
576 case SJME_SYSCALL_EXCEPTION_LOAD
:
577 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
578 rv
->lo
= cpu
->ipcexception
;
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];
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
;
597 /* Depends on the property. */
600 /* Framebuffer address. */
601 case SJME_FB_CONTROL_ADDRESS
:
602 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
603 rv
->lo
= jvm
->framebuffer
->fakeptr
;
606 /* Width of the framebuffer. */
607 case SJME_FB_CONTROL_WIDTH
:
608 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
609 rv
->lo
= jvm
->fbinfo
->width
;
612 /* Height of the framebuffer. */
613 case SJME_FB_CONTROL_HEIGHT
:
614 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
615 rv
->lo
= jvm
->fbinfo
->height
;
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
;
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();
631 /* Frame-buffer format. */
632 case SJME_FB_CONTROL_FORMAT
:
633 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
634 rv
->lo
= jvm
->fbinfo
->format
;
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
;
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;
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
;
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
;
661 /* Unknown property, but there is a framebuffer. */
663 *syserr
= SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE
;
670 case SJME_SYSCALL_FRAME_TASK_ID_GET
:
671 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
672 rv
->lo
= cpustate
->taskid
;
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);
682 /* Set memory to byte value. */
683 case SJME_SYSCALL_MEM_SET
:
684 /* Get address to wipe. */
687 /* The value to store. */
688 ic
= args
[1] & SJME_JINT_C(0xFF);
690 /* Wipe these values! */
692 for (ia
= 0; ia
< ib
; ia
++)
693 sjme_vmmwrite(jvm
->vmem
, SJME_VMMTYPE_BYTE
, pa
, ia
, ic
, error
);
696 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
700 /* Set memory in integer values. */
701 case SJME_SYSCALL_MEM_SET_INT
:
702 /* Get address to wipe. */
705 /* The value to store, is full integer. */
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
,
715 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
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
;
728 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
729 rv
->lo
= jvm
->optionjar
->fakeptr
;
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
;
741 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
742 rv
->lo
= jvm
->optionjar
->size
;
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
);
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
);
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. */
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,
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,
785 /* Unknown descriptor. */
787 *syserr
= SJME_SYSCALL_ERROR_PIPE_DESCRIPTOR_INVALID
;
788 rv
->lo
= SJME_JINT_C(-1);
795 *syserr
= SJME_SYSCALL_ERROR_PIPE_DESCRIPTOR_INVALID
;
796 rv
->lo
= SJME_JINT_C(-1);
801 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
802 rv
->lo
= SJME_JINT_C(1);
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);
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);
825 /* Get supervisor property. */
826 case SJME_SYSCALL_SUPERVISOR_PROPERTY_GET
:
828 if (ia
< 0 || ia
>= SJME_SUPERPROP_NUM_PROPERTIES
)
830 *syserr
= SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE
;
835 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
836 rv
->lo
= cpu
->supervisorprops
[ia
];
840 /* Set supervisor property. */
841 case SJME_SYSCALL_SUPERVISOR_PROPERTY_SET
:
843 if (ia
< 0 || ia
>= SJME_SUPERPROP_NUM_PROPERTIES
)
845 *syserr
= SJME_SYSCALL_ERROR_VALUE_OUT_OF_RANGE
;
850 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
851 rv
->lo
= cpu
->supervisorprops
[ia
] = args
[1];
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
;
865 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
867 rv
->lo
= jvm
->nativefuncs
->millitime(&rv
->hi
);
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
;
881 *syserr
= SJME_SYSCALL_ERROR_NO_ERROR
;
883 rv
->lo
= jvm
->nativefuncs
->nanotime(&rv
->hi
);
887 /* Unknown or unsupported system call. */
889 *syserr
= SJME_SYSCALL_ERROR_UNSUPPORTED_SYSTEM_CALL
;
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 */
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 */
910 sjme_jint_div rv
= {0, 0};
919 /* Disallow division by zero */
925 if ((anum
< 0 && aden
>= 0) || (anum
>= 0 && aden
< 0))
929 anum
= (anum
< 0 ? -anum
: anum
);
930 aden
= (aden
< 0 ? -aden
: aden
);
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
);
949 /* Restore Integers */
950 rv
.quot
= interm
.quot
;
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
969 * @return The number of remaining cycles.
972 sjme_jint
sjme_cpuexec(sjme_jvm
* jvm
, sjme_cpu
* cpu
, sjme_error
* error
,
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);
991 /* Quick register access. */
994 /* Near-Infinite execution loop. */
997 /* Check if we ran out of cycles. */
1002 if ((--cycles
) <= 0)
1006 /* Increase total instruction count. */
1007 jvm
->totalinstructions
++;
1009 /* The zero register always must be zero. */
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
) &
1018 enc
= ((op
>= SJME_ENC_SPECIAL_A
) ? op
: (op
& SJME_ENC_MASK
));
1020 /* Temporary debug. */
1021 #if defined(SJME_DEBUG)
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
,
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
);
1036 /* Depends on the operation. */
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. */
1052 switch (op
& SJME_ENC_COMPARE_MASK
)
1054 case SJME_COMPARETYPE_EQUALS
:
1059 case SJME_COMPARETYPE_NOT_EQUALS
:
1064 case SJME_COMPARETYPE_LESS_THAN
:
1069 case SJME_COMPARETYPE_LESS_THAN_OR_EQUALS
:
1074 case SJME_COMPARETYPE_GREATER_THAN
:
1079 case SJME_COMPARETYPE_GREATER_THAN_OR_EQUALS
:
1084 case SJME_COMPARETYPE_TRUE
:
1088 case SJME_COMPARETYPE_FALSE
:
1093 /* Branch success? */
1100 case SJME_ENC_MATH_REG_INT
:
1101 case SJME_ENC_MATH_CONST_INT
:
1104 ia
= r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
1107 if (enc
== SJME_ENC_MATH_CONST_INT
)
1108 ib
= sjme_opdecodejint(jvm
->vmem
, &nextpc
, error
);
1110 ib
= r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
1112 /* Perform the math. */
1113 switch (op
& SJME_ENC_MATH_MASK
)
1128 ic
= sjme_div(ia
, ib
).quot
;
1132 ic
= sjme_div(ia
, ib
).rem
;
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! */
1149 ic
= ((ia
& sjme_sh_lmask
[ib
]) << ib
);
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! */
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
];
1170 ic
&= sjme_sh_lmask
[31 - ib
];
1185 case SJME_MATH_SIGNX8
:
1186 if (ia
& SJME_JINT_C(0x80))
1187 ic
= (ia
| SJME_JINT_C(0xFFFFFF00));
1189 ic
= (ia
& SJME_JINT_C(0x000000FF));
1192 case SJME_MATH_SIGNX16
:
1193 if (ia
& SJME_JINT_C(0x8000))
1194 ic
= (ia
| SJME_JINT_C(0xFFFF0000));
1196 ic
= (ia
& SJME_JINT_C(0x0000FFFF));
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)));
1207 r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)] = ic
;
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
);
1226 ib
= r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
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
;
1239 case SJME_DATATYPE_CHARACTER
:
1240 case SJME_DATATYPE_SHORT
:
1241 id
= SJME_VMMTYPE_JAVASHORT
;
1244 case SJME_DATATYPE_OBJECT
:
1245 case SJME_DATATYPE_INTEGER
:
1246 case SJME_DATATYPE_FLOAT
:
1247 id
= SJME_VMMTYPE_JAVAINTEGER
;
1253 switch (op
& SJME_MEM_DATATYPE_MASK
)
1255 case SJME_DATATYPE_BYTE
:
1256 id
= SJME_VMMTYPE_BYTE
;
1259 case SJME_DATATYPE_CHARACTER
:
1260 case SJME_DATATYPE_SHORT
:
1261 id
= SJME_VMMTYPE_SHORT
;
1264 case SJME_DATATYPE_OBJECT
:
1265 case SJME_DATATYPE_INTEGER
:
1266 case SJME_DATATYPE_FLOAT
:
1267 id
= SJME_VMMTYPE_INTEGER
;
1272 if ((op
& SJME_MEM_LOAD_MASK
) != 0)
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
]);
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
]);
1303 /* Atomic compare, get, and set. */
1304 case SJME_OP_ATOMIC_COMPARE_GET_AND_SET
:
1307 ia
= r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
1310 ib
= sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
);
1313 ic
= r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
1316 id
= r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
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
);
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
);
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
);
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
);
1371 ia
= sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
);
1372 ib
= sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
);
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
);
1400 case SJME_OP_DEBUG_EXIT
:
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
) &
1411 cpu
->state
.debugjpc
=
1412 sjme_opdecodeui(jvm
->vmem
, &nextpc
, error
);
1416 /* If equal to constant? */
1417 case SJME_OP_IFEQ_CONST
:
1420 ia
= r
[sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
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? */
1435 /* Invoke method. */
1436 case SJME_OP_INVOKE
:
1438 /* Allocate to store old CPU state. */
1439 oldcpu
= sjme_malloc(sizeof(*oldcpu
));
1442 sjme_seterror(error
, SJME_ERROR_NOMEMORY
,
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
++)
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. */
1464 sjme_opdecodereg(jvm
->vmem
, &nextpc
, error
)];
1466 /* Load in register list (wide). */
1467 ib
= sjme_vmmreadp(jvm
->vmem
, SJME_VMMTYPE_BYTE
, &nextpc
,
1469 if ((ib
& SJME_JINT_C(0x80)) != 0)
1471 /* Skip back and read lower value. */
1473 ib
= sjme_opdecodejshort(jvm
->vmem
, &nextpc
, error
);
1476 for (ic
= 0; ic
< ib
; ic
++)
1477 r
[SJME_ARGBASE_REGISTER
+ ic
] = oldcpu
->r
[
1478 sjme_opdecodejshort(jvm
->vmem
, &nextpc
,
1482 /* Narrow format list. */
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
++)
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");
1505 /* Old PC address resumes where this read ended. */
1506 oldcpu
->pc
= nextpc
;
1508 /* Our next PC becomes the target address. */
1510 cpu
->state
.pc
= nextpc
;
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)),
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)),
1543 #if defined(SJME_DEBUG)
1544 fprintf(stderr
, "Load pool %d -> %d/%08x\n",
1545 (int)ia
, (int)r
[ib
], (int)r
[ib
]);
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! */
1559 sjme_seterror(error
, SJME_ERROR_THREADRETURN
,
1560 jvm
->totalinstructions
);
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. */
1578 #if defined(SJME_DEBUG)
1579 fprintf(stderr
, "Return: %d/%08x\n",
1580 (int)r
[SJME_RETURN_REGISTER
],
1581 (int)r
[SJME_RETURN_REGISTER
]);
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
,
1599 #if defined(SJME_DEBUG)
1600 fprintf(stderr
, "Store pool %d <- %d/%08x\n",
1601 (int)ia
, (int)r
[ib
], (int)r
[ib
]);
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)),
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
++)
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
)
1657 /* Perform the system call. */
1658 sjme_syscall(jvm
, cpu
, error
, ia
, cpu
->syscallargs
,
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. */
1669 /* Allocate to store old CPU state. */
1670 oldcpu
= sjme_malloc(sizeof(*oldcpu
));
1673 sjme_seterror(error
, SJME_ERROR_NOMEMORY
,
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] =
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
)
1718 /* Invalid operation. */
1720 sjme_seterror(error
, SJME_ERROR_INVALIDOP
, op
);
1725 /* Check for error. */
1727 if (error
->code
!= SJME_ERROR_NONE
)
1730 /* Set next PC address. */
1731 cpu
->state
.pc
= nextpc
;
1734 /* Return remaining cycles. */
1738 /** Prints the error to the console output. */
1739 void sjme_printerror(sjme_jvm
* jvm
, sjme_error
* error
)
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);
1766 sjme_console_pipewrite(jvm
, po
,
1767 hex
, 0, sizeof(hex
) / sizeof(sjme_jbyte
), error
);
1773 sjme_console_pipewrite(jvm
, po
, &b
, 0, 1, error
);
1779 sjme_console_pipewrite(jvm
, po
, &b
, 0, 1, error
);
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
)
1795 /* Fallback error state. */
1798 memset(&xerror
, 0, sizeof(xerror
));
1805 sjme_seterror(error
, SJME_ERROR_INVALIDARG
, 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? */
1819 if ((--cycles
) <= 0)
1823 /* Ignore CPUs which are not turned on. */
1824 cpu
= &jvm
->threads
[threadid
];
1825 if (cpu
->threadstate
== SJME_THREAD_STATE_NONE
)
1828 /* Execute CPU engine. */
1829 cycles
= sjme_cpuexec(jvm
, cpu
, error
, cycles
);
1831 /* CPU fault, stop! */
1832 if (error
->code
!= SJME_ERROR_NONE
)
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. */
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.
1860 void* sjme_loadrom(sjme_nativefuncs
* nativefuncs
, sjme_jint
* outromsize
,
1864 sjme_nativefilename
* fn
;
1865 sjme_nativefile
* file
;
1866 sjme_jint romsize
, readat
, readcount
;
1869 /* Set error if missing. */
1872 memset(&xerror
, 0, sizeof(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);
1886 /* Load file name used for the native ROM. */
1887 fn
= nativefuncs
->nativeromfile();
1890 sjme_seterror(error
, SJME_ERROR_NONATIVEROM
, 0);
1895 /* Set to nothing. */
1899 file
= nativefuncs
->fileopen(fn
, SJME_OPENMODE_READ
, error
);
1902 /* Need ROM size. */
1903 romsize
= nativefuncs
->filesize(file
, error
);
1905 /* Allocate ROM into memory. */
1906 rv
= sjme_malloc(romsize
);
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
,
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);
1933 /* Otherwise clear. */
1935 sjme_seterror(error
, SJME_ERROR_NONE
, 0);
1940 /* Otherwise fail */
1943 /* Force error to be set. */
1944 sjme_seterror(error
, SJME_ERROR_READERROR
, 0);
1946 /* Free resources. */
1953 /* Read count goes up. */
1954 readat
+= readcount
;
1958 /* Just set error. */
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 */
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.
1987 sjme_jint
sjme_initboot(sjme_jvm
* jvm
, sjme_error
* error
)
1990 sjme_vmemptr bootjar
;
1991 sjme_jint bootoff
, i
, n
, seedop
, seedaddr
, seedvalh
, seedvall
, seedsize
;
1992 sjme_jint bootjaroff
, vrambase
, vrombase
, qq
;
1996 /* Invalid arguments. */
1999 sjme_seterror(error
, SJME_ERROR_INVALIDARG
, 0);
2004 /* Force error to be set. */
2007 memset(&xerror
, 0, sizeof(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
);
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
,
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
);
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
);
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
,
2121 seedvalh
= sjme_vmmreadp(jvm
->vmem
, SJME_VMMTYPE_JAVAINTEGER
, &rp
,
2123 seedvall
= sjme_vmmreadp(jvm
->vmem
, SJME_VMMTYPE_JAVAINTEGER
, &rp
,
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)));
2144 /* Offset value if it is in RAM or JAR ROM. */
2146 seedvalh
+= vrambase
;
2147 else if (seedop
== 2)
2148 seedvalh
+= bootjar
;
2150 /* Write long value. */
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
);
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
);
2166 /* Write narrow value. */
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
);
2177 /* Error was reached? */
2178 if (error
->code
!= SJME_ERROR_NONE
)
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
);
2191 /* Force failure to happen! */
2192 if (error
->code
!= SJME_ERROR_NONE
)
2199 /** Destroys the virtual machine instance. */
2200 sjme_jint
sjme_jvmdestroy(sjme_jvm
* jvm
, sjme_error
* error
)
2203 sjme_cpustate
* oldcpu
;
2209 sjme_seterror(error
, SJME_ERROR_INVALIDARG
, 0);
2215 sjme_seterror(error
, SJME_ERROR_NONE
, 0);
2217 /* Go through and cleanup CPUs. */
2218 for (i
= 0; i
< SJME_THREAD_MAX
; i
++)
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
;
2232 /* Free CPU state. */
2233 if (oldcpu
!= &jvm
->threads
[i
].state
)
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. */
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)
2259 sjme_jint opt
, format
, iv
, it
, wlen
;
2260 sjme_vmemptr
* setpointer
;
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. */
2280 /* Depends on the option. */
2283 /* Java VM Version. */
2284 case SJME_CONFIG_JAVA_VM_VERSION
:
2285 format
= SJME_CONFIG_FORMAT_STRING
;
2290 case SJME_CONFIG_JAVA_VM_NAME
:
2291 format
= SJME_CONFIG_FORMAT_STRING
;
2292 sa
= "SquirrelJME RatufaCoat";
2295 /* Java VM Vendor. */
2296 case SJME_CONFIG_JAVA_VM_VENDOR
:
2297 format
= SJME_CONFIG_FORMAT_STRING
;
2298 sa
= "Stephanie Gawroriski";
2301 /* Java VM E-Mail. */
2302 case SJME_CONFIG_JAVA_VM_EMAIL
:
2303 format
= SJME_CONFIG_FORMAT_STRING
;
2304 sa
= "xerthesquirrel@gmail.com";
2308 case SJME_CONFIG_JAVA_VM_URL
:
2309 format
= SJME_CONFIG_FORMAT_STRING
;
2310 sa
= "https://squirreljme.cc/";
2313 /* The guest depth. */
2314 case SJME_CONFIG_GUEST_DEPTH
:
2318 case SJME_CONFIG_MAIN_CLASS
:
2321 /* Main program arguments. */
2322 case SJME_CONFIG_MAIN_ARGUMENTS
:
2325 /* Is this a MIDlet? */
2326 case SJME_CONFIG_IS_MIDLET
:
2329 /* Define system propertly. */
2330 case SJME_CONFIG_DEFINE_PROPERTY
:
2333 /* Classpath to use. */
2334 case SJME_CONFIG_CLASS_PATH
:
2337 /* System Call: Static field pointer. */
2338 case SJME_CONFIG_SYSCALL_STATIC_FIELD_POINTER
:
2339 format
= SJME_CONFIG_FORMAT_INTEGER
;
2340 setpointer
= &jvm
->syscallsfp
;
2343 /* System Call: Code Pointer. */
2344 case SJME_CONFIG_SYSCALL_CODE_POINTER
:
2345 format
= SJME_CONFIG_FORMAT_INTEGER
;
2346 setpointer
= &jvm
->syscallcode
;
2349 /* System Call: Pool Pointer. */
2350 case SJME_CONFIG_SYSCALL_POOL_POINTER
:
2351 format
= SJME_CONFIG_FORMAT_INTEGER
;
2352 setpointer
= &jvm
->syscallpool
;
2355 /* Unknown, ignore. */
2360 /* No known way to write this? */
2364 /* Write option key. */
2365 sjme_vmmwritep(jvm
->vmem
, SJME_VMMTYPE_JAVASHORT
, &wp
, opt
, error
);
2367 /* Store size location for later write. */
2369 sjme_vmmwritep(jvm
->vmem
, SJME_VMMTYPE_JAVASHORT
, &wp
, 0, error
);
2371 /* Base write pointer. */
2374 /* Set pointer as needed. */
2375 if (setpointer
!= NULL
)
2376 *setpointer
= basep
;
2378 /* Depends on the format. */
2382 case SJME_CONFIG_FORMAT_INTEGER
:
2383 sjme_vmmwritep(jvm
->vmem
, SJME_VMMTYPE_JAVAINTEGER
, &wp
, iv
,
2387 /* Key/value pair. */
2388 case SJME_CONFIG_FORMAT_KEYVALUE
:
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
,
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
);
2406 /* Multiple strings. */
2407 case SJME_CONFIG_FORMAT_STRINGS
:
2411 /* Determine length and round it to 4 bytes. */
2413 while ((wlen
& SJME_JINT_C(3)) != 0)
2415 /* Write padding. */
2416 sjme_vmmwritep(jvm
->vmem
, SJME_VMMTYPE_BYTE
, &wp
, 0, error
);
2420 /* Write to the actual size! */
2421 sjme_vmmwrite(jvm
->vmem
, SJME_VMMTYPE_JAVASHORT
, sizep
, 0, wlen
,
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
,
2438 sjme_jvmoptions nulloptions
;
2444 sjme_jint i
, l
, romsize
;
2445 sjme_framebuffer
* fbinfo
;
2448 /* We need native functions. */
2449 if (nativefuncs
== NULL
)
2452 /* Allocate virtual memory manager. */
2453 vmem
= sjme_vmmnew(error
);
2456 sjme_seterror(error
, SJME_ERROR_VMMNEWFAIL
, error
->code
);
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
);
2475 /* Store virtual memory area. */
2478 /* Virtual map config. */
2479 rv
->config
= sjme_vmmmap(vmem
, 0, conf
, SJME_DEFAULT_CONF_SIZE
, error
);
2480 if (rv
->config
== 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. */
2504 /* Cut RAM allocation size down in half. */
2505 options
->ramsize
/= 2;
2508 /* Failed to allocate the RAM. */
2511 sjme_seterror(error
, SJME_ERROR_NOMEMORY
, options
->ramsize
);
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);
2531 /* Set native functions. */
2532 rv
->nativefuncs
= nativefuncs
;
2534 /* Initialize the framebuffer info, if available. */
2536 if (nativefuncs
->framebuffer
!= NULL
)
2537 fbinfo
= nativefuncs
->framebuffer();
2539 /* Initialize framebuffer, done a bit early to show errors. */
2540 rv
->fbinfo
= fbinfo
;
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;
2559 case SJME_PIXELFORMAT_PACKED_TWO
:
2560 fbinfo
->bitsperpixel
= 2;
2563 case SJME_PIXELFORMAT_PACKED_FOUR
:
2564 fbinfo
->bitsperpixel
= 4;
2567 case SJME_PIXELFORMAT_BYTE_INDEXED
:
2568 fbinfo
->bitsperpixel
= 8;
2571 case SJME_PIXELFORMAT_SHORT_RGB565
:
2572 fbinfo
->bitsperpixel
= 16;
2576 case SJME_PIXELFORMAT_INTEGER_RGB888
:
2577 fbinfo
->bitsperpixel
= 32;
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. */
2589 rv
->conw
= fbinfo
->width
/ sjme_font
.charwidths
[0];
2590 rv
->conh
= fbinfo
->height
/ sjme_font
.pixelheight
;
2593 /* Virtual map framebuffer, if available. */
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);
2610 /* Needed by destruction later. */
2611 rv
->presetrom
= options
->presetrom
;
2614 rom
= options
->presetrom
;
2617 /* Call sub-routine which can load the ROM. */
2618 rom
= sjme_loadrom(nativefuncs
, &romsize
, error
);
2620 /* Could not load the ROM? */
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 */
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
);
2648 sjme_seterror(error
, SJME_ERROR_NOMEMORY
, options
->romsize
);
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
);
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);
2691 if (rv
->presetrom
== 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
);
2717 /* If a pre-set ROM is not being used, make sure it gets cleared. */
2718 if (rv
->presetrom
== 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);
2736 if (rv
->presetrom
== NULL
)
2743 /* The JVM is ready to use. */