The Elements of Computing Systems: Building a Modern Computer from First Principles (35 page)

BOOK: The Elements of Computing Systems: Building a Modern Computer from First Principles
6.81Mb size Format: txt, pdf, ePub
■ function void
printString
(String s): prints s starting at the cursor location and advances the cursor appropriately;
■ function void
printInt
(int i): prints i starting at the cursor location and advances the cursor appropriately;
■ function void
println
(): advances the cursor to the beginning of the next line;
■ function void
backSpace
(): moves the cursor one column back.
 
Screen
This class allows drawing graphics on the screen. Column indices start at 0 and are left-to-right. Row indices start at 0 and are top-to-bottom. The screen size is hardware-dependant (in the Hack platform: 256 rows by 512 columns).
 
■ function void
init
(): for internal use only;
■ function void
clearScreen
(): erases the entire screen;
■ function void
setColor
(boolean b): sets a color (white = false, black = true) to be used for all further drawXXX commands;
■ function void
drawPixel
(int x, int y): draws the (x,y) pixel;
■ function void
drawLine
(int x1, int y1, int x2, int y2): draws a line from pixel (x1,y1) to pixel (x2,y2);
■ function void
drawRectangle
(int x1, int y1, int x2, int y2): draws a filled rectangle whose top left corner is (x1,y1) and bottom right corner is (x2,y2);
■ function void
drawCircle
(int x, int y, int r): draws a filled circle of radius r <= 181 around (x,y).
 
Keyboard
This class allows reading inputs from a standard keyboard.
■ function void
init
(): for internal use only;
■ function char
keyPressed
(): returns the character of the currently pressed key on the keyboard; if no key is currently pressed, returns 0;
■ function char
readChar
(): waits until a key is pressed on the keyboard and released, then echoes the key to the screen and returns the character of the pressed key;
■ function String
readLine
(String message): prints the message on the screen, reads the line (text until a newline character is detected) from the keyboard, echoes the line to the screen, and returns its value. This function also handles user backspaces;
■ function int
readInt
(String message): prints the message on the screen, reads the line (text until a newline character is detected) from the keyboard, echoes the line to the screen, and returns its integer value (until the first nondigit character in the line is detected). This function also handles user backspaces.
 
Memory
This class allows direct access to the main memory of the host platform.
 
■ function void
init
(): for internal use only;
■ function int
peek
(int address): returns the value of the main memory at this address;
■ function void
poke
(int address, int value): sets the contents of the main memory at this address to value;
■ function Array
alloc
(int size): finds and allocates from the heap a memory block of the specified size and returns a reference to its base address;
■ function void
deAlloc
(Array o): De-allocates the given object and frees its memory space.
 
Sys
This class supports some execution-related services.
■ function void
init
(): calls the init functions of the other OS classes and then calls the Main.main () function. For internal use only;
■ function void
halt
(): halts the program execution;
■ function void
error
(int errorCode): prints the error code on the screen and halts;
■ function void
wait
(int duration): waits approximately duration milliseconds and returns.
9.3 Writing Jack Applications
Jack is a general-purpose programming language that can be implemented over different hardware platforms. In the next two chapters we will develop a Jack compiler that ultimately generates binary Hack code, and thus it is natural to discuss Jack applications in the Hack context. This section illustrates briefly three such applications and provides general guidelines about application development on the Jack-Hack platform.
 
Examples
Four sample applications are illustrated in figure 9.11. The Pong game, whose Jack code is supplied with the book, provides a good illustration of Jack programming over the Hack platform. The Pong code is not trivial, requiring several hundred lines of Jack code organized in several classes. Further, the program has to carry out some nontrivial mathematical calculations in order to compute the direction of the ball’s movements. The program must also animate the movement of graphical objects on the screen, requiring extensive use of the language’s graphics drawing services. And, in order to do all of the above quickly, the program must be efficient, meaning that it has to do as few real-time calculations and screen drawing operations as possible.
Figure 9.11
Screen shots of sample Jack applications, running on the Hack computer. Hangman, Maze, Pong, and a simple data processing program.
 
Application Design and Implementation
The development of Jack applications over a hardware platform like Hack requires careful planning (as always). First, the application designer must consider the physical limitations of the hardware, and plan accordingly. For example, the dimensions of the computer’s screen limit the size of the graphical images that the program can handle. Likewise, one must consider the language’s range of input/output commands and the platform’s execution speed, to gain a realistic expectation of what can and cannot be done.
As usual, the design process normally starts with a conceptual description of the application’s behavior. In the case of graphical and interactive programs, this may take the form of hand-written drawings of typical screens. In simple applications, one can proceed to implementation using procedural programming. In more complex tasks, it is advisable to first create an object-based design of the application. This entails the identification of classes, fields, and subroutines, possibly leading to the creation of some API document (e.g., figure 9.3a).
Next, one can proceed to implement the design in Jack and compile the class files using a Jack compiler. The testing and debugging of the code generated by the compiler depend on the details of the target platform. In the Hack platform supplied with the book, testing and debugging are normally done using the supplied VM emulator. Alternatively, one can translate the Jack program all the way to binary code and run it directly on the Hack hardware, or on the CPU emulator supplied with the book.
 
