/**
 * Copyright (c) 2004-2005, Regents of the University of California
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of the University of California, Los Angeles nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package avrora.core;



/**
 * The <code>Instr</code> class and its descendants represent instructions within the
 * assembly code. The visitor pattern is applied here. Each instruction has an
 * <code>accept()</code> method that allows it to be visited with double dispatch
 * by a <code>InstrVisitor</code>. Each instruction in the AVR instruction set
 * is represented by an inner class whose source has been generated from a simple
 * specification in the <code>Generator</code> class.
 *
 * @author Ben L. Titzer
 * @see InstrVisitor
 * @see Generator
 */
public abstract class Instr implements InstrPrototype {

    public final InstrProperties properties;

    public Instr(InstrProperties ip) {
        properties = ip;
    }

    /**
     * The <code>getOperands()</code> method returns a string representation
     * of the operands of the instruction. This is useful for printing and
     * tracing of instructions as well as generating listings.
     *
     * @return a string representing the operands of the instruction
     */
    public abstract String getOperands();

    /**
     * The <code>getVariant()</code> method returns the variant name of the
     * instruction as a string. Since instructions like load and store have
     * multiple variants, they each have specific variant names to distinguish
     * them internally in the core of Avrora. For example, for "ld x+, (addr)",
     * the variant is "ldpi" (load with post increment), but the actual instruction
     * is "ld", so this method will return "ldpi".
     *
     * @return the variant of the instruction that this prototype represents
     */
    public String getVariant() {
        return properties.variant;
    }

    /**
     * The <code>getSize()</code> method returns the size of the instruction
     * in bytes.
     *
     * @return the size of this instruction in bytes
     */
    public int getSize() {
        return properties.size;
    }

    /**
     * The <code>getName()</code> method returns the name of the instruction as
     * a string. For instructions that are variants of instructions, this method
     * returns the actual name of the instruction. For example, for "ld x+, (addr)",
     * the variant is "ldpi" (load with post increment), but the actual instruction
     * is "ld", so this method will return "ld".
     *
     * @return the name of the instruction
     */
    public String getName() {
        return properties.name;
    }

    public String toString() {
        return getVariant() + " " + getOperands();
    }

    /**
     * The <code>getCycles()</code> method returns the number of cylces consumed
     * by the instruction in the default case. Most instructions consume the same
     * amount of clock cycles no matter what behavior. For example, 8-bit arithmetic
     * takes one cycle, load and stores take two cycles, etc. Some instructions like
     * the branch and skip instructions take more cycles if they are taken or not
     * taken. In that case, this count returned is the smallest number of cycles
     * that can be consumed by this instruction.
     *
     * @return the number of cycles that this instruction consumes
     */
    public int getCycles() {
        return properties.cycles;
    }

    /**
     * The <code>accept()</code> method is part of the visitor pattern for
     * instructions. The visitor pattern uses two virtual dispatches combined
     * with memory overloading to achieve dispatching on multiple types. The
     * result is clean and modular code.
     *
     * @param v the visitor to accept
     */
    public abstract void accept(InstrVisitor v);

    /**
     * The <code>InvalidOperand</code> class represents a runtime error
     * thrown by the constructor of an instruction or the <code>build</code>
     * method of a prototype when an operand does not meet the restrictions
     * imposed by the AVR instruction set architecture.
     */
    public static class InvalidOperand extends RuntimeException {
        /**
         * The <code>number</code> field of the <code>InvalidOperand</code>
         * instance records which operand this error refers to. For example,
         * if the first operand was the source of the problem, then this
         * field will be set to 1.
         */
        public final int number;

        InvalidOperand(int num, String msg) {
            super("invalid operand #" + num + ": " + msg);
            number = num;
        }
    }

    /**
     * The <code>InvalidRegister</code> class represents an error in
     * constructing an instance of <code>Instr</code> where a register
     * operand does not meet the instruction set specification. For
     * example, the "ldi" instruction can only load values into the
     * upper 16 registers; attempting to create a <code>Instr.LDI</code>
     * instance with a destination register of <code>Register.RO</code>
     * will generate this exception.
     */
    public static class InvalidRegister extends InvalidOperand {
        /**
         * The <code>set</code> field records the expected register set
         * for the operand.
         */
        public final Register.Set set;

