/*
JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine
Copyright (C) 2012-2013 Ian Preston
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published by
the Free Software Foundation.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Details (including contact information) can be found at:
jpc.sourceforge.net
or the developer website
sourceforge.net/projects/jpc/
End of licence header
*/
package org.jpc.emulator.execution.decoder;
import org.jpc.emulator.processor.Processor;
import org.jpc.emulator.processor.fpu64.FpuState64;
import java.util.BitSet;
import static org.jpc.emulator.processor.Processor.*;
public class Pointer extends Address
{
final int base, index;
final int scale;
final int offset;
final int segment;
final boolean addrSize;
public Pointer(Instruction.Operand op, int adr_mode)
{
if (op.base != null)
base = Processor.getRegIndex(op.base);
else
base = -1;
if (op.index != null)
index = Processor.getRegIndex(op.index);
else
index = -1;
if (op.scale != 0)
scale = (int) op.scale;
else if ((op.scale == 0) && (index != -1))
scale = 1;
else
scale = 0;
if (op.offset == 16)
offset = (short) op.lval;
else if (op.offset == 8)
offset = (byte)op.lval;
else
offset = (int)op.lval;
if (op.seg != null)
{
segment = Processor.getSegmentIndex(op.seg);
} else
segment = Processor.getSegmentIndex(getImplicitSegment(op));
addrSize = adr_mode == 32;
}
public Pointer(int base, int index, int scale, int offset, int segment, boolean addrSize)
{
this.base = base;
this.index = index;
this.scale = scale;
this.offset = offset;
this.segment = segment;
this.addrSize = addrSize;
}
private static String getImplicitSegment(Instruction.Operand operand)
{
// :-)
if (operand.toString().toLowerCase().contains("bp") || operand.toString().toLowerCase().contains("sp"))
return "ss";
else
return "ds";
}
public int getBase(Processor cpu)
{
return cpu.segs[segment].getBase();
}
public int get(Processor cpu)
{
return get(cpu, 0);
}
public int get(Processor cpu, int off)
{
int addr = offset+off;
if (addrSize)
{
if (base != -1)
addr += cpu.regs[base].get32();
if (scale != 0)
addr += scale*cpu.regs[index].get32();
}
else
{
if (base != -1)
addr += cpu.regs[base].get16();
if (scale != 0)
addr += scale*cpu.regs[index].get16();
addr &= 0xFFFF;
}
return addr;
}
public double getF64(Processor cpu)
{
return Double.longBitsToDouble(get64(cpu));
}
public byte[] getF80(Processor cpu)
{
byte[] data = new byte[10];
for (int i=0; i < 10; i++)
data[i] = get8(cpu, i);
return data;
}
public void setF80(Processor cpu, byte[] val)
{
for (int i=0; i < 10; i++)
set8(cpu, i, val[i]);
}
public void setF80(Processor cpu, double val)
{
byte[] b = FpuState64.doubleToExtended(val, false);
for (int i=0; i<10; i++)
set8(cpu, i, b[i]);
}
public void setF64(Processor cpu, double val)
{
set64(cpu, Double.doubleToRawLongBits(val));
}
public long get64(Processor cpu)
{
return cpu.segs[segment].getQuadWord(get(cpu));
}
public void set64(Processor cpu, long val)
{
cpu.segs[segment].setQuadWord(get(cpu), val);
}
public float getF32(Processor cpu)
{
return Float.intBitsToFloat(get32(cpu));
}
public void setF32(Processor cpu, float val)
{
set32(cpu, Float.floatToRawIntBits(val));
}
public int get32(Processor cpu, int offset)
{
return cpu.segs[segment].getDoubleWord(get(cpu, offset));
}
public int get32(Processor cpu)
{
return cpu.segs[segment].getDoubleWord(get(cpu));
}
public void set32(Processor cpu, int off, int val)
{
cpu.segs[segment].setDoubleWord(get(cpu, off), val);
}
public void set32(Processor cpu, int val)
{
cpu.segs[segment].setDoubleWord(get(cpu), val);
}
public short get16(Processor cpu, int off)
{
return cpu.segs[segment].getWord(get(cpu, off));
}
public short get16(Processor cpu)
{
return cpu.segs[segment].getWord(get(cpu));
}
public void set16(Processor cpu, int off, short val)
{
cpu.segs[segment].setWord(get(cpu, off), val);
}
public void set16(Processor cpu, short val)
{
cpu.segs[segment].setWord(get(cpu), val);
}
public byte get8(Processor cpu, int off)
{
return cpu.segs[segment].getByte(get(cpu, off));
}
public byte get8(Processor cpu)
{
return cpu.segs[segment].getByte(get(cpu));
}
public void set8(Processor cpu, int off, byte val)
{
cpu.segs[segment].setByte(get(cpu, off), val);
}
public void set8(Processor cpu, byte val)
{
cpu.segs[segment].setByte(get(cpu), val);
}
public String toString()
{
StringBuffer b = new StringBuffer();
if (segment != -1)
b.append(Processor.getSegmentString(segment) + ":");
if (base != -1)
b.append("regs["+base+"]");
if (scale != 0)
b.append(String.format("+regs[%d]*%d", index, scale));
if (offset != 0)
b.append(String.format("+%08x", offset));
return b.toString();
}
public String toSource()
{
StringBuffer b = new StringBuffer();
if (segment != -1)
{
b.append("((cpu."+Processor.getSegmentString(segment)+" != null) ? "+"cpu."+Processor.getSegmentString(segment) + ".getBase():0)");
if (base != -1)
b.append("+");
}
if (base != -1)
b.append("cpu.regs["+base+"].get32()");
if (scale != 0)
b.append(String.format("+cpu.regs[%d].get32()*%d",index, scale));
if (offset != 0)
b.append(String.format("+0x%08x", offset));
else if ((segment == -1) && (base == -1) && (scale == 0))
b.append("0x0");
return b.toString();
}
}