Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

picoPERC: A Small-Footprint Dialect of Java


Dr. Dobb's Journal March 1998: picoPERC: A Small-Footprint Dialect of Java

Kelvin is president of NewMonics and can be contacted at http://www.newmonics .com/ or [email protected].


Embedded computers are everywhere. In grocery stores, for example, they tally up your bill, gather consumer-profile information about your buying habits, provide online access to your bank and credit-card accounts, and open the doors for you when you are ready to leave. In cars, embedded computers unlock doors, roll down windows, adjust mirrors, control fuel injection, report speed, and monitor for situations that require antilock braking or air-bag deployment. At home, they control the circulation and temperature of air, microwave and convection ovens, dish and clothes washers, television sets, stereo systems, cable or satellite TV converters, and remote-control devices. Projections by companies such as Motorola, in fact, suggest that by the year 2000, the average number of microcontrollers in a typical home will exceed 200. Furthermore, the report "Software 2000: A View of the Future" (ICL, 1994) projects that by the year 2010, there will be ten times as many software developers working on embedded-system software as will be developing commercial software for use with desktop computers and servers.

Java is attractive to embedded-systems developers for many of the same reasons it appeals to desktop/Internet programmers. Unlike C++, Java has a clean and simple design. Java is easy to learn and easy to use. It is object oriented and strongly typed. Java compilers prohibit many error-prone practices that are permitted in C and C++. Beyond the standard math, file handling, and text-formatting libraries, Java also provides standard libraries for Internet, multimedia, and multithreaded programming. Finally, Java provides garbage collection, a high-level service that automatically reclaims memory for objects that are no longer in use. Even though Java development tools and compilers are still relatively immature, embedded-systems companies are already experimenting with this new technology. Engineers at a large telecommunications company recently reported they were twice as productive writing code in Java than in C++. Engineers from the same company reported that they had been disappointed with C++, in part because they had found it necessary to spend millions of dollars finding and fixing memory leaks in their C++-based telecommunications software. Another issue raised by these engineers was Java's impact on human resources. They had found it difficult to recruit competent C++ programmers and subcontractors. Even more difficult was finding people skilled in this company's in-house proprietary languages and tools. These engineers felt that it would be easier to find skilled Java programmers, or, if necessary, to train existing technical staff in effective use of Java.

The Portable Executive for Reliable Control (PERC) is a clean-room implementation of the Java Virtual Machine developed by NewMonics (my company). PERC is designed specifically for embedded and real-time programming applications. Some of the qualities of PERC that make it especially well suited for these applications are its incremental defragmenting real-time garbage collector; a special ROMizer tool that allows Java bytecodes to be executed out of ROM memory and supports ahead-of-time compilation of Java bytecodes to native-machine language; a Minimal Windows Toolkit that is approximately one third the size of Java's Abstract Windows Toolkit; and optional real-time extensions that allow real-time tasks to reserve resources for periodic execution, a particular amount of live memory, and a particular rate for dynamic memory turnover. In supporting the real-time extensions, PERC converts the various memory requests into a CPU-time requirement for garbage collection. Then it uses rate-monotonic analysis to determine whether the workload representing all application-level tasks combined with the garbage-collection task can meet the desired real-time constraints. Once CPU time and memory budgets have been granted, PERC enforces the budgets. Tasks are not allowed to run longer or allocate more memory than was budgeted.

Shrinking the memory footprint is of prime importance in tailoring Java implementations for embedded systems. For consumer electronics products shipped in the millions, every penny shaved from unit manufacturing costs adds up to a significant savings. Handheld devices must be small and lightweight. Battery-powered devices must operate on very low current. picoPERC is a Java subset in which the core Virtual Machine implementation fits in less than 64 KB of memory. This 64-KB footprint is nearly 1/16th the size of JavaSoft's yet-to-be-defined EmbeddedJava and over 50 times smaller than typical Enterprise Java implementations.

