2003/09/18 08:10:36
[org.ibex.core.git] / src / org / xwt / mips / Compiler.java
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
2 package org.xwt.imp;
3
4 import java.util.*;
5 import java.io.*;
6
7 // FIXME: lb/sb/sh/lh need not be word aligned
8 // FIXME: memory accesses aren't handling sign-extending properly
9 // FIXME: probably have to implement nonaligned access
10 // FIXME: implement malloc()
11
12 // FIXME: implement an ELF parser based on RandomAccessFile
13
14 // FEATURE: progress indicator
15 // FEATURE: support n32 abi (passes more arguments in registers)
16 // FEATURE: trap on arithmetic overflows
17 // FEATURE: FPU
18 // FEATURE: we always know the value of the pc register; we should emit it as a literal when it appears in computations
19 // FEATURE: emit bytecode rather than .java code (for on-the-fly classloading without javac present in "real" JVMs)
20
21 /** reads a fully linked MIPS ELF binary image on stdin; writes a .java file on stdout */
22 public class MIPS {
23
24     static String runs = "";
25     static int last_emit = -1;
26     static DataInputStream dis;
27     public static void main(String[] s) throws IOException {
28
29         if (s.length != 2) {
30             System.err.println("usage: java " + MIPS.class.getName() + " <classname> <binary.mips>");
31             System.exit(-1);
32         }
33
34         String packageName = null;
35         String className = s[0];
36         if (s[0].indexOf('.') != -1) {
37             packageName = s[0].substring(0, s[0].lastIndexOf('.'));
38             className = s[0].substring(s[0].lastIndexOf('.') + 1);
39         }
40
41         System.out.println(prefix + "// This file was generated by MipsToJava");
42         if (packageName != null) System.out.println(prefix + "package " + packageName + ";");
43         System.out.println(prefix + "public class " + className + " {");
44         System.out.println(prefix + "");
45         System.out.println(prefix + "    public " + className + "() { }");
46         System.out.println(prefix + "");
47         System.out.println(prefix + "    // memory");
48         System.out.println(prefix + "    public int mem_read[][] = new int[65535][];");
49         System.out.println(prefix + "");
50         System.out.println(prefix + "    // same as mem_read unless a page is write-protected");
51         System.out.println(prefix + "    public int mem_write[][] = new int[65535][];");
52         System.out.println(prefix + "");
53         System.out.println(prefix + "    // program counter");
54         System.out.println(prefix + "    int pc = 0;");
55         System.out.println(prefix + "");
56         System.out.println(prefix + "    // temporary");
57         System.out.println(prefix + "    int tmp = 0;");
58         System.out.println(prefix + "");
59         System.out.println(prefix + "    // MIPS multiply/divide subsystem; 64-bit result");
60         System.out.println(prefix + "    long hilo = 0;");
61         System.out.println(prefix + "");
62         System.out.println(prefix + "    // General Purpose registers");
63         System.out.println(prefix + "    final int r0 = 0;");
64         System.out.println(prefix + "    int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0,");
65         System.out.println(prefix + "        r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0,");
66         System.out.println(prefix + "        r16 = 0, r17 = 0, r18 = 0, r19 = 0, r20 = 0, r21 = 0, r22 = 0, r23 = 0,");
67         System.out.println(prefix + "        r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0, r30 = 0, r31 = 0;");
68         System.out.println(prefix + "");
69
70         dis = new DataInputStream(new FileInputStream(s[1]));
71
72         // read the ELF header
73         if (dis.readByte() != 0x7f || dis.readByte() != 'E' || dis.readByte() != 'L' || dis.readByte() != 'F')
74             throw new RuntimeException("input file is not an ELF binary");
75         dis.skip(12);
76
77         if (dis.readShort() != 2)
78             throw new RuntimeException("binary is not a linked executable");
79
80         if (dis.readShort() != 8)
81             throw new RuntimeException("binary is not a MIPS R3000 binary");
82
83         dis.skip(4);
84         
85         int entry_point = dis.readInt();
86         String entry_point_string = Long.toString(entry_point & 0xffffffffL, 16);
87
88         int ph_offset = dis.readInt();
89         int sh_offset = dis.readInt();
90         if (ph_offset == 0) throw new RuntimeException("binary is not statically linked");
91         dis.skip(4);
92         dis.skip(2);
93
94         int ph_entry_size = dis.readShort();
95         int ph_num_entries = dis.readShort();
96         int sh_entry_size = dis.readShort();
97         int sh_num_entries = dis.readShort();
98         int string_table_section_number = dis.readShort();
99
100         int skipamount = sh_offset - (4 + 12 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2);
101         while (skipamount>0) skipamount -= (int)dis.skip(skipamount);
102
103         int[] p_type = new int[sh_num_entries];
104         int[] p_ofs = new int[sh_num_entries];
105         int[] addr = new int[sh_num_entries];
106         int[] p_size = new int[sh_num_entries];
107         int[] p_name = new int[sh_num_entries];
108         for(int i=0; i<sh_num_entries; i++) {
109             p_name[i] = dis.readInt();
110             p_type[i] = dis.readInt();
111             dis.skip(4);
112             addr[i] = dis.readInt();
113             p_ofs[i] = dis.readInt();
114             p_size[i] = dis.readInt();
115             dis.skip(sh_entry_size - 4 * 6);
116         }
117
118         dis.close();
119         dis = new DataInputStream(new FileInputStream(s[1]));
120
121         int seek = p_ofs[string_table_section_number];
122         while (seek > 0) seek -= dis.skip(seek);
123         char[] stringTable = new char[p_size[string_table_section_number]];
124         for(int i=0; i<p_size[string_table_section_number]; i++)
125             stringTable[i] = (char)dis.readByte();
126
127         dis.close();
128         dis = new DataInputStream(new FileInputStream(s[1]));
129
130         int pos = 0;
131         for(int i=0; i<sh_num_entries; i++) {
132
133             String name = "";
134             for(int j=p_name[i]; j<stringTable.length && stringTable[j] != 0; j++) name += stringTable[j];
135             System.out.println();
136             System.out.println(prefix + "// section \"" + name +
137                                "\" #" + i + "; file offset 0x" + Long.toString(p_ofs[i] & 0xffffffffL, 16) +
138                                ", vma 0x" + Long.toString(addr[i] & 0xffffffffL, 16) + 
139                                ", size 0x" + Long.toString(p_size[i] & 0xffffffff, 16));
140
141             if (name.equals(".sdata")) {
142         if (last_emit != -1) {
143             System.out.println(prefix + "                case 0x" + Long.toString((last_emit & 0xffffffffL) + 0x1000, 16) + ": return;");
144             System.out.println(prefix + "                default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
145             System.out.println(prefix + "        }");
146             System.out.println(prefix + "    }");
147             last_emit = -1;
148         }
149                 pos = 0; dis.close(); dis = new DataInputStream(new FileInputStream(s[1]));
150                 while(pos < p_ofs[i]) pos += dis.skip(p_ofs[i] - pos);
151                 String base = "0x" + Long.toString((addr[i] & 0xffff0000L) >> 16, 16);
152                 System.out.println(prefix + "    private void initData() {");
153                 System.out.println(prefix + "        r28 = 0x" + Long.toString((addr[i] - Short.MIN_VALUE - 12) & 0xffffffffL, 16) + ";");
154                 System.out.println(prefix + "        mem_read[" + base + "] = mem_write[" + base + "] = new int[65535];");
155                 for(long k=addr[i] & 0xffffffffL; k<((addr[i] + p_size[i]) & 0xffffffffL); k += 4)
156                     System.out.println(prefix + "        mem_write[" + base + "][0x" + Long.toString(k & 0xffff, 16) + "] = 0x" +
157                                        Long.toString(dis.readInt() & 0xffffffffL, 16) + ";");
158                 System.out.println(prefix + "    }");
159
160             } else if (name.equals(".text") /*|| name.equals(".init")*/) {
161                 if (pos > p_ofs[i]) { pos = 0; dis.close(); dis = new DataInputStream(new FileInputStream(s[1])); }
162                 while(pos < p_ofs[i]) pos += dis.skip(p_ofs[i] - pos);
163                 int remaining = p_size[i];
164                 for(int ofs = addr[i]; ofs < addr[i] + p_size[i];) {
165                     String base = Long.toString(ofs & 0xffffff00L, 16);
166                     int len = Math.min(((ofs + 0x100) & 0xffffff00) - ofs, remaining);
167                     emit(ofs, len, dis);
168                     last_emit = ofs;
169                     remaining -= len;
170                     ofs += len;
171                 }
172             }
173         }
174
175         if (last_emit != -1) {
176             System.out.println(prefix + "                case 0x" + Long.toString((last_emit & 0xffffffffL) + 0x1000, 16) + ": return;");
177             System.out.println(prefix + "                default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
178             System.out.println(prefix + "        }");
179             System.out.println(prefix + "    }");
180             last_emit = -1;
181         }
182
183         System.out.println();
184         System.out.println(prefix + "    public static void main(String[] s) { new " + className + "().main(); }");
185         System.out.println();
186         System.out.println(prefix + "    public void main() {");
187         System.out.println();
188         System.out.println(prefix + "        // allocate the stack");
189         System.out.println(prefix + "        mem_read[1] = mem_write[1] = new int[65535];");
190         System.out.println();
191         System.out.println(prefix + "        // set the stack pointer");
192         System.out.println(prefix + "        r29 = 0x0001ff00;");
193         System.out.println();
194         System.out.println(prefix + "        // set the \"return address\" from _start to point at the \"magic exit address\" (0xdeadbeef)");
195         System.out.println(prefix + "        r31 = 0xdeadbeef;");
196         System.out.println();
197         System.out.println(prefix + "        // read in the .data segment");
198         System.out.println(prefix + "        initData();");
199         System.out.println();
200         System.out.println(prefix + "        trampoline(0x" + entry_point_string + ");");
201         System.out.println();
202         System.out.println(prefix + "    }");
203         
204         System.out.println();
205         System.out.println(prefix + "    public void trampoline(int pc) {");
206         System.out.println(prefix + "        this.pc = pc;");
207         System.out.println(prefix + "        while(true) {");
208         System.out.println(prefix + "            switch(this.pc & 0xffffff00) {");
209         System.out.println(prefix + "                case 0xdeadbe00: System.out.println(\"exiting with return value \" + r2); System.exit(r2); continue;");
210         System.out.print(runs);
211         System.out.println(prefix + "                default: throw new Error(\"invalid address 0x\" + Long.toString(this.pc&0xffffffffL,16));");
212         System.out.println(prefix + "            }");
213         System.out.println(prefix + "        }");
214         System.out.println(prefix + "    }");
215         System.out.println(prefix + "}");
216     }
217
218     static int _instruction;
219     static boolean readnext = true;
220
221     /** reads <tt>numbytes</tt> from the stream, emitting <tt>case</tt> blocks starting at vaddr <tt>ofs</tt> */
222     static void emit(int vaddr, int numbytes, DataInputStream dis) throws IOException {
223         if (last_emit != -1 && ((last_emit & 0xffffff00) != (vaddr & 0xffffff00))) {
224             System.out.println(prefix + "                case 0x" + Long.toString((last_emit & 0xffffffffL) + 0x1000, 16) + ": return;");
225             System.out.println(prefix + "                default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
226             System.out.println(prefix + "        }");
227             System.out.println(prefix + "    }");
228         }
229         if (last_emit == -1 || ((last_emit & 0xffffff00) != (vaddr & 0xffffff00))) {
230             System.out.println("");
231             System.out.println(prefix + "    private void run_" + Long.toString(vaddr & 0xffffff00L,16) + "() {");
232             runs += "                case 0x" + Long.toString(vaddr & 0xffffff00L,16) +
233                 ": run_" + Long.toString(vaddr & 0xffffff00L,16) + "(); continue;\n";
234             System.out.println(prefix + "        switch(pc) {");
235         }
236         int ofs = vaddr;
237         try {
238             OUTER: for(ofs = vaddr; ofs < vaddr + numbytes; ofs+=4) {
239                 if (readnext) _instruction = dis.readInt();
240                 readnext = true;
241
242                 String istring = Long.toString(_instruction & 0xffffffffL, 16);
243                 while(istring.length() < 8) istring = "0" + istring;
244                 String ostring = Long.toString(ofs & 0xffffffffL, 16);
245                 while(ostring.length() < 8) ostring = "0" + ostring;
246                 System.out.print(prefix + "                /* " + istring + " */   case 0x" + ostring + ": System.out.println(\"pc=0x\" + Long.toString(pc&0xffffffffL,16));");
247
248                 emit_instruction(ofs, _instruction);
249             }
250         } catch (EOFException e) {
251             emit(ofs, "                // warning, reached EOF before section end");
252         } finally {
253             last_emit = ofs;
254         }  
255     }
256
257     private static void emit_instruction(int ofs, int instruction) throws IOException {
258         int op = (instruction >>> 26) & 0xff;                // bits 26-31
259         int rs = (instruction >> 21) & 0x1f;                 // bits 21-25
260         int rt = (instruction >> 16) & 0x1f;                 // bits 16-20 
261         int rd = (instruction >> 11) & 0x1f;                 // bits 11-15
262         int shamt = (instruction >> 6) & 0x1f;               // bits 6-10
263         int subcode = instruction & 0x3f;                    // bits 0-5
264         
265                 int branch_offset = (((instruction & 0x8000) << 16) | ((instruction & 0x7fff))) * 4;
266                 int jump_target = (instruction & 0x03ffffff) * 4;
267                 int signed_immediate = (int)((short)(instruction & 0xffff));
268                 int unsigned_immediate = instruction & 0xffff;
269                 
270                 switch(op) {
271                     
272                     case 0: {
273                         switch(subcode) {
274                             
275                         case 0:
276                             if (instruction == 0) emit(ofs, "    /* NOP */;");                     // NOP
277                             else emit(ofs, "    r" + rd + " = r" + rt + " << " + shamt + ";");     // SLL
278                             break;
279
280                         case 1: throw new Error("opcode 0, subcode 1 is not part of the MIPS I instruction set");
281
282                         case 2:
283                             emit(ofs, "    r" + rd + " = r" + rt + " >>> " + shamt + ";");    // SRL
284                             break;
285
286                         case 3:
287                             emit(ofs, "    r" + rd + " = r" + rt + " >> " + shamt + ";");     // SRA
288                             break;
289
290                         case 4:
291                             emit(ofs, "    r" + rd + " = r" + rt + " << (r" + rs + " % 32);");     // SLLV
292                             break;
293
294                         case 5: throw new Error("opcode 0, subcode 5 is not part of the MIPS I instruction set");
295
296                         case 6:
297                             emit(ofs, "    r" + rd + " = r" + rs + " >>> (r" + rt + " % 32);");     // SRLV
298                             break;
299
300                         case 7:
301                             emit(ofs, "    r" + rd + " = r" + rs + " >> (r" + rt + " % 32);");     // SRAV
302                             break;
303
304                         case 8:
305                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
306                             emit(ofs, "    pc = r" + rs + "; return;");                                   // JR
307                             break;
308                             
309                         case 9:
310                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
311                             emit(ofs, "    r" + rd + " = pc + 8; pc = r" + rs + "; return;");             // JALR
312                             break;
313                             
314                         case 10: throw new Error("opcode 0, subcode 10 is not part of the MIPS I instruction set");                            
315                         case 11: throw new Error("opcode 0, subcode 11 is not part of the MIPS I instruction set");                            
316
317                         case 12:
318                             emit(ofs, "    syscall(" + ((instruction & 0x07ffffc0) >> 6) + ");");         // SYSCALL
319                             break;
320                             
321                         case 13:
322                             emit(ofs, "    /* BREAKPOINT */");
323                             break;
324
325                         case 14: throw new Error("opcode 0, subcode 14 is not part of the MIPS I instruction set");
326                         case 15: throw new Error("opcode 0, subcode 15 is not part of the MIPS I instruction set");
327
328                         case 16:
329                             emit(ofs, "    r" + rd + " = (int)(hilo >>> 32);");               // MFHI
330                             break;
331
332                         case 17:
333                             emit(ofs, "    hilo = (hilo & 0x00000000ffffffffL) | ((r" + rs + " & 0xffffffffL) << 32);");   // MTHI
334                             break;
335                             
336                         case 18:
337                             emit(ofs, "    r" + rd + " = (int)hilo;");               // MFLO
338                             break;
339
340                         case 19:
341                             emit(ofs, "    hilo = (hilo & 0xffffffff00000000L) | (r" + rs + " & 0xffffffffL);");   // MTLO
342                             break;
343
344                         case 20: throw new Error("opcode 0, subcode 20 is not part of the MIPS I instruction set");
345                         case 22: throw new Error("opcode 0, subcode 22 is not part of the MIPS I instruction set");
346                         case 23: throw new Error("opcode 0, subcode 23 is not part of the MIPS I instruction set");
347                             
348                         case 24:
349                             emit(ofs, "    hilo = ((long)r" + rs + ") * ((long)r" + rt + ");");   // MULT
350                             break;
351
352                         case 25:
353                             emit(ofs, "    hilo = (r" + rs + " & 0xffffffffL) * (r" + rt + " & 0xffffffffL);");   // MULTU
354                             break;
355
356                         case 26:
357                             emit(ofs, "    hilo = (((r" + rs + " % r" + rt +") & 0xffffffffL) << 32) | ((r" + rs + " / r" + rt +") & 0xffffffffL);");   // DIV
358                             break;
359
360                         case 27:
361                             emit(ofs, "    hilo = (((r" + rs + " & 0xffffffffL) % (r" + rt +" & 0xffffffffL)) << 32) | " +               // DIVU
362                                   "((r" + rs + " & 0xffffffffL) / (r" + rt +" & 0xffffffffL));");   
363                             break;
364
365                         case 28: throw new Error("opcode 0, subcode 28 is not part of the MIPS I instruction set");
366                         case 29: throw new Error("opcode 0, subcode 29 is not part of the MIPS I instruction set");
367                         case 30: throw new Error("opcode 0, subcode 30 is not part of the MIPS I instruction set");
368                         case 31: throw new Error("opcode 0, subcode 31 is not part of the MIPS I instruction set");
369
370                         case 32:
371                             emit(ofs, "    r" + rd + " = r" + rs + " + r" + rt + ";");                                                    // ADD
372                             break;
373                             
374                         case 33:
375                             emit(ofs, "    r" + rd + " = (int)(((r" + rs + " & 0xffffffffL) + (r" + rt + " & 0xffffffffL)));");           // ADDU
376                             break;
377                             
378                         case 34:
379                             emit(ofs, "    r" + rd + " = r" + rs + " - r" + rt + ";");                                                    // SUB
380                             break;
381                             
382                         case 35:
383                             emit(ofs, "    r" + rd + " = (int)(((r" + rs + " & 0xffffffffL) - (r" + rt + " & 0xffffffffL)));");           // SUBU
384                             break;
385                             
386                         case 36:
387                             emit(ofs, "    r" + rd + " = r" + rs + " & r" + rt + ";");                                                    // AND
388                             break;
389
390                         case 37:
391                             emit(ofs, "    r" + rd + " = r" + rs + " | r" + rt + ";");                                                    // OR
392                             break;
393
394                         case 38:
395                             emit(ofs, "    r" + rd + " = r" + rs + " ^ r" + rt + ";");                                                    // XOR
396                             break;
397
398                         case 39:
399                             emit(ofs, "    r" + rd + " = ~(r" + rs + " | r" + rt + ");");                                                 // NOR
400                             break;
401
402                         case 40: throw new Error("opcode 0, subcode 40 is not part of the MIPS I instruction set");
403                         case 41: throw new Error("opcode 0, subcode 41 is not part of the MIPS I instruction set");
404
405                         case 42:
406                             emit(ofs, "    r" + rd + " = (r" + rs + " < r" + rt + ") ? 1 : 0;");                                          // SLT
407                             break;
408
409                         case 43:
410                             emit(ofs, "    r" + rd + " = ((r" + rs + " & 0xffffffffL) < (r" + rt + " & 0xffffffffL)) ? 1 : 0;");            // SLTU
411                             break;
412
413                         case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54:
414                         case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63:
415                             throw new Error("opcode 0, subcode " + subcode + " is not part of the MIPS I instruction set");                        
416                         default:
417                             throw new Error("opcode 0, subcode " + subcode + " is not a valid MIPS instruction");
418                         }
419                         break;
420                     }
421
422                 case 1: {
423                     switch(rt) {
424                     case 0:
425                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
426                         emit(ofs, "    if (r" + rs + " < 0) { pc += " + (branch_offset + 4) + "; return; }; ");                            // BLTZ
427                         break;
428
429                     case 1:
430                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
431                         emit(ofs, "    if (r" + rs + " >= 0) { pc += " + (branch_offset + 4) + "; return; }; ");                               // BGEZ
432                         break;
433
434                     case 16:
435                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
436                         emit(ofs, "    r31 = pc + 4; if (r" + rs + " < 0) { pc += " + (branch_offset + 4) + "; return; }; ");                  // BLTZAL
437                         break;
438
439                     case 17:
440                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
441                         emit(ofs, "    r31 = pc + 4; if (r" + rs + " >= 0) { pc += " + (branch_offset + 4) + "; return; }; ");                // BGEZAL
442                         break;
443
444                     default: throw new Error("opcode 1, subcode " + rt + " is not part of the MIPS I instruction set");
445                     }
446                     break;
447                 }
448                     
449                 case 2:
450                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
451                     emit(ofs, "    pc &= 0xf0000000; pc |= 0x" + Long.toString(jump_target & 0xffffffffL, 16) + "; return;");                                            // J
452                     break;
453
454                 case 3:
455                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
456                     emit(ofs, "    r31 = pc + 4; pc &= 0xf0000000; pc |= 0x" + Long.toString(jump_target & 0xffffffffL, 16) + "; return;");                                  // JAL
457                     break;
458
459                 case 4:
460                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
461                     emit(ofs, "    if (r" + rs + " == r" + rt + ") { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; ");                  // BEQ
462                     break;
463
464                 case 5:
465                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
466                     emit(ofs, "    if (r" + rs + " != r" + rt + ") { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; ");                  // BNE
467                     break;
468
469                 case 6:
470                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
471                     emit(ofs, "    if (r" + rs + " <= 0) { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; ");                            // BLEZ
472                     break;
473
474                 case 7:
475                             _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction);
476                     emit(ofs, "    if (r" + rs + " > 0) { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; ");                             // BGTZ
477                     break;
478
479                 case 8: case 9:
480                     emit(ofs, "    r" + rt + " = r" + rs + " + " + signed_immediate + ";");                                         // ADDI[U]
481                     break;
482                     
483                 case 10:
484                     emit(ofs, "    r" + rt + " = (r" + rs + " < " + signed_immediate + ") ? 1 : 0;");                               // SLTI
485                     break;
486                     
487                 case 11:
488                     emit(ofs, "    r" + rt + " = ((r" + rs + " & 0xffffffffL) < (" + signed_immediate + " & 0xffffffffL)) ? 1 : 0;");     // SLTIU
489                     break;
490                     
491                 case 12:
492                     emit(ofs, "    r" + rt + " = r" + rs + " & " + unsigned_immediate + ";");                                         // ANDI
493                     break;
494                     
495                 case 13:
496                     emit(ofs, "    r" + rt + " = r" + rs + " | " + unsigned_immediate + ";");                                         // ORI
497                     break;
498                     
499                 case 14:
500                     emit(ofs, "    r" + rt + " = r" + rs + " ^ " + unsigned_immediate + ";");                                         // XORI
501                     break;
502                     
503                 case 15:
504                     emit(ofs, "    r" + rt + " = " + unsigned_immediate + " << 16;");                                                 // LUI
505                     break;
506
507                 case 16: /* throw new Error("coprocessor instructions (opcode 16) are not implemented"); */
508                     emit(ofs, "    throw new Error(\"coprocessor instructions (opcode 16) are not implemented\");");
509                     break;
510                 case 17: throw new Error("coprocessor instructions (opcode 17) are not implemented");
511                 case 18: throw new Error("coprocessor instructions (opcode 18) are not implemented");
512
513                 case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28:
514                     throw new Error("opcode " + op + " is not part of the MIPS I instruction set @" + Long.toString(ofs & 0xffffffffL, 16));
515                     
516                 case 32: {
517                     String dest = "(r" + rs + " + " + signed_immediate + ")";
518                     emit(ofs, "    tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff];  r" + rt + " = ((tmp & 0x80) << 24) | (tmp & 0x7f);");       // LB
519                     break;
520                 }
521
522                 case 33:  {
523                     String dest = "(r" + rs + " + " + signed_immediate + ")";
524                     emit(ofs, "    tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff];  r" + rt + " = ((tmp & 0x8000) << 16) | (tmp & 0x7fff);");   // LH
525                     break;
526                 }
527
528                 case 34:
529                     emit(ofs, "    throw new Error(\"LWL (opcode 34) is not supported; are you sure you used -mstrict-align?\");");
530                     break;
531
532                 case 35: {
533                     String dest = "(r" + rs + " + " + signed_immediate + ")";
534                     emit(ofs, "    r" + rt + " = mem_read[" + dest + ">>>16][" + dest + " & 0xffff];");               // LW
535                     break;
536                 }
537
538                 case 36: {
539                     String dest = "(r" + rs + " + " + signed_immediate + ")";
540                     emit(ofs, "    r" + rt + " = mem_read[" + dest + ">>>16][" + dest + " & 0xffff] & 0xff;");       // LBU
541                     break;
542                 }
543
544                 case 37: {
545                     String dest = "(r" + rs + " + " + signed_immediate + ")";
546                     emit(ofs, "    r" + rt + " = mem_read[" + dest + ">>>16][" + dest + " & 0xffff] & 0xffff;");       // LHU
547                     break;
548                 }
549
550                 case 38:
551                     emit(ofs, "    throw new Error(\"LWR (opcode 38) is not supported; are you sure you used -mstrict-align?\");");
552                     break;
553
554                 case 39:  throw new Error("opcode 39 is not part of the MIPS I instruction set");
555
556                 case 40: {
557                     String dest = "(r" + rs + " + " + signed_immediate + ")";
558                     emit(ofs, "    tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff]; " +
559                           "mem_write[" + dest + ">>>16][" + dest + " & 0xffff] = (tmp & 0xffffff00) | (r" + rt + " & 0xff);");   // SB
560                     break;
561                 }
562                     
563                 case 41: {
564                     String dest = "(r" + rs + " + " + signed_immediate + ")";
565                     emit(ofs, "    tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff]; " +
566                           "mem_write[" + dest + ">>>16][" + dest + " & 0xffff] = (tmp & 0xffff0000) | (r" + rt + " & 0xffff);");   // SH
567                     break;
568                 }
569                     
570                 case 42:
571                     emit(ofs, "    throw new Error(\"SWL (opcode 42) is not supported; are you sure you used -mstrict-align?\");");
572                     break;
573
574                 case 43: {
575                     String dest = "(r" + rs + " + " + signed_immediate + ")";
576                     emit(ofs, "    mem_write[" + dest + ">>>16][" + dest + " & 0xffff] = r" + rt + ";");               // SW
577                     break;
578                 }
579
580                 case 44:  throw new Error("opcode 44 is not part of the MIPS I instruction set");
581                 case 45:  throw new Error("opcode 45 is not part of the MIPS I instruction set");
582
583                 case 46:
584                     emit(ofs, "    throw new Error(\"SWR (opcode 46) is not supported; are you sure you used -mstrict-align?\");");
585                     break;
586
587                 case 47:  throw new Error("opcode 47 is not part of the MIPS I instruction set");
588                 case 48:  throw new Error("opcode 48 is not part of the MIPS I instruction set");
589
590                 case 49:
591                     emit(ofs, "    throw new Error(\"floating point operations (opcode 49) are not yet supported\");");
592                     break;
593
594                 case 50:
595                     emit(ofs, "    throw new Error(\"floating point operations (opcode 50) are not yet supported\");");
596                     break;
597
598                 case 51: case 52: case 53: case 54: case 55: case 56:
599                     throw new Error("opcode " + op + " is not part of the MIPS I instruction set");
600
601                 case 57:
602                     emit(ofs, "    throw new Error(\"floating point operations (opcode 57) are not yet supported\");");
603                     break;
604
605                 case 58:
606                     emit(ofs, "    throw new Error(\"floating point operations (opcode 58) are not yet supported\");");
607                     break;
608
609                 case 60: case 61: case 62: case 63:
610                     throw new Error("opcode " + op + " is not part of the MIPS I instruction set");
611
612                 default:
613                     throw new Error("unknown opcode " + op);
614                 }
615     }
616
617
618         
619     static String prefix = "";
620     static void emit(int vaddr, String s) {
621         if (s.indexOf("r0 = ") != -1) s = "    /* NOP */";
622         if (!s.trim().endsWith("return;") && s.indexOf("throw") == -1) s += " pc = 0x" + Long.toString((vaddr + 4) & 0xffffffffL,16) + ";";
623         System.out.println(s);
624     }
625 }
626