diff --git a/.gitignore b/.gitignore index 36f4b7b..b25964e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ classes.txt doc/*.pdf doc/*.css doc/*.html +doc/entry*.svg *.idv *.aux *.4tc diff --git a/doc/boot.dot b/doc/boot.dot new file mode 100644 index 0000000..018d0e9 --- /dev/null +++ b/doc/boot.dot @@ -0,0 +1,64 @@ +digraph jvm_boot { + + newrank=true; + + + boot_rom [shape=box label="Dreamcast Boot ROM"] + first_read [shape=box label="1ST_READ.BIN"] + discarded [shape=ellipse label="(discarded/overwritten)"] + ip_bin [shape=box label="gdrom_jvm_boot.bin (“ip.bin”)"] + + boot_rom -> first_read -> discarded + boot_rom -> ip_bin + + subgraph cluster_jvm_bin { + label=" boot class files (embedded inside jvm.bin)" + + jvm_bin [shape=box label="jvm.bin"] + + boot_class_files [shape=plaintext label=< + + + + + + + +
example/GdromClassLoader.class
sega/dreamcast/gdrom/GdromExtentReader.class
sega/dreamcast/gdrom/GdromProtocol.class
sega/dreamcast/gdrom/GdromCommandPacketFormat.class
filesystem/iso9660/VolumeParser.class
jvm/internal/Loader.class
+ >] + } + + subgraph cluster_application { + label=" application class files (files on the iso9660 filesystem)" + + main [shape=box label="Main.class"] + + class_files [shape=plaintext label=< + + + + + + + + + + +
example/JavaCube.class
sega/dreamcast/holly/Core.class
sega/dreamcast/holly/VideoOutput.class
sega/dreamcast/holly/RegionArray.class
sega/dreamcast/holly/TAFIFOPolygonConverter.class
sega/dreamcast/holly/TAGlobalParameter.class
sega/dreamcast/holly/TAVertexParameter.class
sega/dreamcast/holly/TextureMemoryAllocation.class
model/CubeModel.class
+ >] + } + + {rank=same; jvm_bin; boot_class_files} + + {rank=same; main; class_files} + + ip_bin -> jvm_bin + jvm_bin -> boot_class_files + + GdromClassLoader [shape=box label="GdromClassLoader.class"] + + jvm_bin -> GdromClassLoader -> main + + main -> class_files + +} \ No newline at end of file diff --git a/doc/boot.svg b/doc/boot.svg new file mode 100644 index 0000000..f3492a9 --- /dev/null +++ b/doc/boot.svg @@ -0,0 +1,151 @@ + + + + + + +jvm_boot + + +cluster_jvm_bin + +                    boot class files (embedded inside jvm.bin) + + +cluster_application + +                             application class files (files on the iso9660 filesystem) + + + +boot_rom + +Dreamcast Boot ROM + + + +first_read + +1ST_READ.BIN + + + +boot_rom->first_read + + + + + +ip_bin + +gdrom_jvm_boot.bin (“ip.bin”) + + + +boot_rom->ip_bin + + + + + +discarded + +(discarded/overwritten) + + + +first_read->discarded + + + + + +jvm_bin + +jvm.bin + + + +ip_bin->jvm_bin + + + + + +boot_class_files + +  example/GdromClassLoader.class + +  sega/dreamcast/gdrom/GdromExtentReader.class + +  sega/dreamcast/gdrom/GdromProtocol.class + +  sega/dreamcast/gdrom/GdromCommandPacketFormat.class + +  filesystem/iso9660/VolumeParser.class + +  jvm/internal/Loader.class + + + +jvm_bin->boot_class_files + + + + + +GdromClassLoader + +GdromClassLoader.class + + + +jvm_bin->GdromClassLoader + + + + + +main + +Main.class + + + +class_files + +  example/JavaCube.class + +  sega/dreamcast/holly/Core.class + +  sega/dreamcast/holly/VideoOutput.class + +  sega/dreamcast/holly/RegionArray.class + +  sega/dreamcast/holly/TAFIFOPolygonConverter.class + +  sega/dreamcast/holly/TAGlobalParameter.class + +  sega/dreamcast/holly/TAVertexParameter.class + +  sega/dreamcast/holly/TextureMemoryAllocation.class   + +  model/CubeModel.class + + + +main->class_files + + + + + +GdromClassLoader->main + + + + + diff --git a/doc/build.sh b/doc/build.sh new file mode 100644 index 0000000..59b2c05 --- /dev/null +++ b/doc/build.sh @@ -0,0 +1,15 @@ +make4ht entry.tex "pic-m,pic-equation,svg" + +mv entry.html index.html +mv entry.css index.css + +echo 'img[alt="PIC"] { width: 100%; }' >> index.css +echo '.cmtt-10 { font-size: 0.9em; }' >> index.css +echo 'img[src="index3x.svg"] { height: 2.5em; }' >> index.css +echo 'object[class="graphics"] { width: 100% }' >> index.css + +sed -i '/prefers-color-scheme/d' index.css +sed -i 's| | |g' index.html +sed -i 's/entry.css/index.css/g' index.html +sed -i 's/1.5157em/1.3157em/g' index.css +sed -i 's/1.3195em/1.0195em/g' index.css diff --git a/doc/deploy.sh b/doc/deploy.sh new file mode 100644 index 0000000..2ba9647 --- /dev/null +++ b/doc/deploy.sh @@ -0,0 +1 @@ +rsync -arv * root@az1.idk.st:/var/www/dreamcast/jvm/ diff --git a/doc/entry.tex b/doc/entry.tex new file mode 100644 index 0000000..666ed63 --- /dev/null +++ b/doc/entry.tex @@ -0,0 +1,222 @@ +\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}