mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-18 02:06:43 +00:00
example implementation of setcc and first cc setz
This commit is contained in:
parent
a030e9fc5d
commit
12f20d178a
@ -50,9 +50,11 @@ public class DefaultInstructionSet implements InstructionSet {
|
|||||||
add(new SarInstruction());
|
add(new SarInstruction());
|
||||||
add(new IncInstruction());
|
add(new IncInstruction());
|
||||||
add(new DecInstruction());
|
add(new DecInstruction());
|
||||||
|
add(new SetccInstruction());
|
||||||
|
|
||||||
// aliases
|
// aliases
|
||||||
add(new SalInstruction());
|
add(new SalInstruction());
|
||||||
|
add(new SetzInstruction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,19 +3,24 @@ package net.simon987.server.assembly.instruction;
|
|||||||
import net.simon987.server.assembly.Instruction;
|
import net.simon987.server.assembly.Instruction;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
import net.simon987.server.assembly.Target;
|
import net.simon987.server.assembly.Target;
|
||||||
import net.simon987.server.assembly.Util;
|
import net.simon987.server.assembly.Operand;
|
||||||
import net.simon987.server.assembly.Operand;;
|
import net.simon987.server.assembly.OperandType;
|
||||||
|
import net.simon987.server.assembly.MachineCode;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.exception.AssemblyException;
|
||||||
import net.simon987.server.assembly.exception.IllegalOperandException;
|
import net.simon987.server.assembly.exception.IllegalOperandException;
|
||||||
|
import net.simon987.server.assembly.exception.InvalidMnemonicException;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the SETcc family of instructions
|
* Implementation of the SETcc family of instructions
|
||||||
* http://www.ousob.com/ng/iapx86/ng22d84.php
|
* http://www.ousob.com/ng/iapx86/ng22d84.php
|
||||||
*
|
*
|
||||||
* Current problems to get this working is:
|
|
||||||
* - The assembler uses the instruction set to get an instruction by mnemonic, have to check how other alias instructions will be implemented
|
|
||||||
*
|
*
|
||||||
* Stuff to consider
|
* Stuff to consider
|
||||||
* - move the implementation of each instruction to its own class that extends this class
|
* - move the implementation of each instruction to its own class that extends this class
|
||||||
@ -23,45 +28,106 @@ import java.io.ByteArrayOutputStream;
|
|||||||
public class SetccInstruction extends Instruction {
|
public class SetccInstruction extends Instruction {
|
||||||
|
|
||||||
public static final int OPCODE = 50;
|
public static final int OPCODE = 50;
|
||||||
|
/**
|
||||||
|
* Map of mnemonics, stored in mnemonic : family op code
|
||||||
|
* This map includes aliases
|
||||||
|
*/
|
||||||
|
private static final Map<String, Character> mnemnoicFamilyOpCodeMap = new HashMap<>(26);
|
||||||
|
static {
|
||||||
|
mnemnoicFamilyOpCodeMap.put("seta", (char) 0x01);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnbe", (char) 0x01);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setae", (char) 0x02);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnb", (char) 0x02);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnc", (char) 0x02);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setbe", (char) 0x03);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setna", (char) 0x03);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setb", (char) 0x04);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setc", (char) 0x04);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnae", (char) 0x04);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("sete", (char) 0x05);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setz", (char) 0x05);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setne", (char) 0x06);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnz", (char) 0x06);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setg", (char) 0x07);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnle", (char) 0x07);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setge", (char) 0x08);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnl", (char) 0x08);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setle", (char) 0x09);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setng", (char) 0x09);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setl", (char) 0x0A);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setnge", (char) 0x0A);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("seto", (char) 0x0B);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setno", (char) 0x0C);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("sets", (char) 0x0D);
|
||||||
|
mnemnoicFamilyOpCodeMap.put("setns", (char) 0x0E);
|
||||||
|
}
|
||||||
|
|
||||||
public SetccInstruction() {
|
public SetccInstruction() {
|
||||||
// NOTE: The assembler treat this string as a valid mnemonic
|
|
||||||
super("setcc", OPCODE);
|
super("setcc", OPCODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SetccInstruction(String mnemonic) {
|
public SetccInstruction(String alias) {
|
||||||
super(mnemonic, OPCODE);
|
super(alias, OPCODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic switch on the (family) opcode
|
|
||||||
* The SET instructions set the 8-bit destination to 1 if the
|
* The SET instructions set the 8-bit destination to 1 if the
|
||||||
* specified condition is true, otherwise destination is set to 0.
|
* specified condition is true, otherwise destination is set to 0.
|
||||||
*
|
*
|
||||||
* Instruction SET to 1 if ... else to 0 Flags
|
* FamilyOpcode Instruction SET to 1 if ... else to 0 Flags
|
||||||
* SETA, SETNBE Above, Not Below or Equal CF=0 AND ZF=0
|
* 0x01 SETA, SETNBE Above, Not Below or Equal CF=0 AND ZF=0
|
||||||
* SETAE,SETNB,SETNC Above or Equal, Not Below, No Carry CF=0
|
* 0x02 SETAE,SETNB,SETNC Above or Equal, Not Below, No Carry CF=0
|
||||||
* SETBE, SETNA Below or Equal, Not Above CF=1 OR ZF=1
|
* 0x03 SETBE, SETNA Below or Equal, Not Above CF=1 OR ZF=1
|
||||||
* SETB, SETC,SETNAE Below, Carry, Not Above or Equal CF=1
|
* 0x04 SETB, SETC,SETNAE Below, Carry, Not Above or Equal CF=1
|
||||||
* SETE, SETZ Equal, Zero ZF=1
|
* 0x05 SETE, SETZ Equal, Zero ZF=1
|
||||||
* SETNE, SETNZ Not Equal, Not Zero ZF=0
|
* 0x06 SETNE, SETNZ Not Equal, Not Zero ZF=0
|
||||||
*
|
* 0x07 SETG, SETNLE Greater, Not Less or Equal SF=OF AND ZF=0
|
||||||
* SETG, SETNLE Greater, Not Less or Equal SF=OF AND ZF=0
|
* 0x08 SETGE, SETNL Greater or Equal, Not Less SF=OF
|
||||||
* SETGE, SETNL Greater or Equal, Not Less SF=OF
|
* 0x09 SETLE, SETNG Less or Equal, Not Greater SF<>OF OR ZF=1
|
||||||
* SETLE, SETNG Less or Equal, Not Greater SF<>OF OR ZF=1
|
* 0x0A SETL, SETNGE Less, Not Greater or Equal SF<>OF
|
||||||
* SETL, SETNGE Less, Not Greater or Equal SF<>OF
|
* 0x0B SETO Overflow OF=1
|
||||||
* SETO Overflow OF=1
|
* 0x0C SETNO No Overflow OF=0
|
||||||
* SETNO No Overflow OF=0
|
* 0x0D SETS Sign (negative) SF=1
|
||||||
* SETS Sign (negative) SF=1
|
* 0x0E SETNS No Sign (positive) SF=0
|
||||||
* SETNS No Sign (positive) SF=0
|
|
||||||
*/
|
*/
|
||||||
private static Status setcc(Target dst, int dstIndex, int familyOpCode, Status status) {
|
private static Status setcc(Target dst, int dstIndex, int familyOpCode, Status status) {
|
||||||
return status;
|
switch (familyOpCode) {
|
||||||
|
case 0x01:
|
||||||
|
return seta(dst, dstIndex, status);
|
||||||
|
case 0x02:
|
||||||
|
return setae(dst, dstIndex, status);
|
||||||
|
case 0x03:
|
||||||
|
return setbe(dst, dstIndex, status);
|
||||||
|
case 0x04:
|
||||||
|
return setb(dst, dstIndex, status);
|
||||||
|
case 0x05:
|
||||||
|
return sete(dst, dstIndex, status);
|
||||||
|
case 0x06:
|
||||||
|
return setne(dst, dstIndex, status);
|
||||||
|
case 0x07:
|
||||||
|
return setg(dst, dstIndex, status);
|
||||||
|
case 0x08:
|
||||||
|
return setge(dst, dstIndex, status);
|
||||||
|
case 0x09:
|
||||||
|
return setle(dst, dstIndex, status);
|
||||||
|
case 0x0A:
|
||||||
|
return setl(dst, dstIndex, status);
|
||||||
|
case 0x0B:
|
||||||
|
return seto(dst, dstIndex, status);
|
||||||
|
case 0x0C:
|
||||||
|
return setno(dst, dstIndex, status);
|
||||||
|
case 0x0D:
|
||||||
|
return sets(dst, dstIndex, status);
|
||||||
|
case 0x0E:
|
||||||
|
return setns(dst, dstIndex, status);
|
||||||
|
default:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Target can be a memory location or register adressable by dst[dstIndex]
|
* Target can be a memory location or register adressable by dst[dstIndex]
|
||||||
* FamilyOpcode is the value encoded in the source operand as immideate value
|
* FamilyOpcode is the value encoded in the source operand as immidiate value
|
||||||
* it will be used to determince what specfic SETcc operation should be execute
|
* it will be used to determince what specfic SETcc operation should be execute
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -69,9 +135,193 @@ public class SetccInstruction extends Instruction {
|
|||||||
return setcc(dst, dstIndex, familyOpCode, status);
|
return setcc(dst, dstIndex, familyOpCode, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This instruction can never be encoded with 2 operands since one word is reserved for its family op code encoding
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteArrayOutputStream out, Operand o1, int currentLine) {
|
public boolean operandsValid(Operand o1, Operand o2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
/**
|
||||||
|
* Encodes the instruction. Writes the result in the outputStream.
|
||||||
|
* Needs one operand of OperandType.REGISTER or OperandType.
|
||||||
|
*
|
||||||
|
* @param out encoded bytes will be written here
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void encode(ByteArrayOutputStream out, Operand o1, int currentLine) throws AssemblyException {
|
||||||
|
String mnemonic = getMnemonic().toLowerCase();
|
||||||
|
Character familyOpCode = mnemnoicFamilyOpCodeMap.get(mnemonic);
|
||||||
|
|
||||||
|
LogManager.LOGGER.info("received mnemonic: " + mnemonic);
|
||||||
|
LogManager.LOGGER.info("family opcode: " + (int)(char) familyOpCode);
|
||||||
|
|
||||||
|
// This will catch the off case that someone uses the mnemonic 'setcc'
|
||||||
|
// as far as the assembler knows this is a valid instruction, but we know it isn't
|
||||||
|
if (familyOpCode == null) {
|
||||||
|
throw new InvalidMnemonicException(getMnemonic(), currentLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!operandValid(o1)) {
|
||||||
|
throw new IllegalOperandException("Illegal operand combination: " + o1.getType() + " (none)", currentLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
MachineCode code = new MachineCode();
|
||||||
|
code.writeOpcode(getOpCode());
|
||||||
|
|
||||||
|
code.writeSourceOperand(Operand.IMMEDIATE_VALUE);
|
||||||
|
code.appendWord(familyOpCode);
|
||||||
|
|
||||||
|
if (o1.getType() == OperandType.REGISTER16 || o1.getType() == OperandType.MEMORY_REG16) {
|
||||||
|
code.writeDestinationOperand(o1.getValue());
|
||||||
|
} else {
|
||||||
|
code.writeDestinationOperand(o1.getValue());
|
||||||
|
code.appendWord((char) o1.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (byte b : code.bytes()) {
|
||||||
|
out.write(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETA, SETNBE Above, Not Below or Equal CF=0 AND ZF=0
|
||||||
|
*/
|
||||||
|
private static Status seta(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = !status.isCarryFlag() && !status.isZeroFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETAE,SETNB,SETNC Above or Equal, Not Below, No Carry CF=0
|
||||||
|
*/
|
||||||
|
private static Status setae(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = !status.isCarryFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETBE, SETNA Below or Equal, Not Above CF=1 OR ZF=1
|
||||||
|
*/
|
||||||
|
private static Status setbe(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = status.isCarryFlag() || status.isZeroFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETB, SETC,SETNAE Below, Carry, Not Above or Equal CF=1
|
||||||
|
*/
|
||||||
|
private static Status setb(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = status.isCarryFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETE, SETZ Equal, Zero ZF=1
|
||||||
|
*/
|
||||||
|
private static Status sete(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = status.isZeroFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETNE, SETNZ Not Equal, Not Zero ZF=0
|
||||||
|
*/
|
||||||
|
private static Status setne(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = !status.isZeroFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETG, SETNLE Greater, Not Less or Equal SF=OF AND ZF=0
|
||||||
|
*/
|
||||||
|
private static Status setg(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = (status.isSignFlag() == status.isOverflowFlag()) && status.isZeroFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETGE, SETNL Greater or Equal, Not Less SF=OF
|
||||||
|
*/
|
||||||
|
private static Status setge(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = status.isSignFlag() == status.isOverflowFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETLE, SETNG Less or Equal, Not Greater SF<>OF OR ZF=1
|
||||||
|
*/
|
||||||
|
private static Status setle(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = (status.isSignFlag() != status.isOverflowFlag()) || status.isZeroFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETL, SETNGE Less, Not Greater or Equal SF<>OF
|
||||||
|
*/
|
||||||
|
private static Status setl(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = status.isSignFlag() != status.isOverflowFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETO Overflow OF=1
|
||||||
|
*/
|
||||||
|
private static Status seto(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = status.isOverflowFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETNO No Overflow OF=0
|
||||||
|
*/
|
||||||
|
private static Status setno(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = !status.isOverflowFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETS Sign (negative) SF=1
|
||||||
|
*/
|
||||||
|
private static Status sets(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = status.isSignFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SETNS No Sign (positive) SF=0
|
||||||
|
*/
|
||||||
|
private static Status setns(Target dst, int dstIndex, Status status) {
|
||||||
|
boolean condition = !status.isSignFlag();
|
||||||
|
int value = condition ? 1 : 0;
|
||||||
|
dst.set(dstIndex, value);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alias of SetccInstruction
|
||||||
|
*/
|
||||||
|
public class SetzInstruction extends SetccInstruction {
|
||||||
|
|
||||||
|
public SetzInstruction() {
|
||||||
|
super("setz");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user