Skip to content

Commit

Permalink
First implementation of the disassembler
Browse files Browse the repository at this point in the history
  • Loading branch information
azertyfun committed Mar 20, 2016
1 parent b23276f commit 8973c60
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 7 deletions.
55 changes: 48 additions & 7 deletions src/tk/azertyfun/dcputoolchain/DebuggerInterface.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tk.azertyfun.dcputoolchain;

import tk.azertyfun.dcputoolchain.disassembler.Disassembler;
import tk.azertyfun.dcputoolchain.emulator.*;

import javax.swing.*;
Expand All @@ -8,6 +9,7 @@
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.LinkedHashMap;

public class DebuggerInterface extends JFrame {
private Action goToAddressAction = new AbstractAction("Go to address (Ctrl+G)") {
Expand All @@ -18,14 +20,15 @@ public void actionPerformed(ActionEvent actionEvent) {
};

private JButton goToAddress = new JButton(goToAddressAction);
private JEditorPane ramDump = new JEditorPane("text/html", ""), ramChar = new JEditorPane("text/html", "");
private JEditorPane ramDump = new JEditorPane("text/html", ""), ramChar = new JEditorPane("text/html", ""), ramDisassembled = new JEditorPane("text/html", "");

private JLabel regs = new JLabel(), stack = new JLabel(), logs = new JLabel("Logs: ");

private DCPU dcpu;
private TickingThread tickingThread;

private char currentAddress;
private boolean currentAddressisPC = false;

public DebuggerInterface(DCPU dcpu, TickingThread tickingThread, CallbackStop callbackStop) {
//runpause.addActionListener(actionEvent -> runpause());
Expand Down Expand Up @@ -90,19 +93,27 @@ public void actionPerformed(ActionEvent actionEvent) {

Panel viewers = new Panel();
BorderLayout layout = new BorderLayout();
layout.setHgap(10);
viewers.setLayout(layout);

Panel rams = new Panel();
BorderLayout ramsLayout = new BorderLayout();
ramsLayout.setHgap(10);
ramDump.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
//ramDump.setColumns(68);
//ramDump.setRows(32);
ramDump.setEditable(false);
viewers.add(ramDump, BorderLayout.WEST);
rams.add(ramDump, BorderLayout.WEST);

ramChar.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
//ramChar.setColumns(10);
//ramChar.setRows(32);
ramChar.setEditable(false);
viewers.add(ramChar, BorderLayout.CENTER);
rams.add(ramChar, BorderLayout.CENTER);

ramDisassembled.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
ramDisassembled.setEditable(false);
rams.add(ramDisassembled, BorderLayout.EAST);
viewers.add(rams, BorderLayout.WEST);

clearDebugInfo();

Expand Down Expand Up @@ -225,6 +236,12 @@ public void runpause() {

public void step() {
dcpu.step();
if(currentAddressisPC) {
currentAddress = dcpu.getCurrentInstruction();
while(currentAddress % 8 != 0) {
currentAddress--;
}
}
updateDebugInfo();
}

Expand All @@ -246,8 +263,10 @@ public void goToAddress() {

ActionListener actionListener = actionEvent -> {
String input = textField.getText();
currentAddressisPC = false;
if(input.equalsIgnoreCase("PC")) {
currentAddress = dcpu.get(0x10009);
currentAddress = dcpu.getCurrentInstruction();
currentAddressisPC = true;
} else if(input.equalsIgnoreCase("A")) {
currentAddress = dcpu.get(0x10000);
} else if(input.equalsIgnoreCase("B")) {
Expand Down Expand Up @@ -298,8 +317,10 @@ public void updateDebugInfo() {
if(dcpu.isPausing()) {
ramDump.setText("<html><head><style>body{font-family:monospace;font-size:10px;}</style></head><body>");
ramChar.setText("<html><head><style>body{font-family:monospace;font-size:10px;}</style></head><body>");
ramDisassembled.setText("<html><head><style>body{font-family:monospace;font-size:10px;}</style></head><body>");
String text = "0x" + String.format("%04x", (int) currentAddress) + ": ";
String charText = "";
String disassembledText = "";
for(int i = currentAddress; i < currentAddress + 32 * 8; ++i) {
String pcHighlighterOpen = i == dcpu.get(0x10009) ? "<strong>" : "";
String pcHighlighterClose = i == dcpu.get(0x10009) ? "</strong>" : "";
Expand All @@ -322,13 +343,27 @@ public void updateDebugInfo() {
else
charText += ".";
}
}


char[] ram = new char[32];
for(int i = 0; i < 32; ++i) {
ram[i] = dcpu.get(currentAddress + i - 16);
}
Disassembler disassembler = new Disassembler(ram, dcpu.getCurrentInstruction(), (char) (currentAddress - 16));
LinkedHashMap<String, Boolean> disassembled = disassembler.disassemble();
for(String key : disassembled.keySet()) {
if(disassembled.get(key))
disassembledText += "<strong>" + key + "</strong><br />";
else
disassembledText += key + "<br />";
}

text += "</body></html>";
charText += "</body></html>";
disassembledText += "</body></html>";
ramDump.setText(text);
ramChar.setText(charText);
ramDisassembled.setText(disassembledText);

goToAddress.setEnabled(true);

Expand Down Expand Up @@ -363,9 +398,11 @@ public void updateDebugInfo() {
public void clearDebugInfo() {
ramDump.setText("<html><head><style>body{font-family:monospace;font-size:10px;}</style></head><body>");
ramChar.setText("<html><head><style>body{font-family:monospace;font-size:10px;}</style></head><body>");
ramDisassembled.setText("<html><head><style>body{font-family:monospace;font-size:10px;}</style></head><body>");

String text = "0x0000: ";
String charText = "";
String disassembledText = "";
for(int i = 0; i < 32 * 8; ++i) {
if((i + 1) % 8 == 0 && i != 32 * 8 - 1) {
text += "0x0000<br />0x0000: ";
Expand All @@ -377,12 +414,16 @@ public void clearDebugInfo() {
text += "0x0000, ";
charText += ".";
}

}
for(int i = 0; i < 32; ++i)
disassembledText += "--------------------------<br />";

text += "</body></html>";
charText += "</body></html>";
disassembledText += "</body></html>";
ramDump.setText(text);
ramChar.setText(charText);
ramDisassembled.setText(disassembledText);

goToAddress.setEnabled(true);

Expand Down
217 changes: 217 additions & 0 deletions src/tk/azertyfun/dcputoolchain/disassembler/Disassembler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package tk.azertyfun.dcputoolchain.disassembler;

import java.util.HashMap;
import java.util.LinkedHashMap;

public class Disassembler {

public static HashMap<Character, String> opcodes = new HashMap<>();
static {
opcodes.put((char) 0x01, "SET");
opcodes.put((char) 0x02, "ADD");
opcodes.put((char) 0x03, "SUB");
opcodes.put((char) 0x04, "MUL");
opcodes.put((char) 0x05, "MLI");
opcodes.put((char) 0x06, "DIV");
opcodes.put((char) 0x07, "DVI");
opcodes.put((char) 0x08, "MOD");
opcodes.put((char) 0x09, "MDI");
opcodes.put((char) 0x0a, "AND");
opcodes.put((char) 0x0b, "BOR");
opcodes.put((char) 0x0c, "XOR");
opcodes.put((char) 0x0d, "SHR");
opcodes.put((char) 0x0e, "ASR");
opcodes.put((char) 0x0f, "SHL");
opcodes.put((char) 0x10, "IFB");
opcodes.put((char) 0x11, "IFC");
opcodes.put((char) 0x12, "IFE");
opcodes.put((char) 0x13, "IFN");
opcodes.put((char) 0x14, "IFG");
opcodes.put((char) 0x15, "IFA");
opcodes.put((char) 0x16, "IFL");
opcodes.put((char) 0x17, "IFU");
opcodes.put((char) 0x18, "0x0018");
opcodes.put((char) 0x19, "0x0019");
opcodes.put((char) 0x1a, "ADX");
opcodes.put((char) 0x1b, "SBX");
opcodes.put((char) 0x1c, "0x001c");
opcodes.put((char) 0x1d, "0x001d");
opcodes.put((char) 0x1e, "STI");
opcodes.put((char) 0x1f, "STD");
}
public static HashMap<Character, String> specialOpcodes = new HashMap<>();
static {
specialOpcodes.put((char) 0x00, "0x0000");
specialOpcodes.put((char) 0x01, "JSR");
specialOpcodes.put((char) 0x02, "0x0002");
specialOpcodes.put((char) 0x03, "0x0003");
specialOpcodes.put((char) 0x04, "0x0004");
specialOpcodes.put((char) 0x05, "0x0005");
specialOpcodes.put((char) 0x06, "0x0006");
specialOpcodes.put((char) 0x07, "0x0007");
specialOpcodes.put((char) 0x08, "INT");
specialOpcodes.put((char) 0x09, "IAG");
specialOpcodes.put((char) 0x0a, "IAS");
specialOpcodes.put((char) 0x0b, "RFI");
specialOpcodes.put((char) 0x0c, "IAQ");
specialOpcodes.put((char) 0x0d, "0x000d");
specialOpcodes.put((char) 0x0e, "0x000e");
specialOpcodes.put((char) 0x0f, "0x000f");
specialOpcodes.put((char) 0x10, "HWN");
specialOpcodes.put((char) 0x11, "HWQ");
specialOpcodes.put((char) 0x12, "HWI");
specialOpcodes.put((char) 0x13, "LOG");
specialOpcodes.put((char) 0x14, "BRK");
specialOpcodes.put((char) 0x15, "0x0015");
specialOpcodes.put((char) 0x16, "0x0016");
specialOpcodes.put((char) 0x17, "0x0017");
specialOpcodes.put((char) 0x18, "0x0018");
specialOpcodes.put((char) 0x19, "0x0019");
specialOpcodes.put((char) 0x1a, "0x001a");
specialOpcodes.put((char) 0x1b, "0x001b");
specialOpcodes.put((char) 0x1c, "0x001c");
specialOpcodes.put((char) 0x1d, "0x001d");
specialOpcodes.put((char) 0x1e, "0x001e");
specialOpcodes.put((char) 0x1f, "0x001f");
}

private char[] ram;
private char offset;
private char pc = 0;
private char wordToHighlight;
private boolean wordHighlit = false;

public Disassembler(char[] ram, char wordToHighlight, char offset) {
this.ram = ram;
this.offset = offset;
this.wordToHighlight = wordToHighlight;
}

public LinkedHashMap<String, Boolean> disassemble() {
LinkedHashMap<String, Boolean> instructions = new LinkedHashMap<>();

while(pc < ram.length) {
String instruction = "";
char currentInstruction = pc;

instruction += "0x" + String.format("%04x", (int) (currentInstruction + offset)) + ": ";

char word = ram[pc++];
char opcode = (char) (word & 0b11111);
char a = (char) ((word >> 10) & 0b111111);
char b = (char) ((word >> 5) & 0b11111);

if(opcode == 0) { //Special opcode
opcode = b;
instruction += specialOpcodes.get(opcode);
instruction += " " + get(a, true);
} else {
instruction += opcodes.get(opcode);
instruction += " " + get(b, false) + ", " + get(a, true);
}

boolean highlight = false;
if(currentInstruction + offset >= wordToHighlight && !wordHighlit) {
highlight = true;
wordHighlit = true;
}

instructions.put(instruction, highlight);
}

return instructions;
}

public String get(char a, boolean isA) {
if(a <= 0x07) {
switch (a) {
case 0:
return "A";
case 1:
return "B";
case 2:
return "C";
case 3:
return "X";
case 4:
return "Y";
case 5:
return "Z";
case 6:
return "I";
case 7:
return "J";
default:
return "0x" + String.format("%04x", (int) a);
}
} else if(a <= 0x0F) {
switch (a - 0x08) {
case 0:
return "[A]";
case 1:
return "[B]";
case 2:
return "[C]";
case 3:
return "[X]";
case 4:
return "[Y]";
case 5:
return "[Z]";
case 6:
return "[I]";
case 7:
return "[J]";
default:
return "0x" + String.format("%04x", (int) a);
}
} else if(a <= 0x17) {
switch (a - 0x10) {
case 0:
return "[A + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
case 1:
return "[B + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
case 2:
return "[C + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
case 3:
return "[X + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
case 4:
return "[Y + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
case 5:
return "[Z + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
case 6:
return "[I + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
case 7:
return "[J + 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
default:
return String.format("%04x", (int) a);
}
} else if(a == 0x18) {
if(isA)
return "POP";
else
return "PUSH";
} else if(a == 0x19) {
return "PEEK";
} else if(a == 0x1A) {
return "PICK 0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????");
} else if(a == 0x1B) {
return "SP";
} else if(a == 0x1C) {
return "PC";
} else if(a == 0x1D) {
return "EX";
} else if(a == 0x1E) {
return "[0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????") + "]";
} else if(a == 0x1F) {
return "0x" + ((pc < ram.length) ? String.format("%04x", (int) ram[pc++]) : "0x????");
} else if(a <= 0x3F) {
if(a == 0x20)
return "0xffff";
else
return "0x" + String.format("%04x", a - 0x21);
} else {
return "0x" + String.format("%04x", (int) a);
}
}
}
Loading

0 comments on commit 8973c60

Please sign in to comment.