        /**
         * The <code>register</code> field records the offending register
         * that was found not to be in the expected register set.
         */
        public final Register register;

        public InvalidRegister(int num, Register reg, Register.Set s) {
            super(num, "must be one of " + s.contents);
            set = s;
            register = reg;
        }
    }

    /**
     * The <code>InvalidImmediate</code> class represents an error in
     * construction of an instance of <code>Instr</code> where the
     * given immediate operand is not within the range that
     * is specified by the instruction set manual. For example, the
     * "sbic" instruction skips the next instruction if the specified
     * bit in the status register is clear. Its operand is expected
     * to be in the range [0, ..., 7]. If the specified operand is
     * not in the range, then this exception will be thrown.
     */
    public static class InvalidImmediate extends InvalidOperand {

        /**
         * The <code>low</code> field stores the lowest value that is
         * allowed for this operand.
         */
        public final int low;

        /**
         * The <code>high</code> field stores the highest value that is
         * allowed for this operand.
         */
        public final int high;

        /**
         * The <code>value</code> field stores the actual value that was
         * passed during the attempeted construction of this instruction.
         */
        public final int value;

        public InvalidImmediate(int num, int v, int l, int h) {
            super(num, "value out of required range [" + l + ", " + h + "]");
            low = l;
            high = h;
            value = v;
        }
    }

    /**
     * The <code>RegisterRequired</code> class represents an error
     * in construction of an instance of <code>Instr</code> where the
     * given operand is expected to be a register but is not.
     */
    public static class RegisterRequired extends RuntimeException {

        public final Operand operand;

        RegisterRequired(Operand o) {
            super("register required");
            operand = o;
        }
    }

    /**
     * The <code>ImmediateRequired</code> class represents an error
     * in construction of an instance of <code>Instr</code> where the
     * given operand is expected to be an immediate but is not.
     */
    public static class ImmediateRequired extends RuntimeException {

        public final Operand operand;

        ImmediateRequired(Operand o) {
            super("immediate required");
            operand = o;
        }
    }

    /**
     * The <code>WrongNumberOfOperands</code> class represents a runtime
     * error thrown by the <code>build</code> method of a prototype when
     * the wrong number of operands is passed to build an instruction.
     */
    public static class WrongNumberOfOperands extends RuntimeException {
        public final int expected;
        public final int found;

        WrongNumberOfOperands(int f, int e) {
            super("wrong number of operands, expected " + e + " and found " + f);
            expected = e;
            found = f;
        }
    }


    private static void count(int num, Operand[] ops) {
        if (ops.length != num)
            throw new WrongNumberOfOperands(ops.length, num);
    }

    private static int checkRange(int num, int val, int low, int high) {
        if (val < low || val > high) throw new InvalidImmediate(num, val, low, high);
        return val;
    }

    private static Register checkRegSet(int num, Register reg, Register.Set set) {
        if (set.contains(reg)) return reg;
        throw new InvalidRegister(num, reg, set);
    }

    private static final HashMap instructions = new HashMap();
    static {
	    initializeInstrSet();
    }

    public static InstrPrototype getPrototype(String name) {
	    return instructions.get(name);
    }
    
    private static int asImm(int num, Operand[] ops) {
	    if ( !ops[num].isImmediate() )
	        throw new ImmediateRequired(ops[num]);
	    return ops[num].asImmediate();
    }

    private static Register asReg(int num, Operand[] ops) {
	    if ( !ops[num].isRegister() )
	        throw new RegisterRequired(ops[num]);
	    return ops[num].asRegister();
    }

    /**
     * I N S T R U C T I O N   D E S C R I P T I O N S
     * ----------------------------------------------------------------
     * <p/>
     * These are the actual instruction descriptions that contain the
     * constraints on operands and sizes, etc.
     * This code is GENERATED from Generator.java.
     * <p/>
     * DO NOT MODIFY THIS CODE!!!!
     */
//--BEGIN INSTR GENERATOR--
    
//--END INSTR GENERATOR--

}
