/*
* $Id: Short1Instruction.java 536 2008-02-19 06:03:27Z weiju $
*
* Created on 10/03/2005
* Copyright 2005-2008 by Wei-ju Wu
* This file is part of The Z-machine Preservation Project (ZMPP).
*
* ZMPP is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZMPP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZMPP. If not, see <http://www.gnu.org/licenses/>.
*/
package org.zmpp.instructions;
import org.zmpp.vm.Machine;
/**
* This class represents instructions of type SHORT, 1OP.
*
* @author Wei-ju Wu
* @version 1.0
*/
public class Short1Instruction extends AbstractInstruction {
/**
* Constructor.
*
* @param machineState a reference to the MachineState object
* @param opcode the instruction's opcode
*/
public Short1Instruction(Machine machineState, int opcode) {
super(machineState, opcode);
}
/**
* {@inheritDoc}
*/
protected void doInstruction() {
switch (getOpcode()) {
case Short1StaticInfo.OP_JZ:
jz();
break;
case Short1StaticInfo.OP_GET_SIBLING:
get_sibling();
break;
case Short1StaticInfo.OP_GET_CHILD:
get_child();
break;
case Short1StaticInfo.OP_GET_PARENT:
get_parent();
break;
case Short1StaticInfo.OP_GET_PROP_LEN:
get_prop_len();
break;
case Short1StaticInfo.OP_INC:
inc();
break;
case Short1StaticInfo.OP_DEC:
dec();
break;
case Short1StaticInfo.OP_PRINT_ADDR:
print_addr();
break;
case Short1StaticInfo.OP_REMOVE_OBJ:
remove_obj();
break;
case Short1StaticInfo.OP_PRINT_OBJ:
print_obj();
break;
case Short1StaticInfo.OP_JUMP:
jump();
break;
case Short1StaticInfo.OP_RET:
ret();
break;
case Short1StaticInfo.OP_PRINT_PADDR:
print_paddr();
break;
case Short1StaticInfo.OP_LOAD:
load();
break;
case Short1StaticInfo.OP_NOT:
if (getStoryFileVersion() <= 4) {
not();
} else {
call_1n();
}
break;
case Short1StaticInfo.OP_CALL_1S:
call_1s();
break;
default:
throwInvalidOpcode();
}
}
/**
* {@inheritDoc}
*/
public InstructionForm getInstructionForm() {
return InstructionForm.SHORT;
}
/**
* {@inheritDoc}
*/
public OperandCount getOperandCount() {
return OperandCount.C1OP;
}
/**
* {@inheritDoc}
*/
protected InstructionStaticInfo getStaticInfo() {
return Short1StaticInfo.getInstance();
}
/**
* inc instruction.
*/
private void inc() {
final short varNum = getValue(0);
final short value = getCpu().getVariable(varNum);
getCpu().setVariable(varNum, (short) (value + 1));
nextInstruction();
}
/**
* dec instruction.
*/
private void dec() {
final short varNum = getValue(0);
final short value = (short) getCpu().getVariable(varNum);
getCpu().setVariable(varNum, (short) (value - 1));
nextInstruction();
}
/**
* not instruction.
*/
private void not() {
final int notvalue = ~getUnsignedValue(0);
storeResult((short) (notvalue & 0xffff));
nextInstruction();
}
/**
* jump instruction. The offset can be negative.
*/
private void jump() {
// Unconditional jump
getCpu().incrementProgramCounter(getValue(0) + 1);
}
/**
* load instruction.
*/
private void load() {
final int varnum = getValue(0);
final short value = varnum == 0 ? getCpu().getStackTopElement()
: getCpu().getVariable(varnum);
storeResult(value);
nextInstruction();
}
/**
* jz instruction.
*/
private void jz() {
branchOnTest(getValue(0) == 0);
}
/**
* get_parent instruction.
*/
private void get_parent() {
final int obj = getUnsignedValue(0);
int parent = 0;
if (obj > 0) {
parent = getMachine().getParent(obj);
} else {
getMachine().warn("@get_parent illegal access to object " + obj);
}
storeResult((short) (parent & 0xffff));
nextInstruction();
}
private void get_sibling() {
final int obj = getUnsignedValue(0);
int sibling = 0;
if (obj > 0) {
sibling = getMachine().getSibling(obj);
} else {
getMachine().warn("@get_sibling illegal access to object " + obj);
}
storeResult((short) (sibling & 0xffff));
branchOnTest(sibling > 0);
}
private void get_child() {
final int obj = getUnsignedValue(0);
int child = 0;
if (obj > 0) {
child = getMachine().getChild(obj);
} else {
getMachine().warn("@get_child illegal access to object " + obj);
}
storeResult((short) (child & 0xffff));
branchOnTest(child > 0);
}
private void print_addr() {
getMachine().getOutput().printZString(getUnsignedValue(0));
nextInstruction();
}
private void print_paddr() {
getMachine().getOutput().printZString(
getMachine().getCpu().translatePackedAddress(getUnsignedValue(0), false));
nextInstruction();
}
private void ret() {
returnFromRoutine(getValue(0));
}
private void print_obj() {
final int obj = getUnsignedValue(0);
if (obj > 0) {
getMachine().getOutput().printZString(
getMachine().getPropertiesDescriptionAddress(obj));
} else {
getMachine().warn("@print_obj illegal access to object " + obj);
}
nextInstruction();
}
private void remove_obj() {
final int obj = getUnsignedValue(0);
if (obj > 0) {
getMachine().removeObject(obj);
}
nextInstruction();
}
private void get_prop_len() {
final int propertyAddress = getUnsignedValue(0);
final short proplen = (short) getMachine().getPropertyLength(propertyAddress);
storeResult(proplen);
nextInstruction();
}
private void call_1s() {
call(0);
}
private void call_1n() {
call(0);
}
}