/********************************************************************************
* 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. *
********************************************************************************/
package Hack.VMEmulator;
import Hack.CPUEmulator.Keyboard;
import Hack.CPUEmulator.RAM;
import Hack.CPUEmulator.ScreenGUI;
import Hack.ComputerParts.*;
import Hack.Controller.*;
import Hack.Events.ProgramEvent;
import Hack.Utilities.Conversions;
import Hack.Utilities.Definitions;
import Hack.VirtualMachine.HVMInstructionSet;
import java.io.File;
/**
* A virtual machine emulator. Emulates virtual machine code (in VM format).
*
* Recognizes the following variables:
* RAM[i] - the contents of the RAM at location i (short)
* sp - the value of the stack pointer (short)
* local - the address of the Local segment (short)
* local[i] - the contents of the i'th element in the Local segment (short)
* argument - the address of the Argument segment (short)
* argument[i] - the contents of the i'th element in the Argument segment (short)
* this - the address of the This segment (short)
* this[i] - the contents of the i'th element in the This segment (short)
* that - the address of the That segment (short)
* that[i] - the contents of the i'th element in the That segment (short 0..7)
* temp[i] - the contents of the i'th element in the Temp segment (short)
* currentFunction - the name of the current function (String) - READ ONLY
* line - <function name>.<index in function> (String) - READ ONLY
*/
public class VMEmulator extends HackSimulator
implements ComputerPartErrorEventListener {
private static final File INITIAL_BUILTIN_DIR = new File("builtInVMCode");
// variables
private static final String VAR_SP = "sp";
private static final String VAR_RAM = "RAM";
private static final String VAR_LOCAL = "local";
private static final String VAR_ARGUMENT = "argument";
private static final String VAR_THIS = "this";
private static final String VAR_THAT = "that";
private static final String VAR_TEMP = "temp";
private static final String VAR_LINE = "line";
private static final String VAR_CURRENT_FUNCTION = "currentFunction";
// Commands
private static final String COMMAND_VMSTEP = "vmstep";
private static final String COMMAND_ROMLOAD = "load";
private static final String COMMAND_SETVAR = "set";
// The CPU
private CPU cpu;
// The gui of the emulator
private VMEmulatorGUI gui;
// The list of recognized variables.
private String[] vars;
// The keyboard
private Keyboard keyboard;
// The current animation mode
private int animationMode;
/**
* Constructs a new VM Emulator with no GUI component.
*/
public VMEmulator() {
VMProgram program = new VMProgram(null);
MemorySegment[][] segments = new MemorySegment[Definitions.RAM_SIZE][];
RAM ram = new RAM(null, segments, null);
ram.addErrorListener(this);
ram.reset();
// assignes the memory segments
AbsolutePointedMemorySegment stackSegment =
new AbsolutePointedMemorySegment(ram, null);
TrimmedAbsoluteMemorySegment workingStackSegment =
new TrimmedAbsoluteMemorySegment(ram, null);
MemorySegment staticSegment =
new MemorySegment(ram, null);
MemorySegment localSegment =
new MemorySegment(ram, null);
MemorySegment argSegment =
new MemorySegment(ram, null);
MemorySegment thisSegment =
new MemorySegment(ram, null);
MemorySegment thatSegment =
new MemorySegment(ram, null);
MemorySegment tempSegment =
new MemorySegment(ram, null);
stackSegment.reset();
stackSegment.addErrorListener(this);
stackSegment.setEnabledRange(Definitions.STACK_START_ADDRESS,
Definitions.STACK_END_ADDRESS, true);
workingStackSegment.reset();
workingStackSegment.addErrorListener(this);
workingStackSegment.setEnabledRange(Definitions.STACK_START_ADDRESS,
Definitions.STACK_END_ADDRESS, true);
staticSegment.reset();
staticSegment.addErrorListener(this);
localSegment.reset();
localSegment.addErrorListener(this);
argSegment.reset();
argSegment.addErrorListener(this);
thisSegment.reset();
thisSegment.addErrorListener(this);
thatSegment.reset();
thatSegment.addErrorListener(this);
tempSegment.reset();
tempSegment.addErrorListener(this);
tempSegment.setStartAddress(Definitions.TEMP_START_ADDRESS);
tempSegment.setEnabledRange(5, 12, true);
segments[Definitions.SP_ADDRESS] = new MemorySegment[]{stackSegment, workingStackSegment};
segments[Definitions.LOCAL_POINTER_ADDRESS] = new MemorySegment[]{localSegment};
segments[Definitions.ARG_POINTER_ADDRESS] = new MemorySegment[]{argSegment};
segments[Definitions.THIS_POINTER_ADDRESS] = new MemorySegment[]{thisSegment};
segments[Definitions.THAT_POINTER_ADDRESS] = new MemorySegment[]{thatSegment};
keyboard = new Keyboard(ram, null);
keyboard.reset();
CallStack callStack = new CallStack(null);
callStack.reset();
Calculator calculator = new Calculator(null);
calculator.reset();
Bus bus = new Bus(null);
bus.reset();
cpu = new CPU(program, ram, callStack, calculator, bus, stackSegment,
workingStackSegment, staticSegment, localSegment,
argSegment, thisSegment, thatSegment, tempSegment,
INITIAL_BUILTIN_DIR);
cpu.boot();
init();
}
/**
* Constructs a new VM Emulator with the given GUI component.
*/
public VMEmulator(VMEmulatorGUI gui) {
this.gui = gui;
VMProgram program = new VMProgram(gui.getProgram());
program.addErrorListener(this);
program.addProgramListener(this);
MemorySegment[][] segments = new MemorySegment[Definitions.RAM_SIZE][];
RAM ram = new RAM(gui.getRAM(), segments, gui.getScreen());
ram.addErrorListener(this);
ram.reset();
// sets ram labels
LabeledPointedMemoryGUI ramGUI = gui.getRAM();
ramGUI.setLabel(Definitions.SP_ADDRESS, Definitions.SP_NAME);
ramGUI.setLabel(Definitions.LOCAL_POINTER_ADDRESS, Definitions.LOCAL_POINTER_NAME);
ramGUI.setLabel(Definitions.ARG_POINTER_ADDRESS, Definitions.ARG_POINTER_NAME);
ramGUI.setLabel(Definitions.THIS_POINTER_ADDRESS, Definitions.THIS_POINTER_NAME);
ramGUI.setLabel(Definitions.THAT_POINTER_ADDRESS, Definitions.THAT_POINTER_NAME);
ramGUI.setLabel(Definitions.R5_ADDRESS, "Temp0");
ramGUI.setLabel(Definitions.R6_ADDRESS, "Temp1");
ramGUI.setLabel(Definitions.R7_ADDRESS, "Temp2");
ramGUI.setLabel(Definitions.R8_ADDRESS, "Temp3");
ramGUI.setLabel(Definitions.R9_ADDRESS, "Temp4");
ramGUI.setLabel(Definitions.R10_ADDRESS, "Temp5");
ramGUI.setLabel(Definitions.R11_ADDRESS, "Temp6");
ramGUI.setLabel(Definitions.R12_ADDRESS, "Temp7");
ramGUI.setLabel(Definitions.R13_ADDRESS, Definitions.R13_NAME);
ramGUI.setLabel(Definitions.R14_ADDRESS, Definitions.R14_NAME);
ramGUI.setLabel(Definitions.R15_ADDRESS, Definitions.R15_NAME);
// assignes the memory segments
AbsolutePointedMemorySegment stackSegment =
new AbsolutePointedMemorySegment(ram, gui.getStack());
TrimmedAbsoluteMemorySegment workingStackSegment =
new TrimmedAbsoluteMemorySegment(ram, gui.getWorkingStack());
MemorySegment staticSegment =
new MemorySegment(ram, gui.getStaticSegment());
MemorySegment localSegment =
new MemorySegment(ram, gui.getLocalSegment());
MemorySegment argSegment =
new MemorySegment(ram, gui.getArgSegment());
MemorySegment thisSegment =
new MemorySegment(ram, gui.getThisSegment());
MemorySegment thatSegment =
new MemorySegment(ram, gui.getThatSegment());
MemorySegment tempSegment =
new MemorySegment(ram, gui.getTempSegment());
stackSegment.reset();
stackSegment.setEnabledRange(Definitions.STACK_START_ADDRESS,
Definitions.STACK_END_ADDRESS, true);
stackSegment.addErrorListener(this);
workingStackSegment.reset();
workingStackSegment.setEnabledRange(Definitions.STACK_START_ADDRESS,
Definitions.STACK_END_ADDRESS, true);
workingStackSegment.addErrorListener(this);
staticSegment.reset();
staticSegment.addErrorListener(this);
localSegment.reset();
localSegment.addErrorListener(this);
argSegment.reset();
argSegment.addErrorListener(this);
thisSegment.reset();
thisSegment.addErrorListener(this);
thatSegment.reset();
thatSegment.addErrorListener(this);
tempSegment.reset();
tempSegment.setStartAddress(Definitions.TEMP_START_ADDRESS);
tempSegment.setEnabledRange(5, 12, true);
tempSegment.addErrorListener(this);
segments[Definitions.SP_ADDRESS] = new MemorySegment[]{stackSegment, workingStackSegment};
segments[Definitions.LOCAL_POINTER_ADDRESS] = new MemorySegment[]{localSegment};
segments[Definitions.ARG_POINTER_ADDRESS] = new MemorySegment[]{argSegment};
segments[Definitions.THIS_POINTER_ADDRESS] = new MemorySegment[]{thisSegment};
segments[Definitions.THAT_POINTER_ADDRESS] = new MemorySegment[]{thatSegment};
keyboard = new Keyboard(ram, gui.getKeyboard());
keyboard.reset();
CallStack callStack = new CallStack(gui.getCallStack());
callStack.reset();
Calculator calculator = new Calculator(gui.getCalculator());
calculator.hideCalculator();
calculator.reset();
Bus bus = new Bus(gui.getBus());
bus.reset();
cpu = new CPU(program, ram, callStack, calculator, bus, stackSegment,
workingStackSegment, staticSegment, localSegment,
argSegment, thisSegment, thatSegment, tempSegment,
INITIAL_BUILTIN_DIR);
cpu.boot();
init();
}
// Initializes the emulator.
private void init() {
vars = new String[]{VAR_SP, VAR_CURRENT_FUNCTION, VAR_LINE, VAR_RAM + "[]",
VAR_LOCAL, VAR_LOCAL + "[]", VAR_ARGUMENT, VAR_ARGUMENT + "[]",
VAR_THIS, VAR_THIS + "[]", VAR_THAT, VAR_THAT + "[]",
VAR_TEMP + "[]", VAR_RAM + "[]"};
}
public String getName() {
return "Virtual Machine Emulator";
}
/**
* Returns the value of the given variable.
* Throws VariableException if the variable is not legal.
*/
public String getValue(String varName) throws VariableException {
if (varName.equals(VAR_LOCAL))
return String.valueOf(cpu.getRAM().getValueAt(Definitions.LOCAL_POINTER_ADDRESS));
else if (varName.equals(VAR_ARGUMENT))
return String.valueOf(cpu.getRAM().getValueAt(Definitions.ARG_POINTER_ADDRESS));
else if (varName.equals(VAR_THIS))
return String.valueOf(cpu.getRAM().getValueAt(Definitions.THIS_POINTER_ADDRESS));
else if (varName.equals(VAR_THAT))
return String.valueOf(cpu.getRAM().getValueAt(Definitions.THAT_POINTER_ADDRESS));
else if (varName.equals(VAR_SP))
return String.valueOf(cpu.getSP());
else if (varName.equals(VAR_CURRENT_FUNCTION))
return cpu.getCallStack().getTopFunction();
else if (varName.equals(VAR_LINE))
return String.valueOf(cpu.getCallStack().getTopFunction() + "." +
cpu.getCurrentInstruction().getIndexInFunction());
else if (varName.startsWith(VAR_LOCAL + "[")) {
short index = getRamIndex(varName);
return String.valueOf(cpu.getSegmentAt(HVMInstructionSet.LOCAL_SEGMENT_CODE, index));
}
else if (varName.startsWith(VAR_ARGUMENT + "[")) {
short index = getRamIndex(varName);
return String.valueOf(cpu.getSegmentAt(HVMInstructionSet.ARG_SEGMENT_CODE, index));
}
else if (varName.startsWith(VAR_THIS + "[")) {
short index = getRamIndex(varName);
return String.valueOf(cpu.getSegmentAt(HVMInstructionSet.THIS_SEGMENT_CODE, index));
}
else if (varName.startsWith(VAR_THAT + "[")) {
short index = getRamIndex(varName);
return String.valueOf(cpu.getSegmentAt(HVMInstructionSet.THAT_SEGMENT_CODE, index));
}
else if (varName.startsWith(VAR_TEMP + "[")) {
short index = getRamIndex(varName);
return String.valueOf(cpu.getSegmentAt(HVMInstructionSet.TEMP_SEGMENT_CODE, index));
}
else if (varName.startsWith(VAR_RAM + "[")) {
short index = getRamIndex(varName);
return String.valueOf(cpu.getRAM().getValueAt(index));
}
else
throw new VariableException("Unknown variable", varName);
}
/**
* Sets the given variable with the given value.
* Throws VariableException if the variable name or value are not legal.
*/
public void setValue(String varName, String value) throws VariableException {
int numValue;
try {
value = Conversions.toDecimalForm(value);
if (varName.equals(VAR_LOCAL)) {
numValue = Integer.parseInt(value);
check_address(varName, numValue);
cpu.getRAM().setValueAt(Definitions.LOCAL_POINTER_ADDRESS, (short)numValue, false);
if (gui != null)
gui.getLocalSegment().setEnabledRange(numValue, Definitions.STACK_END_ADDRESS, true);
}
else if (varName.equals(VAR_ARGUMENT)) {
numValue = Integer.parseInt(value);
check_address(varName, numValue);
cpu.getRAM().setValueAt(Definitions.ARG_POINTER_ADDRESS, (short)numValue, false);
if (gui != null)
gui.getArgSegment().setEnabledRange(numValue, Definitions.STACK_END_ADDRESS, true);
}
else if (varName.equals(VAR_THIS)) {
numValue = Integer.parseInt(value);
check_address(varName, numValue);
cpu.getRAM().setValueAt(Definitions.THIS_POINTER_ADDRESS, (short)numValue, false);
if (gui != null)
gui.getThisSegment().setEnabledRange(numValue, Definitions.HEAP_END_ADDRESS, true);
}
else if (varName.equals(VAR_THAT)) {
numValue = Integer.parseInt(value);
check_address(varName, numValue);
cpu.getRAM().setValueAt(Definitions.THAT_POINTER_ADDRESS, (short)numValue, false);
if (gui != null)
gui.getThatSegment().setEnabledRange(numValue, Definitions.SCREEN_END_ADDRESS, true);
}
else if (varName.equals(VAR_SP)) {
numValue = Integer.parseInt(value);
check_address(varName, numValue);
cpu.setSP((short)numValue);
}
else if (varName.equals(VAR_CURRENT_FUNCTION))
throw new VariableException("Read Only variable", varName);
else if (varName.equals(VAR_LINE)) {
numValue = Integer.parseInt(value);
if (numValue >= cpu.getProgram().getSize())
throw new VariableException("Line " + value + "is not within the program range",
varName);
cpu.getProgram().setPC((short)numValue);
}
else if (varName.startsWith(VAR_LOCAL + "[")) {
short index = getRamIndex(varName);
numValue = Integer.parseInt(value);
check_value(varName, numValue);
cpu.setSegmentAt(HVMInstructionSet.LOCAL_SEGMENT_CODE, index, (short)numValue);
}
else if (varName.startsWith(VAR_ARGUMENT + "[")) {
short index = getRamIndex(varName);
numValue = Integer.parseInt(value);
check_value(varName, numValue);
cpu.setSegmentAt(HVMInstructionSet.ARG_SEGMENT_CODE, index, (short)numValue);
}
else if (varName.startsWith(VAR_THIS + "[")) {
short index = getRamIndex(varName);
numValue = Integer.parseInt(value);
check_value(varName, numValue);
cpu.setSegmentAt(HVMInstructionSet.THIS_SEGMENT_CODE, index, (short)numValue);
}
else if (varName.startsWith(VAR_THAT + "[")) {
short index = getRamIndex(varName);
numValue = Integer.parseInt(value);
check_value(varName, numValue);
cpu.setSegmentAt(HVMInstructionSet.THAT_SEGMENT_CODE, index, (short)numValue);
}
else if (varName.startsWith(VAR_TEMP + "[")) {
short index = getRamIndex(varName);
numValue = Integer.parseInt(value);
check_value(varName, numValue);
cpu.setSegmentAt(HVMInstructionSet.TEMP_SEGMENT_CODE, index, (short)numValue);
}
else if (varName.startsWith(VAR_RAM + "[")) {
short index = getRamIndex(varName);
numValue = Integer.parseInt(value);
check_address(varName, index);
cpu.getRAM().setValueAt(index, (short)numValue, false);
}
else
throw new VariableException("Unknown variable", varName);
} catch (NumberFormatException nfe) {
throw new VariableException("'" + value + "' is not a legal value for variable",
varName);
}
}
/**
* Executes the given simulator command (given in args[] style).
* Throws CommandException if the command is not legal.
* Throws ProgramException if an error occurs in the program.
*/
public void doCommand(String[] command)
throws CommandException, ProgramException, VariableException {
if (command.length == 0)
throw new CommandException("Empty command", command);
// hide gui highlights
if (animationMode != HackController.NO_DISPLAY_CHANGES)
hideHighlightes();
// execute the appropriate command
if (command[0].equals(COMMAND_VMSTEP)) {
if (command.length != 1)
throw new CommandException("Illegal number of arguments to command", command);
cpu.executeInstruction();
}
else if (command[0].equals(COMMAND_SETVAR)) {
if (command.length != 3)
throw new CommandException("Illegal number of arguments to command", command);
setValue(command[1], command[2]);
}
else if (command[0].equals(COMMAND_ROMLOAD)) {
if (command.length != 1 && command.length != 2)
throw new CommandException("Illegal number of arguments to command", command);
String fileName = getWorkingDir() + (command.length == 1 ? "" : "/" + command[1]);
cpu.getProgram().loadProgram(fileName);
cpu.boot();
}
else
throw new CommandException("Unknown simulator command", command);
}
// Hides all highlights in GUIs.
private void hideHighlightes() {
cpu.getRAM().hideHighlight();
cpu.getStack().hideHighlight();
cpu.getWorkingStack().hideHighlight();
cpu.getCalculator().hideHighlight();
cpu.getStaticSegment().hideHighlight();
MemorySegment[] segments = cpu.getMemorySegments();
for (int i = 0; i < segments.length; i++)
segments[i].hideHighlight();
}
/**
* Restarts the VMEmulator - program will be restarted.
*/
public void restart() {
cpu.getRAM().reset();
cpu.getCallStack().reset();
cpu.getProgram().restartProgram();
cpu.getStack().reset();
cpu.getWorkingStack().reset();
cpu.getCalculator().hideCalculator();
cpu.getCalculator().reset();
cpu.getStaticSegment().reset();
MemorySegment[] segments = cpu.getMemorySegments();
for (int i = 0; i < segments.length; i++)
segments[i].reset();
cpu.boot();
}
public void setAnimationMode(int newAnimationMode) {
if (gui != null) {
// enter NO_DISPLAY_CHANGES
if (newAnimationMode == HackController.NO_DISPLAY_CHANGES &&
animationMode != HackController.NO_DISPLAY_CHANGES) {
cpu.getRAM().disableUserInput();
cpu.getStack().disableUserInput();
cpu.getWorkingStack().disableUserInput();
cpu.getStaticSegment().disableUserInput();
MemorySegment[] segments = cpu.getMemorySegments();
for (int i = 0; i < segments.length; i++)
segments[i].disableUserInput();
ScreenGUI screen = gui.getScreen();
if (screen != null)
screen.startAnimation();
}
// exit NO_DISPLAY_CHANGES
if (newAnimationMode != HackController.NO_DISPLAY_CHANGES &&
animationMode == HackController.NO_DISPLAY_CHANGES) {
cpu.getRAM().enableUserInput();
cpu.getStack().enableUserInput();
cpu.getWorkingStack().enableUserInput();
cpu.getStaticSegment().enableUserInput();
MemorySegment[] segments = cpu.getMemorySegments();
for (int i = 0; i < segments.length; i++)
segments[i].enableUserInput();
ScreenGUI screen = gui.getScreen();
if (screen != null)
screen.stopAnimation();
}
}
animationMode = newAnimationMode;
boolean animate = (animationMode == HackController.ANIMATION);
cpu.getBus().setAnimate(animate);
cpu.getRAM().setAnimate(animate);
cpu.getCallStack().setAnimate(animate);
cpu.getProgram().setAnimate(animate);
cpu.getStack().setAnimate(animate);
cpu.getWorkingStack().setAnimate(animate);
cpu.getCalculator().setAnimate(animate);
cpu.getStaticSegment().setAnimate(animate);
boolean displayChanges = (animationMode != HackController.NO_DISPLAY_CHANGES);
cpu.getRAM().setDisplayChanges(displayChanges);
cpu.getCallStack().setDisplayChanges(displayChanges);
cpu.getProgram().setDisplayChanges(displayChanges);
cpu.getStack().setDisplayChanges(displayChanges);
cpu.getWorkingStack().setDisplayChanges(displayChanges);
cpu.getCalculator().setDisplayChanges(displayChanges);
cpu.getStaticSegment().setDisplayChanges(displayChanges);
MemorySegment[] segments = cpu.getMemorySegments();
for (int i = 0; i < segments.length; i++) {
segments[i].setDisplayChanges(displayChanges);
segments[i].setAnimate(animate);
}
}
public int getInitialAnimationMode() {
return HackController.DISPLAY_CHANGES;
}
public int getInitialNumericFormat() {
return HackController.DECIMAL_FORMAT;
}
public void setNumericFormat(int formatCode) {
cpu.getRAM().setNumericFormat(formatCode);
cpu.getStack().setNumericFormat(formatCode);
cpu.getWorkingStack().setNumericFormat(formatCode);
cpu.getCalculator().setNumericFormat(formatCode);
}
public void setAnimationSpeed(int speedUnit) {
cpu.getBus().setAnimationSpeed(speedUnit);
}
public void refresh() {
cpu.getRAM().refreshGUI();
cpu.getCallStack().refreshGUI();
cpu.getProgram().refreshGUI();
cpu.getStack().refreshGUI();
cpu.getWorkingStack().refreshGUI();
cpu.getCalculator().refreshGUI();
cpu.getStaticSegment().refreshGUI();
MemorySegment[] segments = cpu.getMemorySegments();
for (int i = 0; i < segments.length; i++)
segments[i].refreshGUI();
}
public void prepareFastForward() {
gui.requestFocus();
keyboard.requestFocus();
}
public void prepareGUI() {
}
public String[] getVariables() {
return vars;
}
protected HackSimulatorGUI getGUI() {
return gui;
}
/**
* Called when an error occured in a computer part.
* The event contains the source object and the error message.
*/
public void computerPartErrorOccured(ComputerPartErrorEvent event) {
displayMessage(event.getErrorMessage(), true);
}
public void programChanged(ProgramEvent event) {
super.programChanged(event);
if (event.getType() == ProgramEvent.LOAD) {
int oldAnimationMode = animationMode;
setAnimationMode(HackController.DISPLAY_CHANGES);
refresh();
notifyListeners(ControllerEvent.ENABLE_MOVEMENT, null);
restart();
setAnimationMode(oldAnimationMode);
}
}
// receives a variable name of the form xxx[i] and returns the numeric
// value of i, which is an address in the RAM.
// Throws VariableException if i is not a legal address in the RAM.
private static short getRamIndex(String varName) throws VariableException {
if (varName.indexOf("]") == -1)
throw new VariableException("Missing ']'", varName);
String indexStr = varName.substring(varName.indexOf("[") + 1, varName.indexOf("]"));
int index = Integer.parseInt(indexStr);
if (index < 0 || index >= Definitions.RAM_SIZE)
throw new VariableException("Illegal variable index", varName);
return (short)index;
}
// Checks that the given value is a legal 16-bit value
private void check_value(String varName, int value) throws VariableException {
if (value < -32768 || value >= 32768)
throw new VariableException(value +
" is an illegal value for variable", varName);
}
// Checks that the given value is a legal 16-bit address
private void check_address(String varName, int value) throws VariableException {
if (value < 0 || value >= Definitions.RAM_SIZE)
throw new VariableException(value +
" is an illegal value for", varName);
}
}