/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.tools;
import java.io.Serializable;
import java.util.*;
public class Instruction implements Serializable {
private static final long serialVersionUID = 1L;
enum StackType {
PUSH, POP, NOP
};
enum JmpType {
BR, JMP, NOP
};
public String name;
public int opcode;
public int opdSize;
public JmpType jType;
StackType sType;
/** Length of instruction without opd and nxt */
final static int INSTLEN = 10;
private Instruction(String s, int oc, int ops, JmpType jp, StackType st) {
name = s;
opcode = oc;
opdSize = ops;
jType = jp;
sType = st;
}
public String toString() {
return name;
}
public boolean isStackConsumer() {
return sType == StackType.POP;
}
public boolean isStackProducer() {
return sType == StackType.PUSH;
}
public boolean noStackUse() {
return sType == StackType.NOP;
}
private static Instruction[] ia = new Instruction[] {
//
// 'pop' instructions
//
new Instruction("pop", 0x000, 0, JmpType.NOP, StackType.POP),
new Instruction("and", 0x001, 0, JmpType.NOP, StackType.POP),
new Instruction("or", 0x002, 0, JmpType.NOP, StackType.POP),
new Instruction("xor", 0x003, 0, JmpType.NOP, StackType.POP),
new Instruction("add", 0x004, 0, JmpType.NOP, StackType.POP),
new Instruction("sub", 0x005, 0, JmpType.NOP, StackType.POP),
// st (vp) 3 bits
new Instruction("st0", 0x010 + 0, 0, JmpType.NOP, StackType.POP),
new Instruction("st1", 0x010 + 1, 0, JmpType.NOP, StackType.POP),
new Instruction("st2", 0x010 + 2, 0, JmpType.NOP, StackType.POP),
new Instruction("st3", 0x010 + 3, 0, JmpType.NOP, StackType.POP),
new Instruction("st", 0x010 + 4, 0, JmpType.NOP, StackType.POP),
new Instruction("stmi", 0x010 + 5, 0, JmpType.NOP, StackType.POP),
new Instruction("stvp", 0x018, 0, JmpType.NOP, StackType.POP),
new Instruction("stjpc", 0x019, 0, JmpType.NOP, StackType.POP),
new Instruction("star", 0x01a, 0, JmpType.NOP, StackType.POP),
new Instruction("stsp", 0x01b, 0, JmpType.NOP, StackType.POP),
// shift
new Instruction("ushr", 0x01c, 0, JmpType.NOP, StackType.POP),
new Instruction("shl", 0x01d, 0, JmpType.NOP, StackType.POP),
new Instruction("shr", 0x01e, 0, JmpType.NOP, StackType.POP),
// new Instruction("shift reserved", 0x1f, 0, JmpType.NOP, StackType.POP),
// 5 bits: 0x20-0x3f
new Instruction("stm", 0x020, 5, JmpType.NOP, StackType.POP),
// MMU 4 bit subfield selects function (pop type)
new Instruction("stmul", 0x040 + 0, 0, JmpType.NOP, StackType.POP),
new Instruction("stmwa", 0x040 + 1, 0, JmpType.NOP, StackType.POP),
new Instruction("stmra", 0x040 + 2, 0, JmpType.NOP, StackType.POP),
new Instruction("stmwd", 0x040 + 3, 0, JmpType.NOP, StackType.POP),
// array instructions
new Instruction("stald", 0x040 + 4, 0, JmpType.NOP, StackType.POP),
new Instruction("stast", 0x040 + 5, 0, JmpType.NOP, StackType.POP),
// getfield/putfield
new Instruction("stgf", 0x040 + 6, 0, JmpType.NOP, StackType.POP),
new Instruction("stpf", 0x040 + 7, 0, JmpType.NOP, StackType.POP),
// magic copying
new Instruction("stcp", 0x040 + 8, 0, JmpType.NOP, StackType.POP),
// bytecode read
new Instruction("stbcrd", 0x040 + 9, 0, JmpType.NOP, StackType.POP),
// store TOS to MMU index register for jopsys_*field
new Instruction("stidx", 0x040 + 0xa, 0, JmpType.NOP, StackType.POP),
// putstatic
new Instruction("stps", 0x040 + 0xb, 0, JmpType.NOP, StackType.POP),
// read constants through cache
new Instruction("stmrac", 0x040 + 0xc, 0, JmpType.NOP, StackType.POP),
// read through fully associative cache
new Instruction("stmraf", 0x040 + 0xd, 0, JmpType.NOP, StackType.POP),
// write through fully associative cache
new Instruction("stmwdf", 0x040 + 0xe, 0, JmpType.NOP, StackType.POP),
// stpfr used for reference asignment checks
new Instruction("stpfr", 0x040 + 0xf, 0, JmpType.NOP, StackType.POP),
//new Instruction("stpsr", 0x040 + 0xf, 0, JmpType.NOP, StackType.POP),
//new Instruction("stastr", 0x040 + 0xf, 0, JmpType.NOP, StackType.POP),
//
// 'push' instructions
//
// 5 bits: 0xa0-0xbf
new Instruction("ldm", 0x0a0, 5, JmpType.NOP, StackType.PUSH),
// 5 bits: 0xc0-0xdf
new Instruction("ldi", 0x0c0, 5, JmpType.NOP, StackType.PUSH),
// MMU 4 bit subfield selects function (push type)
new Instruction("ldmrd", 0x0e0 + 0, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ldmul", 0x0e0 + 1, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ldbcstart", 0x0e0 + 2, 0, JmpType.NOP, StackType.PUSH),
// ld (vp) 3 bits
new Instruction("ld0", 0x0e8 + 0, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ld1", 0x0e8 + 1, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ld2", 0x0e8 + 2, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ld3", 0x0e8 + 3, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ld", 0x0e8 + 4, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ldmi", 0x0e8 + 5, 0, JmpType.NOP, StackType.PUSH),
// 2 bits
new Instruction("ldsp", 0x0f0 + 0, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ldvp", 0x0f0 + 1, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ldjpc", 0x0f0 + 2, 0, JmpType.NOP, StackType.PUSH),
// ld opd 2 bits
new Instruction("ld_opd_8u", 0x0f4 + 0, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ld_opd_8s", 0x0f4 + 1, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ld_opd_16u", 0x0f4 + 2, 0, JmpType.NOP, StackType.PUSH),
new Instruction("ld_opd_16s", 0x0f4 + 3, 0, JmpType.NOP, StackType.PUSH),
new Instruction("dup", 0x0f8, 0, JmpType.NOP, StackType.PUSH),
//
// 'no SP change' instructions
//
new Instruction("nop", 0x100, 0, JmpType.NOP, StackType.NOP),
new Instruction("wait", 0x101, 0, JmpType.NOP, StackType.NOP),
new Instruction("jbr", 0x102, 0, JmpType.NOP, StackType.NOP),
// no SP change instructions for MMU
// 4 bit subfield selects function (pop type)
// getstatic, data cache invalidation, atomic start and end
new Instruction("stgs", 0x110 + 0x0, 0, JmpType.NOP, StackType.NOP),
new Instruction("cinval", 0x110 + 0x1, 0, JmpType.NOP, StackType.NOP),
new Instruction("atmstart", 0x110 + 0x2, 0, JmpType.NOP, StackType.NOP),
new Instruction("atmend", 0x110 + 0x3, 0, JmpType.NOP, StackType.NOP),
// branches
new Instruction("bz", 0x180, 6, JmpType.BR, StackType.POP),
new Instruction("bnz", 0x1c0, 6, JmpType.BR, StackType.POP),
new Instruction("jmp", 0x200, 9, JmpType.JMP, StackType.NOP),
};
public static Map<String, Instruction> map = new HashMap<String, Instruction>();
public static Map<Integer, Instruction> imap = new TreeMap<Integer, Instruction>();
static {
for (int i = 0; i < ia.length; ++i) {
map.put(ia[i].name, ia[i]);
imap.put(ia[i].opcode, ia[i]);
}
}
public static Instruction get(String name) {
return map.get(name);
}
public static Instruction get(int opcode) {
return imap.get(opcode);
}
public static void printVhdl() {
for (int i = 0; i < ia.length; ++i) {
Instruction ins = ia[i];
System.out.print("\t\t\twhen \"");
System.out.print(Jopa.bin(ins.opcode >>> ins.opdSize, INSTLEN
- ins.opdSize));
for (int j = 0; j < ins.opdSize; ++j) {
System.out.print("-");
}
System.out.print("\" =>\t\t\t-- ");
System.out.print(ins.name);
System.out.println();
}
System.out.println();
// we assume that the stack type is encoded in the upper
// 4 bits
StackType st[] = new StackType[16];
for (int i = 0; i < ia.length; ++i) {
Instruction ins = ia[i];
int idx = ins.opcode >>> (INSTLEN - 4);
if (st[idx] == null) {
st[idx] = ins.sType;
} else if (st[idx] != ins.sType) {
throw new Error("Conflicting stack types: " + ins.name);
}
}
for (int i = 0; i < 16; ++i) {
System.out.print("\t\twhen \"");
System.out.print(Jopa.bin(i, 4));
System.out.print("\" =>\t\t\t-- " + st[i]);
System.out.println();
if (st[i]==StackType.PUSH) {
System.out.println("\t\t\t\tis_push <= '1';");
}
if (st[i]==StackType.POP) {
System.out.println("\t\t\t\tis_pop <= '1';");
}
}
}
public static void printCsv() {
for (int i = 0; i < ia.length; ++i) {
Instruction ins = ia[i];
System.out.print(ins.name);
System.out.print(";;{");
System.out.print(Jopa.bin(ins.opcode >>> ins.opdSize, INSTLEN
- ins.opdSize));
for (int j = 0; j < ins.opdSize; ++j) {
System.out.print("-");
}
System.out.println("}");
}
}
public static void printTable() {
Instruction table[] = new Instruction[1024];
for (int i = 0; i < 1024; i++)
table[i] = null;
for (int i = 0; i < ia.length; ++i) {
Instruction ins = ia[i];
int up = 1 << ins.opdSize;
for (int j = 0; j < up; j++) {
int code = ins.opcode | j;
if (table[code] != null) {
System.err.println("Two entries for: " + code + " : " + ins
+ " and " + table[code]);
System.exit(1);
} else
table[code] = ins;
}
}
for (int i = 0; i < 256; i++) {
System.out.print(String.format("0x%02x ", i));
if (table[i] == null)
System.out.print("---");
else {
Instruction ins = table[i];
System.out.print(ins);
if (ins.opdSize != 0)
System.out.print(" " + (i & ((1 << ins.opdSize) - 1)));
if (ins.isStackConsumer())
System.out.print(" [-]");
else if (ins.isStackProducer())
System.out.print(" [+]");
}
System.out.println("");
}
}
public static String genJavaConstants() {
StringBuffer sb = new StringBuffer();
sb.append("package com.jopdesign.timing.jop;\n");
sb.append("public class MicrocodeConstants {\n");
for (Instruction i : ia) {
sb.append(String.format(
" public static final int %-15s = 0x%x; /* %s %s%s*/ \n",
i.name.toUpperCase(), i.opcode,
i.isStackConsumer() ? "consumer"
: (i.isStackProducer() ? "producer" : "nostack"),
i.opdSize != 0 ? "opd MS: not to confuse it with opd in mc"
: "", i.jType==JmpType.BR || i.jType==JmpType.JMP ? "jmp " : ""));
}
sb.append("};");
return sb.toString();
}
/**
* Reserved VHDL keywords
*/
static String[] reserved = {
"and", "or", "xor", "wait"
};
static String substReserved(String s) {
for (int i=0; i<reserved.length; ++i) {
if (reserved[i].equals(s)) {
return s+"_x";
}
}
return s;
}
/**
* Print the VHDL code for microcode mnemonics in the simulation.
*/
public static void printVhdlMicrocode() {
System.out.println("\ttype mcval is (");
for (int i = 0; i < ia.length; ++i) {
Instruction ins = ia[i];
System.out.println("\t\t"+substReserved(ins.name)+",");
}
System.out.println("\t\tunknown");
System.out.println("\t);");
System.out.println("\tsignal val : mcval;");
System.out.println("");
System.out.println("");
System.out.println("begin");
System.out.println("");
System.out.println("process(instr)");
System.out.println("begin");
System.out.println("");
System.out.println("\tval <= unknown;");
System.out.println("\tif instr(9)='1' then");
System.out.println("\t\tval <= jmp;");
System.out.println("\telsif instr(9 downto 6)=\"0110\" then");
System.out.println("\t\tval <= bz;");
System.out.println("\telsif instr(9 downto 6)=\"0111\" then");
System.out.println("\t\tval <= bnz;");
System.out.println("\telse");
System.out.println("\t\tcase instr is");
for (int i = 0; i < ia.length; ++i) {
Instruction ins = ia[i];
if (ins.opdSize>=6) {
continue; // jmp, bz, and bnz
}
for (int j=0; j<1<<ins.opdSize; ++j) {
System.out.print("\t\t\twhen \"");
System.out.print(Jopa.bin(ins.opcode+j, INSTLEN));
System.out.print("\" => val <= ");
System.out.println(substReserved(ins.name)+";");
}
}
System.out.println("");
System.out.println("\t\t\twhen others => null;");
System.out.println("\t\tend case;");
System.out.println("\tend if;");
System.out.println("");
System.out.println("end process;");
System.out.println("");
}
public static void main(String[] args) {
// printVhdl();
// printCsv();
// printTable();
// System.out.println(genJavaConstants());
printVhdlMicrocode();
}
}