/*
HighLevelCodeInfo.java
(c) 2008-2013 Edward Swartz
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
*/
package v9t9.machine.ti99.asm;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import ejs.base.utils.Check;
import v9t9.common.asm.Block;
import v9t9.common.asm.IDecompileInfo;
import v9t9.common.asm.IHighLevelInstruction;
import v9t9.common.asm.IInstructionFactory;
import v9t9.common.asm.Label;
import v9t9.common.asm.MemoryRanges;
import v9t9.common.asm.RawInstruction;
import v9t9.common.asm.Routine;
import v9t9.common.cpu.ICpuState;
import v9t9.common.memory.IMemoryDomain;
/**
* An instance of this class stores all the known information
* about a certain collection of code -- discovered entry points, blocks, routines, etc.
* @author ejs
*
*/
public class HighLevelCodeInfo implements IDecompileInfo {
//Cpu cpu;
IMemoryDomain domain;
/** dimensions */
//int addr;
//int size;
/** instruction list */
Map<Integer, RawInstruction> instructions;
/** LL instruction list */
Map<Integer, IHighLevelInstruction> llInstructions;
//List<Instruction> instructions;
private MemoryRanges memoryRanges;
private TreeMap<Block, Label> labelMap;
protected Map<Integer, Block> blockMap;
protected Map<Label, Routine> routineMap;
private TopDownPhase phase;
private boolean scanned;
private ICpuState state;
private final IInstructionFactory instructionFactory;
public HighLevelCodeInfo(ICpuState state, IInstructionFactory instructionFactory) {
this.state = state;
this.instructionFactory = instructionFactory;
this.domain = state.getConsole();
//this.ent = entry;
//this.addr = addr;
//this.size = size;
this.instructions = new TreeMap<Integer, RawInstruction>();
this.blockMap = new TreeMap<Integer, Block>();
this.memoryRanges = new MemoryRanges();
this.llInstructions = new TreeMap<Integer, IHighLevelInstruction>();
this.labelMap = new TreeMap<Block, Label>();
this.routineMap = new TreeMap<Label, Routine>();
//memoryRanges.addRange(addr, size, true);
this.scanned = false;
}
/** Get the instruction for the given PC */
public RawInstruction getInstruction(int pc) {
pc &= 0xfffe;
RawInstruction ins = instructions.get(pc);
if (ins == null) {
ins = instructionFactory.decodeInstruction(pc, domain);
instructions.put(pc, ins);
}
return ins;
}
/** Test method */
public void addInstruction(IHighLevelInstruction inst) {
instructions.put(inst.getInst().pc & 0xfffe, inst.getInst());
}
/**
* Examine the call site.
* For now, see how many words are consumed by it
* @param block current block containing the call
* @param caller instruction with call
* @param target PC of call target
*/
/*
public FunctionInfo getFunctionInfoFromCall(Instruction caller, short target) {
int type = caller.inst == Instruction.Ibl
? FunctionInfo.FUNCTION_BL : FunctionInfo.FUNCTION_BLWP;
FunctionInfo fi = getFunction(target, type);
if (fi == null) {
int params = 0;
int reg = type == FunctionInfo.FUNCTION_BL ? 11 : 14;
// look for uses of parameter words; ignore any branching
for (Iterator<Instruction> iter = iterateInstructions(target); iter.hasNext();) {
Instruction inst = iter.next();
MachineOperand mop1 = (MachineOperand) inst.op1;
// return?
if (inst.inst == Instruction.Ib && mop1.type == MachineOperand.OP_IND && mop1.val == 11) {
break;
}
if (inst.inst == Instruction.Irtwp) {
break;
}
if (mop1.isMemory() && mop1.type == MachineOperand.OP_INC
&& mop1.val == reg) {
params++;
}
}
if (params > 0) {
System.out.println("call site " + Utils.toHex4(target) + " seems to use " + params + " data words");
}
registerFunction(type, target, params);
}
return fi;
}*/
/** Get an instruction iterator from the PC */
/*
public Iterator<Instruction> iterateInstructions(final short pc) {
return new Iterator<Instruction>() {
int nextAddr = pc;
int end = addr + size;
public boolean hasNext() {
return nextAddr < end;
}
public Instruction next() {
int addr = nextAddr;
Instruction ins = getInstruction(addr);
nextAddr += ins.size;
return ins;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}*/
public MemoryRanges getMemoryRanges() {
return memoryRanges;
}
/* (non-Javadoc)
* @see v9t9.common.asm.IDecompileInfo#getInstructions()
*/
@Override
public Map<Integer, RawInstruction> getInstructions() {
return instructions;
}
public Map<Integer, Block> getBlockMap() {
return blockMap;
}
public Map<Block, Label> getLabelMap() {
return labelMap;
}
public Collection<Routine> getRoutines() {
return routineMap.values();
}
public Map<Label, Routine> getRoutineMap() {
return routineMap;
}
public Collection<Block> getBlocks() {
return blockMap.values();
}
public Collection<Label> getLabels() {
return labelMap.values();
}
public Map<Integer, IHighLevelInstruction> getLLInstructions() {
return llInstructions;
}
public IHighLevelInstruction disassemble(int startAddr, int size) {
memoryRanges.addRange(startAddr, size, true);
IHighLevelInstruction first = null;
IHighLevelInstruction prev = null;
for (int addr = startAddr; addr < startAddr + size; addr += 2) {
IHighLevelInstruction inst = getLLInstructions().get(addr);
if (inst == null) {
RawInstruction rawInst = instructionFactory.decodeInstruction(addr, domain);
inst = new HighLevelInstruction(0,
rawInst,
instructionFactory.getInstructionFlags(rawInst));
getLLInstructions().put(new Integer(inst.getInst().pc), inst);
}
if (prev != null) {
prev.setPhysicalNext(inst);
} else {
first = inst;
}
prev = inst;
}
/*
// wire up instructions to their next real instructions
for (IHighLevelInstruction inst : getLLInstructions().values()) {
if (inst.getInst().getSize() > 2) {
inst.setLogicalNext(getLLInstructions().get(new Integer(inst.getInst().pc + inst.getInst().getSize())));
}
}
*/
return first;
}
/** Detect the structure of the code using the current memory ranges.
* Does not delete any information. */
public void analyze() {
if (!scanned) {
scanned = true;
phase = new TopDownPhase(state, this);
phase.run();
}
}
public void markDirty() {
this.scanned = false;
}
public IDecompileInfo getDecompileInfo() {
return this;
}
public Label getLabel(int addr) {
// first, see if a block exists here
addr &= 0xfffe;
IHighLevelInstruction inst = getLLInstructions().get(addr);
if (inst == null) {
RawInstruction rawInst = getInstruction(addr);
inst = new HighLevelInstruction(0, rawInst, instructionFactory.getInstructionFlags(rawInst));
llInstructions.put(addr, inst);
}
Check.checkState((inst != null));
Block block = inst.getBlock();
if (block != null) {
Label label = labelMap.get(block);
return label;
}
return null;
}
public Label findOrCreateLabel(int addr) {
// first, see if a block exists here
addr &= 0xfffe;
IHighLevelInstruction inst = getLLInstructions().get(addr);
if (inst == null) {
RawInstruction rawInst = getInstruction(addr);
inst = new HighLevelInstruction(0, getInstruction(addr), instructionFactory.getInstructionFlags(rawInst));
llInstructions.put(addr, inst);
}
Check.checkState((inst != null));
inst.setFlags(inst.getFlags() | IHighLevelInstruction.fStartsBlock);
Block block = inst.getBlock();
if (block == null) {
// make block
block = new Block(inst);
blockMap.put(addr, block);
}
Label label = labelMap.get(block);
if (label == null) {
label = new Label(block, null);
labelMap.put(block, label);
}
return label;
}
public void replaceInstruction(IHighLevelInstruction inst) {
instructions.put(inst.getInst().pc, inst.getInst());
}
/* (non-Javadoc)
* @see v9t9.common.asm.IDecompileInfo#reset()
*/
@Override
public void reset() {
instructions.clear();
llInstructions.clear();
labelMap.clear();
routineMap.clear();
blockMap.clear();
}
}