0 Members and 2 Guests are viewing this topic.
Many of you here have requested a java virtual machine for the Prizm. (most notably Ashbad ) Well I have been studying my java bytecode and I believe that this is quite possible. If you did not know, java bytecode is a stack oriented language in which the Prizm excels at. Now I did not find any of the jazelle extensions that the arm has, but it doesn't mean that java is impossible. What can be done is code the proper functions for each of the instructions, some of which would only take 1 SH3 instruction. The other thing to do is remove all of those fancy, but unnecessary features of the JVM. Stuff like malicious code testing and maybe partial garbage collecting. So right now I'm kind of busy with about 4 other Prizm projects that I'm working on, but during the summer or maybe after the AP exams, I will have time to get started on this.
Java would be nice, assuming it's feasible. A bunch of people in the community already knows Java and maybe Builderboy could port some of his games to the Prizm.
General Parser form:If R0 holds a pointer to the first byte of the .class file STC.L SR,@–R15 // Store value to RET to. MOV.L @R0+,R1 MOV.L (Magic),R2 XOR R1,R2 // If both values are the same, 0->R2 TST R2,R2 BT/S Parse NOP RET (Magic) 0xCAFEBABE ParseVer: XOR R4,R4 MOV.L @R0+,R1 MOV.L (Min Major_Minor),R2 MOV.L (Max Major_Minor),R3 CMP/HS R2,R1 // If min version>version ROTL R4 CMP/HS R1,R3 // If version>max version ROTL R4 TST R4,R4 // If both false, 1->T BT/S ParseConst NOP RET (Min Major_Minor) 0x** ** ** ** // Upper two bytes are major version, lower two bytes are minor (Max Major_Minor) 0x** ** ** ** // Same as before ParseConst: MOV.L R0,@R15- // Store pointer to Constant pool MOV.W @R0+,R1 ROTL R1 CLRT ROTR R1 MOV.L R1,R8 ADD R1,R0 // Skip over Constant pool ParseFlags: XOR R12,R12 //Clear flag register MOV.W @R0+,R1 ROTL R1 CLRT ROTR R1 <Other flag checking?> OR R1,R12 // Add Access flags to lower 16 bits of flag register ParseClasses: CLRT XOR R2,R2 XOR R4,R4 MOV.L @R0-,R1 MOV.B 0x10,R3 Loop1: ADD 0xFF,R3 ROTR R3 BF/S Loop1 ROTL R2 // Move super_class index into R2 CMP/HS R1,R8 ROTL R4 CMP/HS R2,R8 ROTL R4 TST R8,R1 BT/S GetIndices1 NOP RET GetIndices1: MOV.L @R15+,R7 MOV.L R7,@R15- ADD R7,R1 MOV.W @R1,R1 <Handle this_class> ADD R7,R2 MOV.W @R2,R2 <Handle super_class> Parsefurther: Etc...
During runtime, the following are assumed: R12 is a 32 bit flag register. R13 holds PC. R14 points to the operand stack. R15 is a stack for interpreter use. aaload 0x32 aastore 0x53 aconst_null 0x01 aload 0x19 Also supports Wide format, which means the opcode is preceded by 0xC4 aload_<n> aload_0 opcode = 0x2A aload_1 opcode = 0x2B aload_2 opcode = 0x2C aload_3 opcode = 0x2D anewarray 0xBD areturn 0xB0 arraylength 0xBE astore 0x3A Also supports Wide format, which means the opcode is preceded by 0xC4 astore_<n> astore_0 opcode = 0x4B astore_1 opcode = 0x4C astore_2 opcode = 0x4D astore_3 opcode = 0x4E athrow 0xBF baload 0x33 bastore 0x54 bipush 0x10 breakpoint 0xCA Reserved opcode. Should not appear in any .class file. caload 0x34 castore 0x55 checkcast d2f d2i d2l dadd daload dastore dcmpg dcmpl dconst_<d> ddiv dload dload_<n> dmul dneg drem dreturn dstore dstore_<n> dsub dup dup2 dup2_x1 dup2_x2 dup_x1 dup_x2 f2d f2i f2l fadd 0x62 faload fastore fcmpg fcmpl fconst_<f> fconst_0 opcode = 0x0B (11) fconst_1 opcode = 0x0C (12) fconst_2 opcode = 0x0D fdiv 0x6E fload fload_<n> fmul 0x6A fneg 0x6A frem freturn fstore fstore_<n> fsub getfield getstatic goto goto_w i2b i2c i2d i2f i2l i2s iadd 0x60 iaload iand 0x7E iastore iconst_<n> iconst_m1 idiv 0x6C if_acmpeq if_acmpne if_icmpeq if_icmpge if_icmpgt if_icmple if_icmplt if_icmpne ifeq ifge ifgt ifle iflt ifne ifnonnull ifnull iinc iload iload_<n> impdep1 impdep2 imul ineg instanceof invokeinterface invokespecial invokestatic invokevirtual ior 0x80 MOV.L @R14+,R1 MOV.L @R14+,R2 OR R2,R1 MOV.L R1 irem 0x70 MOV.L @R14+,R0 MOV.L @R14+,R2 MOV R2,R3 SUB R0,R3 MOV $20,R4 DIV0U R0,R1 Startdiv: ADD $FF,R4 DIV1 R0,R1 TST R4,R4 BT/S Startdiv ROTCL R2 DMULU.L R2,R3 STS MACL,R2 MOV.L R2,@-R14 ireturn ishl ishr istore istore_<n> isub iushr ixor 0x82 MOV.L @R14+,R1 MOV.L @R14+,R2 XOR R2,R1 MOV.L R1 jsr 0xA8 jsr_w 0xC9 l2d l2f l2i ladd 0x61 laload land lastore lcmp lconst_<l> ldc ldc_w ldc2_w ldiv lload lload_<n> lmul lneg lookupswitch lor lrem lreturn lshl lshr lstore lstore_<n> lsub lushr lxor 0x83 monitorenter monitorexit multianewarray new newarray nop 0x00 pop pop2 putfield putstatic ret return saload sastore sipush swap tableswitch wide
It sounds interesting, but do you not need a VM to maintain the state of all the objects and run threads?
Okay, I took the liberty of spending a few days exploring the JVM and how it works. It's surprisingly simple. I see absolutely no reason why would we couldn't get a JVM running on the Prizm.I spent an hour tonight and wrote a routine to parse/validate about half of the .class file format (the rest should be fairly easy to parse). It could probably be used as initialization code for such a JVM.Code: [Select]General Parser form:If R0 holds a pointer to the first byte of the .class file STC.L SR,@–R15 // Store value to RET to. MOV.L @R0+,R1 MOV.L (Magic),R2 XOR R1,R2 // If both values are the same, 0->R2 TST R2,R2 BT/S Parse NOP RET (Magic) 0xCAFEBABE ParseVer: XOR R4,R4 MOV.L @R0+,R1 MOV.L (Min Major_Minor),R2 MOV.L (Max Major_Minor),R3 CMP/HS R2,R1 // If min version>version ROTL R4 CMP/HS R1,R3 // If version>max version ROTL R4 TST R4,R4 // If both false, 1->T BT/S ParseConst NOP RET (Min Major_Minor) 0x** ** ** ** // Upper two bytes are major version, lower two bytes are minor (Max Major_Minor) 0x** ** ** ** // Same as before ParseConst: MOV.L R0,@R15- // Store pointer to Constant pool MOV.W @R0+,R1 ROTL R1 CLRT ROTR R1 MOV.L R1,R8 ADD R1,R0 // Skip over Constant pool ParseFlags: XOR R12,R12 //Clear flag register MOV.W @R0+,R1 ROTL R1 CLRT ROTR R1 <Other flag checking?> OR R1,R12 // Add Access flags to lower 16 bits of flag register ParseClasses: CLRT XOR R2,R2 XOR R4,R4 MOV.L @R0-,R1 MOV.B 0x10,R3 Loop1: ADD 0xFF,R3 ROTR R3 BF/S Loop1 ROTL R2 // Move super_class index into R2 CMP/HS R1,R8 ROTL R4 CMP/HS R2,R8 ROTL R4 TST R8,R1 BT/S GetIndices1 NOP RET GetIndices1: MOV.L @R15+,R7 MOV.L R7,@R15- ADD R7,R1 MOV.W @R1,R1 <Handle this_class> ADD R7,R2 MOV.W @R2,R2 <Handle super_class> Parsefurther: Etc...Also, I have a full instruction list of the JVM, along with a few SH3 ASM routines I wrote that happen to perform those operations.Code: [Select]During runtime, the following are assumed: R12 is a 32 bit flag register. R13 holds PC. R14 points to the operand stack. R15 is a stack for interpreter use. aaload 0x32 aastore 0x53 aconst_null 0x01 aload 0x19 Also supports Wide format, which means the opcode is preceded by 0xC4 aload_<n> aload_0 opcode = 0x2A aload_1 opcode = 0x2B aload_2 opcode = 0x2C aload_3 opcode = 0x2D anewarray 0xBD areturn 0xB0 arraylength 0xBE astore 0x3A Also supports Wide format, which means the opcode is preceded by 0xC4 astore_<n> astore_0 opcode = 0x4B astore_1 opcode = 0x4C astore_2 opcode = 0x4D astore_3 opcode = 0x4E athrow 0xBF baload 0x33 bastore 0x54 bipush 0x10 breakpoint 0xCA Reserved opcode. Should not appear in any .class file. caload 0x34 castore 0x55 checkcast d2f d2i d2l dadd daload dastore dcmpg dcmpl dconst_<d> ddiv dload dload_<n> dmul dneg drem dreturn dstore dstore_<n> dsub dup dup2 dup2_x1 dup2_x2 dup_x1 dup_x2 f2d f2i f2l fadd 0x62 faload fastore fcmpg fcmpl fconst_<f> fconst_0 opcode = 0x0B (11) fconst_1 opcode = 0x0C (12) fconst_2 opcode = 0x0D fdiv 0x6E fload fload_<n> fmul 0x6A fneg 0x6A frem freturn fstore fstore_<n> fsub getfield getstatic goto goto_w i2b i2c i2d i2f i2l i2s iadd 0x60 iaload iand 0x7E iastore iconst_<n> iconst_m1 idiv 0x6C if_acmpeq if_acmpne if_icmpeq if_icmpge if_icmpgt if_icmple if_icmplt if_icmpne ifeq ifge ifgt ifle iflt ifne ifnonnull ifnull iinc iload iload_<n> impdep1 impdep2 imul ineg instanceof invokeinterface invokespecial invokestatic invokevirtual ior 0x80 MOV.L @R14+,R1 MOV.L @R14+,R2 OR R2,R1 MOV.L R1 irem 0x70 MOV.L @R14+,R0 MOV.L @R14+,R2 MOV R2,R3 SUB R0,R3 MOV $20,R4 DIV0U R0,R1 Startdiv: ADD $FF,R4 DIV1 R0,R1 TST R4,R4 BT/S Startdiv ROTCL R2 DMULU.L R2,R3 STS MACL,R2 MOV.L R2,@-R14 ireturn ishl ishr istore istore_<n> isub iushr ixor 0x82 MOV.L @R14+,R1 MOV.L @R14+,R2 XOR R2,R1 MOV.L R1 jsr 0xA8 jsr_w 0xC9 l2d l2f l2i ladd 0x61 laload land lastore lcmp lconst_<l> ldc ldc_w ldc2_w ldiv lload lload_<n> lmul lneg lookupswitch lor lrem lreturn lshl lshr lstore lstore_<n> lsub lushr lxor 0x83 monitorenter monitorexit multianewarray new newarray nop 0x00 pop pop2 putfield putstatic ret return saload sastore sipush swap tableswitch wideOpcodes and descriptions can be found here.Quote from: graphmastur on April 04, 2011, 07:18:15 amIt sounds interesting, but do you not need a VM to maintain the state of all the objects and run threads?That depends on what you mean by "Virtual machine." The JVM is essentially nothing more than an interpreter. It just happens to interpret the machine code for a virtual machine.
General Parser form:If R0 holds pointer to the first byte of the .class file STC.L SR,@–R15 // Store value to RET to. MOV.L @R0+,R1 MOV.L (Magic),R2 XOR R1,R2 // If both values are the same, 0->R2 TST R2,R2 BT/S Parse NOP RET (Magic) 0xCAFEBABE ParseVer: XOR R4,R4 MOV.L @R0+,R1 MOV.L (Min Major_Minor),R2 MOV.L (Max Major_Minor),R3 CMP/HS R2,R1 // If min version>version ROTL R4 CMP/HS R1,R3 // If version>max version ROTL R4 TST R4,R4 // If both false, 1->T BT/S ParseConst NOP RET (Min Major_Minor) 0x** ** ** ** // Upper two bytes are major version, lower two bytes are minor (Max Major_Minor) 0x** ** ** ** // Same as before ParseConst: MOV.L R0,@R15- // Store pointer to Constant pool MOV.W @R0+,R1 MOV.L R1,R8 ROTL R1 ADD R1,R0 // Skip over Constant pool ParseFlags: XOR R12,R12 //Clear flag register MOV.W @R0+,R1 ROTL R1 CLRT ROTR R1 <Other flag checking?> OR R1,R12 // Add Access flags to lower 16 bits of flag register ParseClasses: XOR R2,R2 XOR R4,R4 MOV.L @R0-,R1 MOV.B 0x10,R3 CLRT Loop1: ADD 0xFF,R3 ROTR R3 TST R3,R3 BF/S Loop1 ROTL R2 // Move super_class index into R2 CMP/HS R1,R8 ROTL R4 CMP/HS R2,R8 ROTL R4 TST R4,R4 BT/S GetIndices1 NOP RET GetIndices1: MOV.L @R15+,R7 MOV.L R7,@R15- ADD R7,R1 MOV.W @R1,R1 <Handle this_class> ADD R7,R2 MOV.W @R2,R2 <Handle super_class> Parsefurther: MOV.L R0,@15- MOV.W @R0+,R1 MOV.W R1,R4 XOR R2.R2 Loop2: ADD 0xFF,R1 MOV.W @R0+,R3 CMP/HS R3,R8 // R8 must be carried from the previous sections! TST R1,R1 BF/S Loop1 ADD 0x01,R2 ADD 0xFF,R2 CMP/EQ R2,R4 BT/S FieldsMethods NOP RET FieldsMethods: MOV 0x01,R3 Loop3: MOV.L R0,@R15- MOV.W @R0+,R1 MOV 0x04,R2 MULU.W R1,R2 STS MACL,R1 ADD R1,R0 TST R3 BF/S Loop3 ADD 0xFF,R3 Parseattribs: MOV.W @R0+,R1 MOV 0x07,R2 MULU.W R1,R2 STS MACL,R2 MOV.L R0,@R15- ADD R2,R0 ParseInstruct: Etc...When it's reached the end of the header, the stack contains pointers to the Attributes table, the methods table, the fields table, the constant pool table, as well as a pointer to a the location to exit to. There might are a few bugs in this code that I still have to fix, but it's mostly functional.
Nice catch. I must have missed that.However, I just noticed a simpler way of detecting .class files: use the "magic" number 0xCAFEBABE. It's present in all .class files, so it can identify them and my file format can easily allow that particular header to be invalid.