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  
627