package elw.dp.mips;
import elw.dp.mips.asm.Data;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Pattern;
public class Instruction {
// binary code areas
public static final String T_REG_D = "$d";
public static final String T_REG_S = "$s";
public static final String T_REG_T = "$t";
public static final String T_IMM26 = "imm26";
public static final String T_IMM16 = "imm16";
public static final String T_H5 = "h5";
// labels
public static final String T_ADDR16 = "addr16";
public static final String T_ADDR26 = "addr26";
private static final Map<String, String> tokenToMask = createTokenToMaskMap();
private static Map<String, String> createTokenToMaskMap() {
final Map<String, String> map = new LinkedHashMap<String, String>();
map.put(T_IMM26, "iiiiiiiiiiiiiiiiiiiiiiiiii");
map.put(T_IMM16, "iiiiiiiiiiiiiiii");
map.put(T_REG_D, "ddddd");
map.put(T_REG_T, "ttttt");
map.put(T_REG_S, "sssss");
map.put(T_H5, "hhhhh");
return map;
}
private static final Pattern PATTERN_COMPLETE = Pattern.compile("^[-01]+$");
private final InstructionDesc desc;
private final String codeLine;
private final int index;
private final int lineIndex;
private final String[] labels;
private Reg s = Reg.fp;
private Reg t = Reg.fp;
private Reg d = Reg.fp;
private int i16;
private int i26;
private int h;
private String addr16 = "";
private String addr26 = "";
public Instruction(InstructionDesc desc, String codeLine, int index, int lineIndex, String[] labels) {
this.desc = desc;
this.codeLine = codeLine;
this.index = index;
this.lineIndex = lineIndex;
this.labels = labels;
}
public String getOpName() {
final String syntax = desc.syntax();
final int firstSpace = syntax.indexOf(" ");
return firstSpace < 0 ? syntax : syntax.substring(0, firstSpace);
}
public String getBinaryCode() {
StringBuffer res = new StringBuffer(desc.template());
for (String token : tokenToMask.keySet()) {
final String mask = tokenToMask.get(token);
final int maskStart = res.indexOf(mask);
if (maskStart >= 0) {
res.replace(maskStart, maskStart + mask.length(), Data.strTwosComplement(getBits(token), getWidth(token)));
}
}
return res.toString();
}
public boolean isAssembled() {
return PATTERN_COMPLETE.matcher(getBinaryCode()).matches();
}
public int getIndex() {
return index;
}
public String getCodeLine() {
return codeLine;
}
public String toString() {
return "'" + desc.syntax() + "' : '" + getBinaryCode() + "'";
}
public void setReg(String regId, Reg reg) {
if (T_REG_D.equals(regId)) {
d = reg;
} else if (T_REG_S.equals(regId)) {
s = reg;
} else if (T_REG_T.equals(regId)) {
t = reg;
} else {
throw new IllegalArgumentException("unknown regId: '" + regId + "'");
}
}
public Reg getReg(String regId) {
if (T_REG_D.equals(regId)) {
return d;
}
if (T_REG_S.equals(regId)) {
return s;
}
if (T_REG_T.equals(regId)) {
return t;
}
throw new IllegalArgumentException("unknown regId: '" + regId + "'");
}
public int getBits(String id) {
if (T_REG_D.equals(id)) {
return getReg(T_REG_D).ordinal();
}
if (T_REG_S.equals(id)) {
return getReg(T_REG_S).ordinal();
}
if (T_REG_T.equals(id)) {
return getReg(T_REG_T).ordinal();
}
if (T_H5.equals(id)) {
return (int) Data.comp(h, 5);
}
if (T_IMM16.equals(id)) {
return desc.unsigned() ? (int) Data.comp(i16, 16) : i16;
}
if (T_ADDR16.equals(id)) {
throw new IllegalArgumentException("addr16 is a string");
}
if (T_ADDR26.equals(id)) {
throw new IllegalArgumentException("addr26 is a string");
}
if (T_IMM26.equals(id)) {
return desc.unsigned() ? (int) Data.comp(i26, 26) : i26;
}
throw new IllegalArgumentException("unknown token id: '" + id + "'");
}
public void setBits(String id, int bits) {
if (T_REG_D.equals(id)) {
setReg(T_REG_D, Reg.values()[bits]);
} else if (T_REG_S.equals(id)) {
setReg(T_REG_S, Reg.values()[bits]);
} else if (T_REG_T.equals(id)) {
setReg(T_REG_T, Reg.values()[bits]);
} else if (T_H5.equals(id)) {
h = bits;
} else if (T_IMM16.equals(id)) {
i16 = bits;
} else if (T_ADDR16.equals(id)) {
throw new IllegalArgumentException("addr16 is a string");
} else if (T_ADDR26.equals(id)) {
throw new IllegalArgumentException("addr26 is a string");
} else if (T_IMM26.equals(id)) {
i26 = bits;
} else {
throw new IllegalArgumentException("unknown token id: '" + id + "'");
}
}
public static int getWidth(String id) {
if (T_REG_D.equals(id)) {
return 5;
}
if (T_REG_S.equals(id)) {
return 5;
}
if (T_REG_T.equals(id)) {
return 5;
}
if (T_H5.equals(id)) {
return 5;
}
if (T_IMM16.equals(id)) {
return 16;
}
if (T_ADDR16.equals(id)) {
return 16;
}
if (T_ADDR26.equals(id)) {
return 26;
}
if (T_IMM26.equals(id)) {
return 26;
}
throw new IllegalArgumentException("unknown token id: '" + id + "'");
}
public String getAddr(final String addrId) {
if (T_ADDR16.equals(addrId)) {
return addr16;
}
if (T_ADDR26.equals(addrId)) {
return addr26;
}
throw new IllegalArgumentException("unknown address id: '" + addrId + "'");
}
public void setAddr(final String addrId, String addr) {
if (T_ADDR16.equals(addrId)) {
this.addr16 = addr;
} else if (T_ADDR26.equals(addrId)) {
this.addr26 = addr;
} else {
throw new IllegalArgumentException("unknown address id: '" + addrId + "'");
}
}
public String[] getLabels() {
return labels;
}
public boolean resolve(int codeBase, Map<String, Integer> labelIndex) {
if (addr16.length() > 0) {
final Integer offs16 = labelIndex.get(addr16);
if (offs16 != null) {
setBits(T_IMM16, offs16 - index);
return false;
} else {
return true;
}
}
if (addr26.length() > 0) {
final Integer offs26 = labelIndex.get(addr26);
if (offs26 != null) {
setBits(T_IMM26, (codeBase >> 2) + offs26);
return false;
} else {
return true;
}
}
return false;
}
public String getAddr() {
if (addr16.length() > 0) {
return addr16;
}
if (addr26.length() > 0) {
return addr26;
}
return "";
}
public int getLineIndex() {
return lineIndex;
}
}