\documentclass[20pt]{article} \usepackage{hyperref} \hypersetup{ colorlinks=true, linkcolor=blue, filecolor=magenta, urlcolor=cyan, pdftitle={Dreamcast}, pdfpagemode=FullScreen, } \usepackage{graphicx} \graphicspath{ {./images/} } \title{Dreamcast JVM} \date{} \setcounter{secnumdepth}{0} \begin{document} \maketitle %\href{images/revision-1-inserted.png}{\includegraphics{images/revision-1-inserted.png}} \tableofcontents \section{Introduction} This is a from-scratch JVM implementation for Sega Dreamcast, from zero to 3D spinning translucent textured cubes in 14 days. This is not a port of the JVM from the OpenJDK project, but instead a completely separate and independent implementation that follows the same specification. My time on this project was split roughly 3 ways: \begin{itemize} \item 30\% of my time was spent writing the actual JVM itself \item 30\% on writing new Java libraries for manipulating the Dreamcast hardware \item 30\% on writing a "load Java classes the Dreamcast GDROM drive" loader. \item 10\% on designing Java APIs, (and reviewing existing APIs, e.g: \texttt{java.nio}/\texttt{sun.misc}), particularly related to giving Java code direct and arbitrary access to Dreamcast memory/registers \end{itemize} \section{Demo download} There are three different versions of my demo, depending on how/where you'd like to run this: \subsection{Dreamcast (for physical CD-R; may also work on GD-ROM drive emulators)} \begin{itemize} \item \href{https://dreamcast.idk.st/jvm/jvm-cube-dreamcast.cdi}{jvm-cube-dreamcast.cdi} \end{itemize} \subsection{Dreamcast (for loading via a Dreamcast USB-UART)} \begin{itemize} \item \href{https://dreamcast.idk.st/jvm/jvm-cube-usb-uart.bin}{jvm-cube-usb-uart.bin} \end{itemize} \subsection{Flycast} \begin{itemize} \item \href{https://dreamcast.idk.st/jvm/jvm-cube-flycast.cdi}{jvm-cube-flycast.cdi} \end{itemize} \section{Current status} The current Dreamcast JVM implementation is fairly complete, and will correctly interpret a wide range of Java code correctly. However, the following JVM features are not supported: \begin{itemize} \item exceptions (\texttt{try}/\texttt{catch}/\texttt{finally} in Java) \item separately from the above, \texttt{finally} clauses from Java versions <=1.4 (2002 or earlier) \item \texttt{invokedynamic} (Java lambdas, Java string concatenation, etc...) \item \texttt{synchronized} methods (Java threads are also not implemented) \item runtime type checks (\texttt{instanceof}/\texttt{checkedcast}) on zero-length/null arrays of references \item garbage collection and memory deallocation (technically not required of a JVM, but fair to expect of a JVM that this exists) \end{itemize} The above list is \textit{probably} exhaustive. An attempt to do any of these will trigger a failed assertion, and JVM execution will halt. Other than above list, generally speaking Java class files emitted by any Java version from 6 through 23 inclusive should be compatible with the Dreamcast JVM. \section{How much of this cube demo is written in Java?} To the greatest extent that Java (a language that does not have memory address dereferences as a built-in language construct) is able, all manipulations of Dreamcast hardware and memory state are manipulated directly from Java code. Memory access occurs either directly via the \texttt{Memory.getU4} and \texttt{Memory.putU4} static methods, or indirectly via the Dreamcast DMA controllers. There are no “foreign calls” to C libraries whatsoever. The cube demo is 100\% native Java. \section{How does the demo work?} I believe it could be interesting if it were possible to author code for the Dreamcast without GCC/binutils. In service to this idea, I designed this multi-stage “boot” process. The boot process allows Java class files to be automatically loaded from iso9660 on a CD, rather than embedded in another binary file via a specialized toolchain. This means that anyone with a generic \texttt{javac}, \texttt{mkisofs}, and copies of \texttt{jvm.bin} and \texttt{gdrom\_jvm\_boot.bin} can write code for the Dreamcast. \href{boot.svg}{\includegraphics{boot.svg}} \section{Could the Dreamcast JVM also work on Sega Saturn?} \textbf{Yes.} Java float and double primitives are perhaps the only obstacle. Though the JVM specification does clearly specify that float and double \textbf{must} be in IEEE-754 format, I think it would be interesting to instead implement float as 16.16 fixed-point, and double as 32.32 fixed-point on Saturn in deliberate violation of the specification. Implementing fixed-point operations as primitive types rather than as a “FixedPoint” class in Java would also yield significantly better performance---arithmetic opcode execution is practically "free" compared to the expense of resolving and calling instance methods, not even considering the additional pointer indirections. \section{What about JVM languages other than Java?} Kotlin “hello world” works in the current Dreamcast JVM implementation: \begin{verbatim} fun main() { println("Hello world!") } \end{verbatim} I did not test beyond this. The most probable issue with attempts to run Kotlin/Clojure/Jython, etc... (and in particular their interpreters) on the Dreamcast JVM is most of the Java SE class library is missing. This is not a hard issue to solve; perhaps just slightly tedious at worst. \section{Why can't you just use the Java SE libraries from OpenJDK with the Dreamcast JVM?} The OpenJDK class libraries depend on the OpenJDK JVM's internals (for which there is no formal specification). \section{What about performance? Is the Dreamcast JVM fast?} \textbf{Absolutely not.} On the current JVM implementation, expect performance somewhere on the order of \textbf{100x slower} than semantically-equivalent C code as compiled by GCC. The fact that my cube demo spins at all at relatively nice-looking framerates is a testament to the brute speed of the SH7091 SH4 CPU in the Dreamcast. \section{Could Dreamcast JVM performance improve?} The Dreamcast JVM is a fairly naive bytecode interpreter, so there are myriad ways to improve performance. For long sequences of arithmetic operations (e.g: a vertex transformation function), it is fairly obvious that the solution should be to JIT-compile the bytecodes to SH instructions. I think this should be fairly easy to do. While there have been several "JIT-compile SH to x86" projects (as in Dreamcast emulators), I am not aware of any "JIT-compile [thing] to SH" projects. This adds to the list of reasons why I think this would be interesting to pursue. Indepent of bytecode execution: method lookups, and particularly instance method lookups, are slower than they could be. Perhaps in parallel with the JIT effort, with a more thorough “linking” process, method lookups could likely become about as fast as calling a function pointer in C. \section{Does this mean Java ME games for early 2000's mobile phones could be run on Dreamcast?} I like this idea. Unlike Java SE, which is fairly huge, implementing the Java ME class libraries feels closer to what could be a one-person initiative. It could also be fun to implement the "Mobile 3D Graphics" Java ME profiles for Dreamcast. \section{What about .NET/CLR for Dreamcast/Saturn?} The Dreamcast JVM project would not have been possible without the excellent and freely-available specification: \href{https://docs.oracle.com/javase/specs/jvms/se23/html/index.html}{https://docs.oracle.com/javase/specs/jvms/se23/html/index.html} I am aware that a CLR/CLI/CIL specification exists as well: \href{https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf}{https://ecma-international.org/wp-content/uploads/ECMA-335\_6th\_edition\_june\_2012.pdf} The ECMA-335 specification looks fairly complete/implementable, and I estimate such a project would be roughly on the same level of effort as this JVM project. I don't know. Maybe? \section{Other possible future directions} I am interested in hearing anyone's opinions on any topic even vaguely related to any of the above. \end{document}