The Jack OS
Jack programs make an extensive use of the various abstractions and services supplied by the language’s standard library, also called the Jack OS. This OS is itself implemented in Jack, and thus its executable version is a set of compiled .vm files—just like the user program (following compilation). Therefore, before running any Jack program, you must first copy into the program directory the .vm files comprising the Jack OS (supplied with the book). The chain of command is as follows: The computer is programmed to first run the Sys.init. This OS function, in turn, is programmed to start running your Main.main function. This function will then call various subroutines from both the user program and from the OS, and so on.
Although the standard library of the Jack language can be extended, readers will perhaps want to hone their programming skills elsewhere. After all, we don’t expect Jack to be part of your life beyond this book. Therefore, it is best to view the Jack/ Hack platform as a given environment and make the best out of it. That’s precisely what programmers do when they write software for embedded devices and dedicated processors that operate in restricted environments. Instead of viewing the constrains imposed by the host platform as a problem, professionals view it as an opportunity to display their resourcefulness and ingenuity. That’s why some of the best programmers in the trade were first trained on primitive computers.
9.4 Perspective
Jack is an “object-based” language, meaning that it supports objects and classes, but not inheritance. In this respect it is located somewhere between procedural languages like Pascal or C and object-oriented languages like Java or C++. Jack is certainly more “clunky” than any of these industrial-strength programming languages. However, its basic syntax and semantics are not very different from those of modern languages.
Some features of the Jack language leave much to be desired. For example, its primitive type system is, well, rather primitive. Moreover, it is a weakly typed language, meaning that type conformity in assignments and operations is not strictly enforced. Also, one may wonder why the Jack syntax includes keywords like do and let, why curly brackets must be used even in single statement blocks, and why the language does not enforce a formal operator priority.
Well, all these deviations from normal programming languages were introduced into Jack with one purpose: to allow the development of elegant and simple Jack compilers, as we will do in the next two chapters. For example, when parsing a statement (in any language), it is much easier to handle the code if the first token of the statement indicates which statement we’re in. That’s why the Jack syntax includes the do and let keywords, and so on. Thus, although Jack’s simplicity may be a nuisance when writing a Jack application, you will probably be quite grateful for it while writing the Jack compiler in the next two chapters.
Most modern languages are deployed with standard libraries, and so is Jack. As in Java and C#, this library can also be viewed as an interface to a simple and portable operating system. In the Jack-Hack platform, the services supplied by this OS are extremely minimal. They include no concurrency to support multi-threading or multi-processing, no file system to support permanent storage, and no communication. At the same time, the Jack OS provides some classical OS services like graphic and textual I/O (in very basic forms), standard implementation of strings, and standard memory allocation and de-allocation. Additionally, the Jack OS implements various mathematical functions, including multiplication and division, normally implemented in hardware. We return to these issues in chapter 12, where we will build this simple operating system as the last module in our computer system.
9.5 Project
Objective
The hidden agenda of this project is to get acquainted with the Jack language, for two purposes: writing the Jack compiler in Projects 10 and 11, and writing the Jack operating system in Project 12.
 
Contract
Adopt or invent an application idea, for example, a simple computer game or some other interactive program. Then design and build the application.
 
Resources
You will need three tools: the Jack compiler, to translate your program into a set of .vm files, the VM emulator, to run and test your translated program, and the Jack Operating System.
 
The Jack OS
The Jack Operating System is available as a set of .vm files. These files constitute an implementation of the standard library of the Jack programming language. In order for any Jack program to execute properly, the compiled .vm files of the program must reside in a directory that also contains all the .vm files of the Jack OS. When an OS-oriented error is detected by the Jack OS, it displays a numeric error code (rather than text, which wastes precious memory space). A list of all the currently supported error codes and their textual descriptions can be found in the file projects/09/OSerrors.txt.
 
Compiling and Running a Jack Program
0. Each program must be stored in a separate directory, say Xxx. Start by creating this directory, then copy all the files from tools/OS into it.

Other books

His Little Runaway by Emily Tilton
Wraith by Claire, Edie
The Awakener by Amanda Strong
Krewe Daddy by Margie Church
Domination by Lyra Byrnes
Casting Bones by Don Bruns
Red Orchestra by Anne Nelson