The contents of this file are subject to the GNU General Public License (GPL) Version 2 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, without warranty of any kind, either expressed or implied. See the License for the specific language governing rights and limitations under the License. This file was originally developed as part of the software suite that supports the book "The Elements of Computing Systems" by Nisan and Schocken, MIT Press 2005. If you modify the contents of this file, please document and mark your changes clearly, for the benefit of others. Contents -------- 1. Directory Structure and Compilation Instructions 2. Build Instructions 3. The Chip API for Implementation of Chips in Java 4. The VMCode API for Implementation of VM Functions/Classes in Java Directory Structure and Compilation Instructions: ------------------------------------------------- InstallDir - the installation directory of the software suite (to which the compiled code should be copied) HackPackageSource - should be compiled and zipped into Hack.jar and coppied to InstallDir/bin/lib HackGUIPackageSource - should be compiled and zipped into HackGUI.jar and coppied to InstallDir/bin/lib CompilersPackageSource - should be compiled and zipped into Compilers.jar and coppied to InstallDir/bin/lib SimulatorsPackageSource - should be compiled and zipped into Simulators.jar and coppied to InstallDir/bin/lib SimulatorsGUIPackageSource - should be compiled and zipped into SimulatorsGUI.jar and coppied to InstallDir/bin/lib BuiltInChipsSource - should be compiled and copied to InstallDir/builtInChips BuiltInVMCodeSource - should be compiled and copied to InstallDir/builtInVMCode MainClassesSource - should be compiled and copied to InstallDir/bin/classes Build Instructions ------------------ This project was pulled from the zipped source on the Nand2Tetris site as of version 2.5.7. The original source did not come with automated build scripts, so the Gradle build system was added to the project, while leaving the existing project directory structure in tact. Simultaneously, the project was compiled with Java 11 and a few minor incompatibilities were fixed. Windows To build the project: `gradlew.bat build` To run an application within the project: `gradlew.bat runCPUEmulator` To build a redistributable zip: `gradlew.bat assembleDist` To see gradle tasks: `gradlew.bat tasks` *nix To build the project: `./gradlew build` To run an application within the project: `./gradlew runCPUEmulator` To build a redistributable zip: `./gradlew assembleDist` To see gradle tasks: `./gradlew tasks` Artifacts from the assembleDist task will be located in ./build/distributions. You should be able to unzip the distribution at any location, and assuming a JRE is installed, run the appropriate .sh or .bat file and the application should run. The Chip API for Implementation of Chips in Java ------------------------------------------------ The Nand2Tetris Software Suite allows the implementation in Java of new chips for use with the Hardware Simulator via the Chip API which is henceforth described. This feature allows both the ability to achieve greater simulation speed and the ability to provide students with working chips without disclosing their implementation. It is strongly advised, before implementing a chip, to browse through the implementations of chips provided with the Nand2Tetris Software Suite. The HDL files of these chips are located under the InstallDir/builtInChips directory and Java sources for these chips - under the BuiltInChipsSource directory. The input and output pins for each chip are specified by an HDL file for the chip which should bare the name of the chip followed by a .hdl suffix and be located in the InstallDir/builtInChips directory. The HDL should be formed like a normal HDL file (see the Hardware Simulator Tutorial supplied at www.nand2tetris.org) and specify the chip name and all the input and output pins in the usual manner. Instead of the list of gates which usually comprise the implementation, the line: BUILTIN ChipName; should appear (where ChipName should be substituted for the name of the chip). In addition to the HDL file for the chip, each chip should be implemented in a seprate class named the same as the chip. The compiled implementation should reside in the builtInChips package somewhere in the CLASSPATH (for example the compiled counterparts of the aforementioned chip provided with the Nand2Tetris Software Suite are located under the InstallDir/builtInChips directory). The chip class should extend (either directly or indirectly) the Hack.Gates.BuiltInGate class and may overwrite any of the following three methods (which by default do nothing): void clockUp() - called when the clock goes up (useful for clocked chips) void clockDown() - called when the clock goes down (useful for clocked chips) void reCompute() - called whenever any of the input pins changes (useful for combinatorial chips) Required initialization code may be placed in a constructor accepting no arguments and any number of data members may be defined. The code for the chip may access the input and outpu pins via the data members inputPins and outputPins, respectively. The value of a b-bit input pin/bus which was declared n-th (starting from zero) in the chip HDL file can be accessed by evaluating the b least significant bits of the value returned by calling inputPins[n].get(). The value of a b-bit output pin/bus which was declared n-th (starting from zero) in the chip HDL file can be updated to v (a value in which all but the v least significant bits are zero) by calling outputPins[n].set(v). The Nand2Tetris Software Suite Hardware Simulator Chip Java API also provides support for implementing a GUI visualization of the chip (similar to the one implemented by the provided ALU, RAM*, ROM32K, ARegister and DRegister chips). Implementing chips should extend the Hack.Gates.BuilInGateWithGUI class. See the implementations of this class (located in SimulatorsPackageSource/Hack/Games/BuiltInGateWithGUI.java) and of the aforementioned gui-powered chips for examples and information regarding additional methods which should be implemented by gui-powered chips. The VMCode API for Implementation of VM Functions/Classes in Java ----------------------------------------------------------------- The Nand2Tetris Software Suite allows the implementation in Java of new VM functions for use by the VM Emulator via the VMCode API which is henceforth described. This feature allows both the ability to achieve much greater simulation speed and the ability to allow VM programs the access to features which aren't otherwise available or feasible on the Hack platform (such features may include e.g. time & date queries, random number generation using an RNG daemon and performing complex calculation using 3rd-party closed libraries). Whenever the VM Emulator encounters a call to a VM function with a prefix for which the current program doesn't contain a *.vm implementation (e.g. a call to "Screen.drawPixel" when the current program doesn't contain a file called Screen.vm), the VM Emulator will invoke the Java implementation for that VM function, if such an implementation exists. This priority mechanism is similar to the priority mechanism of the Chip API in the Hardware Simulator. Since this mechanism is not discussed in the book, a dialog will pop up to confirm the usage of Java implementation of VM functions upon loading of a program in which such usage is required. It is strongly advised, before implementing a new VM function, to browse through the implementation of the Jack OS supplied in the Nand2Tetris Software Suite. The Java sources for this implementation are located under the BuiltInVMCodeSource directory. It should be noted that since the VMCode API allows the implementation of functions in the VM level and not in the Jack level, there is no concept of constructors or methods in this API but only a concept of functions. Functions may conceptually be class methods and therefore receive a this-style pointer as the first argument (e.g., as the String.* functions do) or may conceptually be class constructors which return a this-style pointer which they allocated and initialized (e.g. as the String.new function does) but may conceptually be mere functions or static methods (e.g., as the Output.* functions are). Each VM function is implemented by a single Java static method. Since all VM data is 16-bit quantities and Java shorts are 16-bit quantities, all of the arguments to the static method should be Java shorts. For convenience, the static method may return void (a value of 0 will be returned to the calling function), boolean (false will be converted to 0, true to 0xffff), char (will be cast to short and returned) or short. As with normal .vm files (see the VM Emulator Tutorial at www.nand2tetris.org), all VM functions which start with the same prefix (e.g., all VM functions which implement methods, constructors and functions of the same Jack class) are implemented together. In the case of normal .vm files, all such functions are implemented in a single file baring the prefix (e.g., the class name) as its name and therefore all such function share the same static segment. In the case of Java-implemented VM functions, all such functions are implemented by static methods of a single class baring the prefix as its name and therefore may share data using static variables of the class. The compiled class should extend (either directly or indirectly) the Hack.VMEmulator.BuiltInVMClass class and should reside in the builtInVMCode package somewhere in the CLASSPATH (for example the compiled classes implementing the Jack OS supplied in the Nand2Tetris Software Suite are located under the InstallDir/builtInVMCode directory). A Java static method which implements a VM function may communiate with the Virual Machine using any of the following static methods which it inherits from Hack.VMEmulator.BuiltInVMClass: short readMemory(int address) - returns the value stored in the VM memory at the given address (the address argument is an int and not a short for convenience but may only be in the one of the ranges HEAP_START_ADDRESS - HEAP_END_ADDRESS or SCREEN_START_ADDRESS - SCREEN_END_ADDRESS (these are provided as static final constants of the Hack.VMEmulator.BuiltInVMClass). void writeMemory(int address, int value) - changes the value stored in the VM memory at the given address (the value is cast to short and the address must be legal - see above). If data flow animation is on, the change in the VM memory will be animated. short callFunction(String functionName, short[] params) - Calls the named VM function (which may be either be implemented in a normal .vm files or in Java using the VMCode API) with the given parameters. The return from the function is returned. To allow for maximum modularity, this function should be used for all calls to VM functions not implemented by the current class, to ensure that the implementation currently used by the VM Emulator (which may or may not be implemented in Java) is called. short callFunction(String functionName, short param1, ...) - For convenience, versions of the callFunction method are supplied for calling VM functions accepting 0-4 arguments without the need to allocate an array of parameters. void infiniteLoop(String message) - Used to halt the VM program (this is the function called by the supplied Java implementation of the Sys.halt function of the Jack OS). If the optional message is provided (non-null) then a pop-up window is opened to display it. * Important: A Java static method implementing a VM function SHOULD NOT enter a blocking infinite loop * A function calling any of the aforementioned static methods must be declared to throw Hack.VMEmulator.TerminateVMProgramThrowable. An instance of this Throwable class will be thrown by any of the aforementioned static methods if the user decides to restart the VM program (e.g. via the << button). This throwable may be caught by the calling method but must be rethrown. For convenience, the following constants are provided by the Hack.VMEmulator.BuiltInVMClass for use by the classes which extend it: short SCREEN_START_ADDRESS short SCREEN_END_ADDRESS int SCREEN_WIDTH int SCREEN_HEIGHT short HEAP_START_ADDRESS short HEAP_END_ADDRESS short KEYBOARD_ADDRESS short NEWLINE_KEY short BACKSPACE_KEY Finally, it should be noted that the Java language does not allow the declaration of a method called "new" (such as the String.new and Array.new constructors from the Jack OS). The implementation of such VM functions using the VMCode API is achieved by implementing a static Java method called "NEW" (all capitals) - the VM Emulator will call the "NEW" function whenever it receives a request for calling the "new" function.