Skip to content

Commit d9ee3c0

Browse files
committed
Add initial compiler, abstract machine, and testing code
1 parent 284e855 commit d9ee3c0

File tree

514 files changed

+15408
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

514 files changed

+15408
-0
lines changed

mJAM/Disassembler.java

+309
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
/**
2+
* generate human readable mJAM instructions
3+
* @author prins
4+
* @version COMP 520 V2.2
5+
*/
6+
package mJAM;
7+
8+
import java.io.FileWriter;
9+
import java.io.IOException;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
import java.util.SortedSet;
13+
import java.util.TreeSet;
14+
15+
/**
16+
* Disassemble the mJAM object code
17+
* from input file xxx.mJAM
18+
* into output file xxx.asm
19+
*
20+
* @author prins
21+
* @version COMP 520 v2.2
22+
*/
23+
public class Disassembler {
24+
25+
private String objectFileName;
26+
private String asmName;
27+
private FileWriter asmOut;
28+
private boolean error = false;
29+
private Map<Integer, String> addrToLabel;
30+
31+
public Disassembler(String objectFileName) {
32+
this.objectFileName = objectFileName;
33+
}
34+
35+
/**
36+
* Writes the r-field of an instruction in the form "l<I>reg</I>r", where
37+
* l and r are the bracket characters to use.
38+
* @param leftbracket the character to print before the register.
39+
* @param r the number of the register.
40+
* @param rightbracket the character to print after the register.
41+
*/
42+
private void writeR(char leftbracket, int r, char rightbracket) {
43+
asmWrite(Character.toString(leftbracket));
44+
asmWrite(Machine.intToReg[r].toString());
45+
asmWrite(Character.toString(rightbracket));
46+
}
47+
48+
/**
49+
* Writes a void n-field of an instruction.
50+
*/
51+
private void blankN() {
52+
asmWrite(" ");
53+
}
54+
55+
// Writes the n-field of an instruction.
56+
/**
57+
* Writes the n-field of an instruction in the form "(n)".
58+
* @param n the integer to write.
59+
*/
60+
private void writeN(int n) {
61+
asmWrite(String.format("%-6s","(" + n + ")"));
62+
}
63+
64+
/**
65+
* Writes the d-field of an instruction.
66+
* @param d the integer to write.
67+
*/
68+
private void writeD(int d) {
69+
asmWrite(Integer.toString(d));
70+
}
71+
72+
/**
73+
* Writes the name of primitive routine with relative address d.
74+
* @param d the displacment of the primitive routine.
75+
*/
76+
private void writePrimitive(int d) {
77+
Machine.Prim prim = Machine.intToPrim[d];
78+
asmWrite(String.format("%-8s",prim.toString()));
79+
}
80+
81+
/**
82+
* Writes the given instruction in assembly-code format.
83+
* @param instr the instruction to display.
84+
*/
85+
private void writeInstruction(Instruction instr) {
86+
87+
String targetLabel = "***";
88+
// get label of destination addr, if instr transfers control
89+
if (instr.r == Machine.Reg.CB.ordinal())
90+
targetLabel = addrToLabel.get(instr.d);
91+
92+
Machine.Op instruction = Machine.intToOp[instr.op];
93+
asmWrite(String.format("%-7s",instruction.toString()));
94+
switch (instruction) {
95+
case LOAD:
96+
blankN();
97+
writeD(instr.d);
98+
writeR('[', instr.r, ']');
99+
break;
100+
101+
case LOADA:
102+
blankN();
103+
writeD(instr.d);
104+
writeR('[', instr.r, ']');
105+
break;
106+
107+
case LOADI:
108+
break;
109+
110+
case LOADL:
111+
blankN();
112+
writeD(instr.d);
113+
break;
114+
115+
case STORE:
116+
blankN();
117+
writeD(instr.d);
118+
writeR('[', instr.r, ']');
119+
break;
120+
121+
case STOREI:
122+
break;
123+
124+
case CALL:
125+
if (instr.r == Machine.Reg.PB.ordinal()) {
126+
blankN();
127+
writePrimitive(instr.d);
128+
} else {
129+
blankN();
130+
asmWrite(targetLabel);
131+
}
132+
break;
133+
134+
case CALLI:
135+
blankN();
136+
asmWrite(targetLabel);
137+
break;
138+
139+
case RETURN:
140+
writeN(instr.n);
141+
writeD(instr.d);
142+
break;
143+
144+
case CALLD:
145+
blankN();
146+
writeD(instr.d);
147+
break;
148+
149+
case PUSH:
150+
blankN();
151+
writeD(instr.d);
152+
break;
153+
154+
case POP:
155+
blankN();
156+
writeD(instr.d);
157+
break;
158+
159+
case JUMP:
160+
blankN();
161+
asmWrite(targetLabel);
162+
break;
163+
164+
case JUMPI:
165+
break;
166+
167+
case JUMPIF:
168+
writeN(instr.n);
169+
asmWrite(targetLabel);
170+
break;
171+
172+
case HALT:
173+
writeN(instr.n);
174+
break;
175+
176+
default:
177+
asmWrite("???? ");
178+
writeN(instr.n);
179+
writeD(instr.d);
180+
writeR('[', instr.r, ']');
181+
break;
182+
}
183+
}
184+
185+
/**
186+
* disassembles program held in code store
187+
*/
188+
void disassembleProgram(String asmFileName) {
189+
190+
try {
191+
asmOut = new FileWriter(asmFileName);
192+
} catch (IOException e) {
193+
System.out.println("Disassembler: can not create asm output file "
194+
+ asmName);
195+
error = true;
196+
return;
197+
}
198+
199+
// collect all addresses that may be the target of a jump instruction
200+
SortedSet<Integer> targets = new TreeSet<Integer>();
201+
for (int addr = Machine.CB; addr < Machine.CT; addr++) {
202+
Instruction inst = Machine.code[addr];
203+
Machine.Op op = Machine.intToOp[inst.op];
204+
switch (op) {
205+
case CALL:
206+
case CALLI:
207+
// only consider calls (branches) within code memory (i.e. not primitives)
208+
if (inst.r == Machine.Reg.CB.ordinal())
209+
targets.add(inst.d);
210+
break;
211+
case JUMP:
212+
// address following an unconditional branch is an implicit target
213+
targets.add(addr+1);
214+
targets.add(inst.d);
215+
break;
216+
case JUMPIF:
217+
// a jump of any sort creates a branch target
218+
targets.add(inst.d);
219+
break;
220+
default:
221+
break;
222+
}
223+
}
224+
225+
// map branch target addresses to unique labels
226+
addrToLabel = new HashMap<Integer, String>();
227+
int labelCounter = 10;
228+
for (Integer addr : targets) {
229+
String label = "L" + labelCounter++ ;
230+
addrToLabel.put(addr, label);
231+
}
232+
233+
// disassemble each instruction
234+
for (int addr = Machine.CB; addr < Machine.CT; addr++) {
235+
236+
// generate instruction address
237+
asmWrite(String.format("%3d ", addr));
238+
239+
// if this addr is a branch target, output label
240+
if (addrToLabel.containsKey(addr))
241+
asmWrite(String.format("%-7s", addrToLabel.get(addr) + ":"));
242+
else
243+
asmWrite(" ");
244+
245+
// instruction
246+
writeInstruction(Machine.code[addr]);
247+
248+
// newline
249+
asmWrite("\n");
250+
}
251+
252+
// close output file
253+
try {
254+
asmOut.close();
255+
} catch (IOException e) {
256+
error = true;
257+
}
258+
}
259+
260+
private void asmWrite(String s) {
261+
try {
262+
asmOut.write(s);
263+
} catch (IOException e) {
264+
error = true;
265+
}
266+
}
267+
268+
public static void main(String[] args) {
269+
System.out.println("********** mJAM Disassembler (1.0) **********");
270+
String objectFileName = "obj.mJAM";
271+
if (args.length == 1)
272+
objectFileName = args[0];
273+
Disassembler d = new Disassembler(objectFileName);
274+
d.disassemble();
275+
}
276+
277+
/**
278+
* Disassemble object file
279+
* @return true if error encountered else false
280+
*/
281+
public boolean disassemble() {
282+
ObjectFile objectFile = new ObjectFile(objectFileName);
283+
284+
// read object file into code store
285+
if (objectFile.read()) {
286+
System.out.println("Disassembler: unable to read object file"
287+
+ objectFileName);
288+
return true;
289+
}
290+
291+
// assembler-code output file name
292+
if (objectFileName.endsWith(".mJAM"))
293+
asmName = objectFileName.substring(0, objectFileName.length() - 5)
294+
+ ".asm";
295+
else
296+
asmName = objectFileName + ".asm";
297+
298+
// disassemble to file
299+
disassembleProgram(asmName);
300+
301+
if (error) {
302+
System.out.println("Disassembler: unable to write asm file"
303+
+ asmName);
304+
return true;
305+
}
306+
307+
return false;
308+
}
309+
}

mJAM/Instruction.java

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* mJAM instruction format
3+
* @author prins
4+
* @version COMP 520 V2.3
5+
*/
6+
package mJAM;
7+
8+
public class Instruction {
9+
10+
public Instruction() {
11+
op = 0;
12+
r = 0;
13+
n = 0;
14+
d = 0;
15+
}
16+
17+
public Instruction(int op, int n, int r, int d) {
18+
this.op = op;
19+
this.n = n;
20+
this.r = r;
21+
this.d = d;
22+
}
23+
24+
// Java has no type synonyms, so the following representations are
25+
// assumed:
26+
//
27+
// type
28+
// OpCode = 0..15; {4 bits unsigned}
29+
// Register = 0..15; (4 bits unsigned)
30+
// Length = 0..255; {8 bits unsigned}
31+
// Operand = -2147483648 .. +2147483647; (32 bits signed for use with LOADL)
32+
public int op; // OpCode
33+
public int r; // RegisterNumber
34+
public int n; // Length
35+
public int d; // Operand
36+
}

0 commit comments

Comments
 (0)