/**
 * This class offers services to disassemble PIC programs.
 * <BR>You can read the source of this class <A HREF="./Disassembler.java.html"> here</A>.
 */
public abstract class Disassembler {

	public final static int OffsetSize = 8;

	public static String[] Disassemble(int ArrayOfProgToDisASM[], boolean AddOffset) {
		return Disassemble(new CompiledProgram(ArrayOfProgToDisASM), AddOffset);
	}

	public static String[] Disassemble(CompiledProgram Prgm, boolean AddOffset) {
		int i;
		String j = null;
		boolean IsThereLabel= false;

		String s[] = new String[Flash.FlashSize];

		for(i = 0 ; i < /*Prgm.Size()*/Flash.FlashSize ; i++) {
			if(Prgm.hasInfos()) {
				j = FindCorellation(i, Prgm.getLabelSymb());
				if(j != null) {
					j = (j + "        ").substring(0, 8);
					s[i] = j + ":   ";
					IsThereLabel = true;
				}
			}

			if(AddOffset) {
				if(Prgm.hasInfos()) {
					if(IsThereLabel)
						s[i] = s[i] + Disassemble(Prgm.Program()[i], Prgm.getLabelSymb(), Prgm.getVariableSymb());
					else
						s[i] = Utils.hex(i, 4, 4) + "    :   " + Disassemble(Prgm.Program()[i], Prgm.getLabelSymb(), Prgm.getVariableSymb());					
				}
				else
					s[i] = Utils.hex(i, 4, 4) + "    :   " + Disassemble(Prgm.Program()[i]);
			}
			else {
				if(Prgm.hasInfos()) {
					if(IsThereLabel)
						s[i] = s[i] + Disassemble(Prgm.Program()[i], Prgm.getLabelSymb(), Prgm.getVariableSymb());
					else
						s[i] = "\t" + Disassemble(Prgm.Program()[i], Prgm.getLabelSymb(), Prgm.getVariableSymb());
						
				}
				else
					s[i] =  "\t" + Disassemble(Prgm.Program()[i]);
			} 
			IsThereLabel= false;

		}

		return s;
	}

	
	public static String Disassemble(int Opcode) {
		return 	Disassemble(Opcode, null, null);
	}	
	
	
	public static String Disassemble(int Opcode, SymbolicInfos[] lbls, SymbolicInfos[] vars) {
		InstructionInformation instr = InstructionSet.Find(Opcode);
		String ret = instr.Mnemonic();
		boolean infos = false;
	
		if(vars != null)
				infos = true;
			
		if(instr == null)
			System.out.println("Illegal opcode");
			
		if(instr.NbOperandes() > 0) {
			ret += " ";
			switch(instr.CodeAndDecodeType()) {
				case OpcodeType.FileAndDest		: ret += DecodeFile(Opcode, infos, vars) + "," + DecodeDest(Opcode, infos); break;
				case OpcodeType.File			: ret += DecodeFile(Opcode, infos, vars); break;
				case OpcodeType.FileAnd3BitsConst	: ret += DecodeFile(Opcode, infos, vars) + "," + Decode3BitsConst(Opcode, infos); break;
				case OpcodeType.Literal8Bits		: ret += DecodeLiteral8Bits(Opcode, infos); break;
				case OpcodeType.Literal11Bits		: ret += DecodeLiteral11Bits(Opcode, infos, lbls); break;
				default					: break;
			}
		}

		return ret;
	}
	
	
	public static String FindCorellation(int c, SymbolicInfos[] Sdb) {
		int i;
		String r = null;

		if(Sdb != null)
			for(i = 0 ; (i < Sdb.length) && (r == null) ; i++ )
				if(Sdb[i].address() == c)
					r = Sdb[i].name();
	
		return r;
	}	
	
	

	protected static String DecodeFile(int Opcode, boolean inf, SymbolicInfos[] vars) {
		int i;
		String r;

		if(!(inf && ((r = FindCorellation(Opcode & 0x7F, vars)) != null)))
			r = "0x" + Utils.hex(Opcode & 0x7F, 2, 4);

		return r;			
	}

	protected static String DecodeDest(int Opcode, boolean inf) {
		return ((Opcode & 0x80) == 0) ? "w" : "f";
	}

	protected static String Decode3BitsConst(int Opcode, boolean inf) {
		return "" + ((Opcode & 0x380) >> 7);
	}

	protected static String DecodeLiteral8Bits(int Opcode, boolean inf) {
		return "0x" + Utils.hex(Opcode & 0xFF, 2, 4);
	}

	protected static String DecodeLiteral11Bits(int Opcode, boolean inf, SymbolicInfos[] lbls) {
		int i;
		String r;

		if(!(inf && ((r = FindCorellation(Opcode & 0x7FF, lbls)) != null)))
			r = "0x" + Utils.hex(Opcode & 0x7FF, 3, 4);

		return r;
	}
}