/*
F99bInstructionFactory.java
(c) 2010-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.f99b.cpu;
import static v9t9.machine.f99b.asm.InstF99b.I0branchB;
import static v9t9.machine.f99b.asm.InstF99b.I0branchW;
import static v9t9.machine.f99b.asm.InstF99b.I0branchX;
import static v9t9.machine.f99b.asm.InstF99b.IbranchB;
import static v9t9.machine.f99b.asm.InstF99b.IbranchW;
import static v9t9.machine.f99b.asm.InstF99b.IbranchX;
import static v9t9.machine.f99b.asm.InstF99b.Icall;
import static v9t9.machine.f99b.asm.InstF99b.IcontextFrom;
import static v9t9.machine.f99b.asm.InstF99b.Idouble;
import static v9t9.machine.f99b.asm.InstF99b.Iext;
import static v9t9.machine.f99b.asm.InstF99b.Ilalloc;
import static v9t9.machine.f99b.asm.InstF99b.IlitB;
import static v9t9.machine.f99b.asm.InstF99b.IlitB_d;
import static v9t9.machine.f99b.asm.InstF99b.IlitD_d;
import static v9t9.machine.f99b.asm.InstF99b.IlitW;
import static v9t9.machine.f99b.asm.InstF99b.IlitX;
import static v9t9.machine.f99b.asm.InstF99b.IlitX_d;
import static v9t9.machine.f99b.asm.InstF99b.Ilocal;
import static v9t9.machine.f99b.asm.InstF99b.Ilpidx;
import static v9t9.machine.f99b.asm.InstF99b.Irpidx;
import static v9t9.machine.f99b.asm.InstF99b.Ispidx;
import static v9t9.machine.f99b.asm.InstF99b.Isyscall;
import static v9t9.machine.f99b.asm.InstF99b.ItoContext;
import static v9t9.machine.f99b.asm.InstF99b.Iupidx;
import v9t9.common.asm.IRawInstructionFactory;
import v9t9.common.asm.RawInstruction;
import v9t9.common.memory.IMemoryDomain;
import v9t9.machine.f99b.asm.InstructionF99b;
import v9t9.machine.f99b.asm.MachineOperandF99b;
/**
* @author ejs
*
*/
public class F99bInstructionFactory implements IRawInstructionFactory {
public static final F99bInstructionFactory INSTANCE = new F99bInstructionFactory();
static class WorkBlock {
public short pc;
public IMemoryDomain domain;
public WorkBlock(short pc, IMemoryDomain domain) {
super();
this.pc = pc;
this.domain = domain;
}
/**
* @return
*/
public int nextByte() {
return domain.readByte(pc++) & 0xff;
}
/**
* @return
*/
public int nextWord() {
return (domain.readByte(pc++) << 8) | domain.readByte(pc++) & 0xff;
}
}
/* (non-Javadoc)
* @see v9t9.tools.asm.assembler.IInstructionFactory#decodeInstruction(int, v9t9.engine.memory.MemoryDomain)
*/
@Override
public RawInstruction decodeInstruction(int pc, IMemoryDomain memory) {
short thisPc = (short) pc;
WorkBlock iblock = new WorkBlock((short) pc, memory);
short opword = (short) memory.readByte(thisPc);
if (opword < 0) {
opword = (short) ((opword << 8) | (memory.readByte(thisPc + 1) & 0xff));
iblock.pc += 2;
// call
return getCallInstruction(pc, opword);
}
iblock.pc = (short) (pc + 1);
if (opword == Iext || opword == Idouble) {
opword = (short) (((opword << 8) | (memory.readByte(thisPc + 1) & 0xff)) & 0xffff);
++iblock.pc;
}
InstructionF99b inst;
inst = getInstruction(thisPc, opword, iblock);
return inst;
}
private InstructionF99b getInstruction(short origPC, short opword, WorkBlock iblock) {
int opcode = opword & 0xffff;
InstructionF99b inst = new InstructionF99b();
inst.pc = origPC;
inst.opcode = opcode;
inst.setInst(opcode);
if (opcode >= IbranchX && opcode < I0branchX + 16) {
inst.setInst(opcode & 0xf0);
int val = (byte)(opcode<<4) >> 4;
inst.setOp1(MachineOperandF99b.createImmediateOperand(
val,
MachineOperandF99b.OP_ENC_IMM4));
}
else if (opcode >= IlitX && opcode < IlitX + 16) {
inst.setInst(IlitX);
inst.setOp1(MachineOperandF99b.createImmediateOperand(
(byte)(opcode<<4) >> 4,
MachineOperandF99b.OP_ENC_IMM4));
}
else if (opcode >= IlitX_d && opcode < IlitX_d + 16) {
inst.setInst(IlitX_d);
inst.setOp1(MachineOperandF99b.createImmediateOperand(
(byte)(opcode<<4) >> 4,
MachineOperandF99b.OP_ENC_IMM4));
}
else
switch (opcode) {
case IbranchB:
case I0branchB: {
int val = (byte) iblock.nextByte();
if (val < 0)
val -= 2 - 1;
inst.setOp1(MachineOperandF99b.createImmediateOperand(
val, MachineOperandF99b.OP_ENC_IMM8));
break;
}
case IlitB:
case IlitB_d:
inst.setOp1(MachineOperandF99b.createImmediateOperand(
(byte) iblock.nextByte(), MachineOperandF99b.OP_ENC_IMM8));
break;
case Isyscall:
inst.setOp1(MachineOperandF99b.createImmediateOperand(
(byte) iblock.nextByte(), MachineOperandF99b.OP_ENC_SYSCALL));
break;
case ItoContext:
case IcontextFrom:
inst.setOp1(MachineOperandF99b.createImmediateOperand(
iblock.nextByte() & 0xff, MachineOperandF99b.OP_ENC_CTX));
break;
case Irpidx:
case Ispidx:
case Iupidx:
case Ilpidx:
case Ilocal:
case Ilalloc:
inst.setOp1(MachineOperandF99b.createImmediateOperand(
iblock.nextByte() & 0xff, MachineOperandF99b.OP_ENC_IMM8));
break;
case I0branchW:
case IbranchW: {
int val = (short) iblock.nextWord();
if (val < 0)
val -= 3 - 1;
inst.setOp1(MachineOperandF99b.createImmediateOperand(
val, MachineOperandF99b.OP_ENC_IMM16));
break;
}
case IlitW: {
int val = (short) iblock.nextWord();
inst.setOp1(MachineOperandF99b.createImmediateOperand(
val, MachineOperandF99b.OP_ENC_IMM16));
break;
}
case IlitD_d: {
int lo = iblock.nextWord() & 0xffff;
int hi = iblock.nextWord() & 0xffff;
inst.setOp1(MachineOperandF99b.createImmediateOperand(
lo | (hi << 16),
MachineOperandF99b.OP_ENC_IMM32));
break;
}
default:
// no immediate
}
int sz = iblock.pc - inst.pc;
if (sz < 0)
sz += 65536;
inst.setSize(sz);
return inst;
}
private InstructionF99b getCallInstruction(int pc, short op) {
InstructionF99b inst = new InstructionF99b();
inst.pc = pc;
inst.opcode = op;
inst.setOp1(MachineOperandF99b.createImmediateOperand((short) (op << 1), MachineOperandF99b.OP_ENC_IMM15S1));
inst.setInst(Icall);
inst.setSize(2);
return inst;
}
/* (non-Javadoc)
* @see v9t9.common.asm.IRawInstructionFactory#getChunkSize()
*/
@Override
public int getChunkSize() {
return 1;
}
/* (non-Javadoc)
* @see v9t9.common.asm.IRawInstructionFactory#getMaxInstrLength()
*/
@Override
public int getMaxInstrLength() {
return 5; // LIT.D
}
}