picoPERC consists of a core virtual machine upon which optional extensions can be layered. Unlike standard Java, the picoPERC core lacks support for floating-point numbers, 64-bit integers, automatic garbage collection, the standard lang, util, io, and net class libraries, and dynamic bytecode loading and verification. All of these capabilities can be added to the picoPERC core under programmer control.

With so much of standard Java missing from the picoPERC core, you might wonder which, if any, of the traditional Java benefits are supported by picoPERC. The main benefit is that the source language is the same as standard Java. This means that if you are developing very small, deeply embedded systems, you can use the same language and development tools you use for larger embedded systems. Also, this means that picoPERC programmers benefit from the simplicity and consistency of the Java language design, and from the strong type checking performed by Java compilers. Another benefit of picoPERC is that it uses Java's portable bytecode representation. This means that portable software components can be developed or delivered by multiple independent suppliers and integrated in binary form, without requiring source code access for system integration. Finally, because picoPERC uses the same byte code representation as traditional Java, it is possible to run, evaluate, and debug picoPERC programs using traditional Java Virtual Machines and integrated development environments. Once the software development effort is done, the ROMizer tool can be used to target the bytecode representation to ROM memory for execution by the picoPERC Virtual Machine.

Black Jack Application

Several months ago, a customer asked us to assist with the development of an application that could demonstrate Java's benefits to management in order to obtain funding approval for development of a larger application. The sample application would have to run on existing hardware, which limited the RAM memory to one MB, restrict output to a two-line by 32-character display, and take all input from a numeric keypad. We wrote the Black Jack program, which I'll present in this article. The source code for the program is available electronically (see "Resource Center," page 3).

The program acts as a Black Jack dealer for a single human player. Before the game begins, the dealer asks how much the user would like to bet on the game. The following interaction indicates that the user's account has $95, of which the user bets $5.

[95]Bet:
5

The computer starts the game by dealing two cards for itself and two for the player. One of the dealer's cards is face down. All other cards are face up. The following display indicates that the dealer has one face down card and one Ten of Hearts. The player has a Nine of Diamonds and Ace of Clubs.

D> * TH
P> 9D AC

The dealer waits for the user to request an action. The user types "s" to stay with the current hand, or "h" (for hit) to request an additional card. Once the user types "s," the dealer begins dealing additional cards to itself. In this case, the dealer also stays, resulting in a tie game. This is represented as:

D Ties> QH TH
P Ties> 9D AC

Figure 1 shows a graphical version of the Black Jack program.

Implementing Black Jack

The main functionality of Black Jack is implemented by the following object (class) definitions:

  • Card represents each card of the deck in terms of suit and rank.
  • Deck represents a shuffled deck of 52 cards and provides methods to begin a new game and deal a card. When a new game begins, all cards dealt in the previous hand are added to the deck's pile of used cards. If the shuffled deck is empty when a new card is to be dealt, the pile of used cards is reshuffled and the next card is dealt from the result.
  • Hand represents the cards dealt to a particular player. The toString() method returns a string representation of the cards held in the hand. The displayCards() method causes the cards to be drawn on a GUI device. This method did not exist in the first implementation of Black Jack; it was added to the program when we ported Black Jack to an embedded system that supported a 600×800 pixel flatpanel VGA screen. The addCard() method adds a new card to the hand. The calcValue() method returns the value of the hand. The empty() method discards all the cards in the current hand, in preparation for a new game. The hide() and reveal() methods control whether the first card in the hand is face down.

Unlike PERC and Java, the picoPERC core does not support automatic garbage collection. Thus, it is necessary to explicitly delete each object after its useful lifetime has expired. This Black Jack program is written as a persistent embedded program. Black Jack starts when the embedded computer is powered up. It continues to run until the computer is powered down. There is no need to ever reclaim the main data structures of the program. Black Jack allocates 52 Card objects to represent the cards of a standard deck. These cards are never recycled. They are simply moved back and forth between the deck, the dealer's hand, and the player's hand. The only dynamically allocated object that must be explicitly reclaimed is the string created by Hand.toString(). Note the invocations of MM.delete() in the showPlayer() and showDealer() methods of the BlackJack class.

To reduce memory footprint, picoPERC does not include all of the standard library services that are built into standard Java. Since these services are redundant with the services provided by many embedded and real-time operating systems, the services can be easily implemented using native methods. A PERC native method is a method implemented by a C program. In the Black Jack program, native methods implement keypad input, LED output, graphics output, and random number generation. The interfaces following represent these services:

  • Input is an interface that describes the getBet() and getAction() methods. These methods are used to determine how much money the player wants to bet and whether the player wants to receive another card.
  • Output is an interface that describes the clearCardArea(), drawCard(), and print() methods. clearCardArea() erases all of the cards that had been previously drawn. drawCard() draws a single card at a selected position within the card area. print() displays a single integer or a single string of characters in the text window.
  • RandGen is an interface that describes generate(), a method that produces a random integer number.

These are represented as interfaces because we want to provide different implementations of these services, depending on execution environment. All of the code can be run either on a traditional Java Virtual Machine or on a picoPERC Virtual Machine.

For development, testing, and debugging, we used KeyboardViaJava to implement Input, ASCIIViaJava to implement Output, and RandGenViaJava to implement RandGen. These classes implement the required services using standard Java libraries. This is portable and convenient, but it adds considerably to the size of the application because it requires inclusion of the standard Java libraries. Once the basic functionality of the application had been tested and debugged, we ported the code to the small LED embedded device by replacing these classes with KeyboardViaNative, ASCIIViaNative, and RandGenViaNative, respectively.

These three classes use native methods, which are not shown, to implement the various services. The ASCIIViaNative methods assume the output device supports only text output. The corresponding clearCardArea() and drawCard() implementations are empty, meaning that there is no attempt to display any graphics on this device.

Later, we ported the code to the VGA flatpanel device by modifying the implementations of KeyboardViaNative and RandGenViaNative, and by replacing ASCIIViaNative with class GUI. The appropriate implementation of native methods depends on the underlying hardware and the services that are provided by the host operating system.

Preparing the picoPERC ROM Image

After the Black Jack program was tested, we prepared a version to be placed into the embedded device. First, we compiled the various Java source files (also available electronically) using the javac program supplied in JavaSoft's JDK 1.0.2:

javac BlackJack.java Deck.java
   Hand.java Card.java
javac Input.java Output.java
   RandGen.java 
javac KeyboardViaJava.java
   ASCIIViaJava.java
   RandGenViaJava.java

We used our ROMizer tool to preload the various class files. The ROMizer resolves symbolic references and replaces certain byte code instructions with more efficient representations. The command-line invocation:

romize -f %perc%\images\picoperc
classes	-f BlackJack.classes

invokes the ROMizer, telling it to preload all of the classes identified in the %perc%\images\picoperc.classes and BlackJack.classes files. %perc%\images\ picoperc.classes names the files that represent the core picoPERC classes. Included among these are simplified definitions of java.lang.Class and java.lang.String and certain exceptions that may be thrown by the Java interpreter. BlackJack.classes names the classes that represent the Black Jack demo. For each loaded class, the ROMizer automatically loads all classes that are directly referenced by the class if those classes have not already been loaded.

We compiled and linked an earlier version of the Black Jack program for the ARM processor running on a Pixel Press board supplied by Applied Data Systems (http://www.flatpanel.com/) and analyzed the resulting memory image. Table 1 describes the memory layout. The subtotal is 4344 bytes larger than the actual size of the load image. This is because the subtotal was calculated by summing individual object file sizes, whereas the total load image size is the size of the linked program. Certain information is discarded from the object files in the process of linking the various files together. We are currently working on a number of optimizations designed to shrink the in-memory sizes of the Java classes by approximately 50 percent.

Acknowledgment

Simanta Mitra and Paul Thompson first ported Black Jack to an embedded computer with only an LED device. Steve Lee ported Black Jack to the picoPERC core. Jim Lathrop and Jason Britton ported the resulting Black Jack program to a Pixel Press ARM computer by Applied Data Systems. Finally, Steve Lee assisted in polishing the Black Jack code for public distribution.

DDJ


Copyright © 1998, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.