PDA

View Full Version : JVM for prop



Pages : [1] 2

Peter Verkaik
01-22-2008, 06:32 AM
Having done the smallc and examined what would be required to add longs and floats to smallc,
I decided that it is not worth the effort. Instead I tried some things with the Javelin IDE program.
It turns out, the compiler used to compile javelin code does support longs, floats and doubles
and multidimensional arrays. It is the javelin linker that throws errors when using these types.
See picture for some demo code using all types. The linker has been made public some time
ago and is part of the JavelinDirect package and you can find that package here:
http://tech.groups.yahoo.com/group/JavelinCode/files/JavelinDirect/
That linker generates a (up to) 32KB eeprom image. I think I can easily change that
to create a spin file with a DAT area holding the byte codes.·Which means we only need
a JVM (and some native routines) to run java code (java 1.1).
I also attached a spin file with all byte code values defined, and commented out
types currently not supported. The JVM could be done in spin for now, as I did for smallc.

Here are the types and their memory use:
· primitive· storage/value· supported
· boolean···· 2bytes/1bit····· yes···
· byte······· 2bytes/1byte···· yes····· byte[n] storage is 2 ints + n bytes
· char······· 2bytes/1byte···· yes····· char[n] storage is 2 ints + n bytes
· short······ 2bytes/2bytes··· yes···
· int········ 2bytes/2bytes··· yes···
· long······· 4bytes/4bytes··· later·
· float······ 4bytes/4bytes··· later·
· double····· 8bytes/8bytes··· later·
······································· other arrays: 2 ints + n*storage bytes

The types currently not supported generate an error, and I just need to change the linker to generate
the appropiate byte codes. For now I would like to get a working JVM for the supported types.
I will start working on the linker. If anyone wishes to participate by setting up a JVM in spin,
you're welcome. Using java, we will have true object passing, classes, unlimited include path's
so we can use multiple·folders to maintain applications.

regards peter

Mark Swann
01-22-2008, 07:28 AM
Great idea. Wish I had the time to commit to the JVM. It should (of course) ultimately be in ASM, but one step at at time.

hippy
01-22-2008, 09:28 AM
I've use Java ( TinyVm, now LeJOS ) on the Lego RCX 'brick' and that worked well for what it did using the standard Sun Java compiler and tools AFAIR.

I haven't done any Java in years but did recently return to look at the JVM specification. It certainly looks possible; it's well defined and there are others who have done similar. Plenty of books available and the source code for the JVM itself, from Sun and third parties.

java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html (http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html)

Peter Verkaik
01-22-2008, 12:23 PM
Thanks for the link.

regards peter

simonl
01-22-2008, 05:56 PM
Excellent work Peter. I'm not a Java programmer, but will be watching this thread with interest, and it might just spur me on to learn Java when it's all working http://forums.parallax.com/images/smilies/smile.gif

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheers,

Simon
-------------------------------
www.norfolkhelicopterclub.co.uk (http://www.norfolkhelicopterclub.co.uk)
You'll always have as many take-offs as landings, the trick is to be sure you can take-off again ;-)
BTW: I type as I'm thinking, so please don't take any offense at my writing style http://forums.parallax.com/images/smilies/smile.gif

hippy
01-23-2008, 02:52 AM
Are there any Java users, experts or gurus who frequent here ? Their help would be invaluable even if they are not able to commit to doing any major work on this project itself. Some mentoring is going to be essential I think for those of us who are not really that familiar with Java.

AIUI there are a number of things which make up for what people call "Java" -

A compiler which supports the core Java language and turns source into bytecode classes.

A set of provided classes which are like C-libraries/include files which provide pre-written functionality. Those can be tailored to suit what the propeller supports and provide the interface to the underlying hardware as well as more general purpose routines which are hardware independent.

A linker which turns bytecode classes into an application. This can also perform static linking and so on to minimise what the JVM has to support / do.

A JVM which runs on the target hardware which loads the bytecode, executes it and handles the interactions with hardware.

Developing Java for the Propeller is therefore a case of bringing all that together as a complete whole. This is what makes for that confusing set of Java implementations ( J2SE, J2ME, KVM, CDLC ) for the unfamiliar. It's the linking stage which I don't really have any understanding of and how that affects the JVM.

Looking at the bytecode, it seems the first 170 opcodes or so are nothing special, simply stuff that manipulates the stack, those above are the more complex ones. I'm out of my depth there.

I was enthused enough to look around to see what is available and already done and there are some quite small implementations out there; TinyVM and LeJOS already mentioned, plus NanoVM for the AVR ATmega8 with an 8KB footprint.

www.harbaum.org/till/nanovm/index.shtml (http://www.harbaum.org/till/nanovm/index.shtml)

I don't think it's a case of simply implementing a JVM, but also working from the other direction as well, the class files and linking in particular, and I'm not sure it's possible to develop the JVM in isolation.

I'd like to get involved but where I'm struggling is in understanding exactly what must be done, and how we would go about doing it.

Peter Verkaik
01-23-2008, 04:16 AM
Hippy and others,

I adapted the JavelinDirect sources. It now generates a spin file, which· holds
the binary image in the DAT area, of what would be loaded into the Javelin eeprom.
I also added a switch to the commandline to enable the debug output.
It turns out, the linker creates an image using only 86 bytecodes, called jemcodes.
I attached the java source for which I generated the spin file, the spin file itself,
an updated jvm file with jemcodes and the debug output.

The java class files are staticly linked and are the exact program as it runs on the javelin.
So besides a jvm we need some native routines that are listed at the end of the debug file.
(testJVM.txt). You will notice that at some point the entries in these tables take two words
whereas they start with one word. This is due to the fact that the generated jemcodes
where to run on a SX48, and the flashmemory (wordsize=12bits) of the sx48 is paged. For the prop we
can make all entries 1 word.

regards peter

jazzed
01-23-2008, 10:38 AM
Hi,

I'm a Java lover and have·written some applications professionally.·The Javelin Java variant left me wanting to meet the garbage collector :) Having a modern programming language on Prop·could have benefits.

So, this is an interesting idea, and who knows maybe we can fix the memory management issue. I spent some time porting the JavelinDirectSrc1.0 code MSC++ to play around today. WIN32 is a horrible pre-processor symbol don't you think :) I managed to get a testJVM debug·listing similar to your's on jem.out, but didn't see the 'address' method in your file .... There were a ton of other differences having to do mostly with the dec->hex printing. You have a .cvs repository somewhere ?

Seems that there is enough power here to do things in a decent way. Doing a JVM in spin might be a little slow but functional. Work done in the spin JVM can be leveraged in providing easily ported "pseudo-code" for more serious work when a good C-compiler is available.

Do you think the JVM might be able to step in when a Task class is used·and loading up and run on a·cog·? (not sure·I remember "Task" correctly from my brief Javelin experiments). Not sure what is possible in the JVM, but there appear to be hooks for the "native" code for which a subset, I imagine, can be implemented in the JVM. Looks like there is a good deal of work left to do in the JVM. This does seem like it can be a bit of a chicken/egg problem though considering the size of jem.out. Seems that one may need a debugger.

I'm no java expert, but I can make contributions here.·This forum of provides a fair medium for project workload distribution and status. Peter may be finished coding before I post this message :) The project seems to be big enough to stress even his prolific producivity though.

Looking forward to the next installment ....

hippy
01-23-2008, 11:06 AM
@ Peter : Thanks for that, the mists are clearing. I hadn't realised your own experience with Java / Javalin / JavelinDirect when I asked about mentors and guru's so I hope no offence was taken.

Given the way the JavelinDirect works ( and looking at the .txt ) I don't see any major problems. I'm presuming the native methods are those from the stamp.* class files and they'd simply be replaced by whatever native methods propeller.* class files use ?

I've got the JavelinStamp software ( including Jikes ) and the JavelinDirect source code now so feeling quite confident that you're on the right track.

Is there a pre-compiled JavelinDirect.exe available - doesn't have to be the latest with floats and longs added ?

Peter Verkaik
01-23-2008, 12:34 PM
@Jazzed,
I think garbage collection can be added without
sacrificing realtime behaviour by using a seperate COG
to do the garbage collection. The same applies to
adding threads.
For now, I am just trying to get a working jvm that
lets me execute javelin code.
The Javelin IDE has a single step debugger that
could be converted for the prop I suppose. As I
maintain the Javelin IDE right now, I could even
add an option to let the Javelin IDE beta generate
the spin file, as the linker integrated into the IDE
is the same as JavelinDirect (as that·was extracted
from the IDE).
Regarding the native methods, at the moment that
is a fixed table as the javelin does not support user
defined native methods. For the prop that could be
changed by letting the linker add entries to the table
for any userdefined native method.

@Hippy,
I added the native methods to the jvm.spin file.
All Virtual Peripherals (background tasks, not threads!)
have a java wrapper class that calls·native methods.
These VP's··have a 16byte register area that is setup
by using registerRead and registerWrite native methods.
Fortunately, all those registers are defined in the
wrapper classes so I can extract the memory map from
those classes.
I attached an executable PropDirect that is an adapted
JavelinDirect.
To use it:
propdirect --path "c:\javelin\lib;c:\javelin" --port 1 --link --debug testJVM
It then generates a jemfile, a spinfile, and debug files
jem.bin, jem.hex and jem.out (this is testJVM.txt)
Note that path can be different, depending on where
the Javelin IDE was installed.

regards peter

Peter Verkaik
01-23-2008, 06:41 PM
A new jvm.spin file. I added descriptions for the native methods
and have put in some code. I would like some prop expert to look
at that code, especially for the pin manipulations (input/output/low/high).
A few native methods have no code yet, but these are much like
some BS2 functions I guess. Perhaps we can use that BS2 code.

regards peter

hippy
01-23-2008, 06:49 PM
Now we're cooking http://forums.parallax.com/images/smilies/roll.gif

Needed the RTL60.BPL/VCL60.BPL installing but I've now got testJVM.java compiling and linked to produce what's expected.

I've been thinking about how best to handle coding the JVM and my preference would be to write it in PASM and hand off bytecode opcodes not handled in PASM to a Spin routine, let Spin do its stuff and pass control back to PASM. That allows development in Spin with all its debugging abilities and eases porting the Spin into PASM as it progresses. I've got the framework done but there are still a few details to iron out.

One thing I found; we don't really need testVM.spin, just use



DAT
JvmBytecodeStart
FILE="textJVM.jem"




and the bytecode is automatically there for the reading ( byte[ @JvmBytecodeStart+N ] ).

Time to go and re-learn Java and get to understand the JVM specification ...

Peter Verkaik
01-23-2008, 06:52 PM
What does FILE exact do? Does it load a file into the DAT area?

Edit: I just checked it and it does. Good idea.

regards peter

Post Edited (Peter Verkaik) : 1/23/2008 11:02:00 AM GMT

Peter Verkaik
01-23-2008, 07:12 PM
Hippy,
The Javelin IDE beta always generates a jemfile when you do·Project->Link
for the application program (the one with static void main in it).
Combine that with the FILE keyword, and you don't need the commandline
tool PropDirect.
I attached the IDE beta for you.
Unzip it in your Javelin IDE installation folder and run it (javelin.exe) instead
of "Javelin Stamp IDE.exe".
After first startup, do Project->Global Options and click ok.
This ensures the registry settings are updated.

regard peter

hippy
01-23-2008, 08:02 PM
Excellent stuff Peter.

I couldn't make head nor tail of TSXcomm in the JavelinDirect sources but presume the Javalin download protocol is documented / known / can be reverse engineered, in which case ( as when I emulated the BS1 / PICAXE ) when the JVM is done, it can be one-off programmed into a Propeller and then the Javelin IDE itself can be used to develop, download and debug Java programs.

With a JVM.eeprom and a third party Propeller downloader ( or built into the Javelin IDE ) a Java programmer wouldn't need to know anything about Spin or the Prop Tool to use the propeller.

Peter Verkaik
01-23-2008, 08:28 PM
The download protocol for the javelin is not documented but can be extracted
from the TSXComm file that you mentioned. For the prop that is entirely irrelevant.
What I can do, because I maintain the IDE beta, is add an option to the Javelin IDE beta,
to select wether to download to a prop or javelin. For that I need a comprehensive
description of the prop download protocol and a way to generate the prop file that
must be downloaded. At the moment only the jemfile is generated.
Are there commandline tools (required/available) to automate that task?
It would be nice if we could program the prop directly from the IDE, especially
since the IDE has a single-step debug facility builtin. That is actually targeted
towards the sx chip SX-key debug capability, but I know what commands are sent,
and maybe we can use that for the prop also.

regards peter

jazzed
01-23-2008, 08:44 PM
@Peter, Good progress on the jvm.spin code.
Can you please post the RTL60.BPL/VCL60.BPL files or links ?
Thanks for the garbage collector carrot :) How many cogs do you think is necessary for the JVM? I have a project that uses all cogs including 1 for main spin, 1 for debug, 2 for floating point libraries, and 4 for hardware driver objects. We are resource constrained. Maybe a little cog planning is in order.
Are you able to use javadoc to create an "API manual" from the .spin file ?

Peter Verkaik
01-23-2008, 09:07 PM
The DLL's are in the attachement.
Presuming the memory requirements for the JVM + native methods is about
equal to the memory in the SX48 chip, which is 4KB, I expect 2 cogs are
needed for the jvm. But I am no PASM expert so perhaps it can be done
in 1. I do think alot of the Virtual Peripherals could share a COG. ADC, DAC PWM
and Timer are all very small routines. The Uarts are probably more difficult to
share a COG but then the native Uart routines are smaller than say FullDuplexSerial
because a lot of the Uart code is encoded in bytecodes.
The javadocs for the java classes available can be viewed in the IDE help.

regards peter

hippy
01-23-2008, 09:43 PM
@ Peter : It should be possible to generate an entire Propeller image to download using third party tools ( if written in PASM rather than Spin ), although I was thinking more along the lines of creating a complete JavelinStamp with a Propeller core which accepted downloaded .jem files. In its box the Java programmer wouldn't know if they were dealing with a real Javalin or a Propeller, they do and see exactly the same.

One advantage of a roll-your-own JVM is that there's complete control over everything, so there's no reason not to hold a 32KB bytecode image in I2C Eeprom; the ProtoBoard is handy for that. Execution would be slower but program size can be larger. The JVM could dynamically choose the best option depending on size of bytecode.

One thing I'm very pleased about; the Beta Javelin IDE and all the tools run under 98SE.

Peter Verkaik
01-23-2008, 09:59 PM
I see. Maybe we should have both options. I don't like the fact that the Prop overwrites
its entire 32KB eeprom space anyway. The javelin only writes the required bytes,
the remaining eeprom is untouched and can be used for persistent application data.
Having a 'fixed' jvm would also allow for that on the prop (read spin stamp).
But to allow userdefined native methods, like·new Virtual Peripherals, it must also
be possible to download a complete new image. VP's usually require some assembly
and that must be programmed with the prop tool.

regards peter

jazzed
01-24-2008, 03:16 AM
@Hippy having Prop behave just like Javelin would be a good start.
If one can use the JIDE debugger with Prop's JVM, it can be a big win.
Getting a VM to work on Prop is a prerequisite to any of it though :)

Exposing Prop capabilities and other enhancements would be useful later, and
may be done in java classes with a little help from the VM. One could have a
CogThread for the user programmer to get access to free cogs. Having access
to vga or tv devices is a Prop "staple" and at some point should be available.

@Peter you wrote:
"The javadocs for the java classes available can be viewed in the IDE help."
Actually I was asking about your use of javadoc/doxygen markup in .spin files
not .java files. If one surrounds the comment in double braces and adds a
function signature, the comments will show up in the prop "Document" view.

It seems that having collaborative written specifications would be useful
and can be made easy using a tool like www.writeboard.com . This may
seem less important now in the prototyping phase, but defining features,
basic decisions, and documenting results of experiments early makes it
easier to produce good engineering output. Teams especially benefit.

Phil Pilgrim (PhiPi)
01-24-2008, 04:32 AM
Peter Verkaik said...
I think garbage collection can be added without sacrificing realtime behaviour by using a seperate COG to do the garbage collection.

This seems like an excellent way to proceed! The real-time behavior may still suffer, though, unless you can do it without using locks and are able to stay ahead of the growing pile.

-Phil

jazzed
01-24-2008, 07:18 AM
Peter,
How do we get the length from the "jem.bin" file ? There must be a simple "small" solution.
According to the .out file the second field is "a" length, but a byte is of course too small to
hold the file length. Some alternatives: use your original embedding method with a length
constant or use jem.hex which results in a 50% bigger byte code file and needs to be parsed.

Aw heck. never mind. This works:
DAT
· jvmBytecodeStart FILE "jem.bin"
· jvmBytecodeEnd
PRI getJemLen : len
· len := @jvmBytecodeEnd-@jvmBytecodeStart


Post Edited (jazzed) : 1/23/2008 11:44:23 PM GMT

Peter Verkaik
01-24-2008, 07:57 AM
Here is the description of the jemfile.

· .jem File Format: (For version 0.1)

·+---------------+
·| Flag········· | Run/Debug flag.
·+---------------+
·+---------------+
·| Length······· | Length of the file in 256 byte multiples.
·+---------------+
·+---------------+
·| Version······ | Version stored as BCD major.minor version #.
·+---------------+
·+---------------+
·| NumStatic···· | Space required for static variables (measured in bytes).
·+---------------+
·| MainOffsetMSB | Offset to the code for the `main' method.
·| MainOffsetLSB |
·+---------------+
·|ObjectOffsetMSB| Offset to the java.lang.Object class for instantiating arrays.
·|ObjectOffsetLSB|
·+---------------+
·|StringOffsetMSB| Offset to the java.lang.String class for instantiating strings.
·|StringOffsetLSB|
·+---------------+
·| ThrowOffsetMSB| Offset to the java.lang.Throwable.throwVMException() method
·| ThrowOffsetLSB| for throwing exceptions.
·+---------------+
·| STOffsetMSB·· | Offset to the string table.
·| STOffsetLSB·· |
·+---------------+
·| CBOffsetMSB·· | Offset to the callback method.
·| CBOffsetLSB·· |
·+---------------+
·| OOMOffsetMSB· | Offset to the java.lang.OutOfMemoryError class for JVM errors.
·| OOMOffsetLSB· |
·+---------------+
·| StackBaseMSB· | Base of the stack in memory.
·| StackBaseLSB· |
·+---------------+
·| ArrayClassMSB | Offset to the dummy array class.
·| ArrayClassLSB |
·+---------------+
·+---------------+ First Class:
·| SuperOffsetMSB| Offset of the superclass from the start of the file.
·| SuperOffsetLSB|
·+---------------+
·| NumFields···· | Number of fields in objects of the class.
·+-+-------------+
·| NumParams···· | Number of method parameters
·+-+-------------+
·| Meth1ETabMSB· | Offset to the exception table for this method.····
·| Meth1ETabLSB· | Offsets measured from start of file.
·+---------------+
·| NumLocals···· | Number of local variables (excluding parameters)
·+---------------+
·| Flags········ | Native method flag.
·+---------------+
·| Meth1OffsetMSB| Offset for the first method of this class (and superclass)
·| Meth1OffsetLSB| Offsets measured from start of file.
·+---------------+
·|E|NumParams··· | Number of method parameters
·+---------------+
·| Meth1ETabMSB· | Offset to the exception table for this method.
·| Meth1ETabLSB· | Offsets measured from start of file.
·+---------------+
·| NumLocals···· | Number of local variables (excluding parameters)
·+---------------+
·| Flags········ | Native method flag.
·+---------------+
·| Meth2OffsetMSB| Second method
·| Meth2OffsetLSB|
·+---------------+
·| ...·········· |
·+---------------+
·+---------------+ Second Class:
·| SuperOffsetMSB| Offset of the superclass from the start of the file.
·| SuperOffsetLSB|
·+---------------+
·| NumFields···· |
·+---------------+
·|E|NumParams··· |
·+---------------+
·| NumLocals···· |
·+---------------+
·| Method1 offset|
·| ...·········· |

·| code ...····· |

·+---------------+ Method exception table.
·| NumHandlers·· |
·+---------------+
·| fromMSB······ | PC to catch from.
·| fromLSB······ |
·+---------------+
·| toMSB········ | PC to catch to.
·| toLSB········ |
·+---------------+
·| handlerMSB··· | Start of the catch handler.
·| handlerLSB··· |
·+---------------+
·| TypeMSB······ | Offset of the class to catch.
·| TypeLSB······ |
·+---------------+
·|...··········· |

·+---------------+ String offsets table.
·|Offset0MSB···· | Offset to string 0, measured from the start of the file.
·|Offset0LSB···· |
·+---------------+
·|Offset1MSB···· | Offset to string 1, measured from the start of the file.
·|Offset1LSB···· |
·+---------------+
·|...··········· |

·+---------------+ String data.
·|...··········· |

·If the high bit of the high byte of the method offset is set then the method is native. The low byte
·is then an offset into the native method dispatch table. Thus there can be only 256 native methods.


In the code itself we find
· binary[kLengthOffset] = (binaryLength/256)+1;
· if ( binary[kLengthOffset] < 20 )
··· binary[kLengthOffset] = 20;

This means
binaryLength = 256*(binary[kLengthOffset]-1) where binary[kLengthOffset] >= 20
According to the above description you need to use
binaryLength = 256*binary[kLengthOffset]
so there is some waste at the end but it ensures the heap starts at a 256byte boundary
in respect to the start address which would be 0 for the javelin but for the prop it is not 0.
The jvm must account for this offset.

regards peter

Peter Verkaik
01-24-2008, 08:37 AM
A new jvm.spin file.
I now included code for all native methods except 8bit sigmadelta ADC and 8bit DAC.
If anyone has some code for this please provide a link.

regards peter

jazzed
01-24-2008, 12:54 PM
Been working on a module for debugging with VGA ... included in the attached JvmMonDebug.spin file.
Made some small additions to your jvm.spin file ... added lines surrounded by {<jazzed>} tags, and
added an init for the pc in the run method. Created a small JvmMain.spin mainly as an entry point
and a way to specify the clock setup that you can use or toss away.

You can toss JvmMonDebug.spin too if you like :) I intend to add some methods that will make
debugging the JVM sections easier without requiring interference on the serial port.

I was thinking next to start into the jem_* case code. I hope I have more answers than questions :)
The heap.spin object will be useful here ... alas I doubt I have the lastest code to support heap.

hippy
01-25-2008, 12:21 AM
Peter Verkaik said...
Here is the description of the jemfile ... If the high bit of the high byte of the method offset is set then the method is native. The low byte is then an offset into the native method dispatch table. Thus there can be only 256 native methods


Is that right ? In the .out I'm getting it seems to be the msb of 'flag' set, high byte is $00, but the entire offset appears available for use.

I've attached my first attempt at doing the JVM in PASM, doesn't run yet, I haven't folded in the native methods nor calls down to the Spin code.

I've also created a page on the Wiki. That can be split into programming / development of JVM as we progress.

propeller.wikispaces.com/Programming+in+Java (http://propeller.wikispaces.com/Programming+in+Java)

jazzed
01-25-2008, 01:13 AM
@Hippy great work! http://forums.parallax.com/images/smilies/smile.gif

Just one suggestion: Please use "jem.bin" as the jem file so any class can be used
without modifying Prop code. This output of PropDirect is exactly the same as testJVM.jem.
I can see where one may like to use a more specific file name for JVM development to
quickly change test files, but it is likely in the end the generic reference will be necessary.

Since VGA_Text and TV_Text have mostly the same API, I was able to change just a few lines
to use my VGA display with the PropProtoboard ... OBJ tv:"VGA_Text" and CON TV_PIN = 16
Maybe that preprocessor would be useful....

BTW, I'm finding the nanovm source code to be a valuable "guide".

hippy
01-25-2008, 03:12 AM
"jem.bin" it is then ... I only have one Java source file, so it didn't worry me http://forums.parallax.com/images/smilies/smile.gif http://forums.parallax.com/images/smilies/smile.gif http://forums.parallax.com/images/smilies/smile.gif

Thanks for the NanoVM pointer. Sun's JVM Spec is probably brilliant once you've "been there, done that, started an 'I write JVMs' T-shirt printing business", but there's got to be a better way to check what "DUP2_X2" actually does with the stack etc. Nothing better than being led by example I find.

There's also TaurusVM ( solved my DUP queries in a jiffy ) and SimpleRTJ.

Peter Verkaik
01-25-2008, 03:18 AM
@Hippy,
You are right, it is bit7 of Flags that is set for a native method. The text as supplied was
directly copied from the sources (and these are thus in error).

@Jazzed,
I have also been looking at Tinyvm (no garbage collection but threads are implemented
for a single processor). I shall look into nanovm also. Perhaps we should select one
as our guide that·we can reference.

The propdirect.exe outputs fixed names for debug output: jem.bin, jem.hex and jem.out
I could change that to be <filename>.bin, <filename>.hex and <filename>.out
if that is more convenient.

regards peter

jazzed
01-25-2008, 03:40 AM
@Peter,
Whatever the "*.bin" file name is would be included in the VM code I suppose.
I'm content with "jem.bin" and it seems like extra work to go beyond that.
Doubt we have to choose one VM as a guide, the number of algorithmic solutions is not finite,
although the context does dictates requirements.

@Hippy,
I'm not sure how to integrate all this, but my since you have chosen TV for debugging PASM,
I think I can continue using VGA for .spin debugging code unless there is some conflict using
both simultaneously.

Is it possible to glue the two modules together without requiring constant diff updates?
Peter has done a great deal of work in native functions ... someone show the way.

In the jvm.spin, I had put "pc" initialization in run(), in retrospect that appears to
be a bad idea. I've moved it to init(). Also calling run(length) is probably a debug thing.
I suppose a VM should handle as many codes as it wants to run :)

The JvmMonDebug VGA output is shaping up like below so far will post more later ...

·---------------------------------
·
· VmMonDebug· pc $0000·· sp $0000
· heap $0000 use $0000 free $0000
· Frame$0000
· OpCode <opcode name>
· <operand dump>
·
· -- debug section --

· -- error section --

·---------------------------------

hippy
01-25-2008, 03:41 AM
@ Peter : jem.bin would be easier; compile <whatever>.java, alt-Tab to prop-tool, hit-F10.

The jem.bin can always be renamed in a batch file, or of course <whatever>.jem renamed the same way, so perhaps it doesn't matter ! May as well leave as it is, IMO.

@ jazzed : The age old integration problem. Got to go out now but I'll think on a solution.

Post Edited (hippy) : 1/24/2008 7:46:05 PM GMT

jazzed
01-25-2008, 06:28 AM
Added some debug features in JvmMonDebug.spin and calls to them from jvm.spin.
Added some bytecode push/pop stuff for demo purposes ... not sure if stack would
be controlled by the vm address or not ... faking it for now with the spin stack var
already in the jvm.spin file. Need to implement jem init stuff and plan to do that
unless someone else does it.

hippy
01-25-2008, 02:11 PM
Okay ... I think I'm on the way to solving the integration issues.

I've split my code into modules; AiChip_JVM_Demo.spin is what you would need to integrate your code into. It's the Spin bytecode loop as we've used it here already except that instead of getting opcodes and operands in that loop yourself, calling jvm.GetOpcodeAndOperand does that for you. It returns the opcode/operand and leaves pc pointing to what will be the next bytecode.

AiChip_JVM_JvmPasm.spin is the object which does this and it's configured so it can run standalone for debugging the PASM side of things. When called as a sub-object that is all by-passed.

I also split the jem.bin bytecode stuff into its own .spin object, AiChip_JVM_JemFile.spin

So, we should be able to pass .zip's around and drop others .spin files into our own development directory, update any version numbers and we're off. At least we're not stepping on each other's toes and only having to worry about our own files.

It's not complete yet - need to really look at how we can also split native methods out as well into their own object - but what I have so far is attached so you can get an idea of what I'm talking about.

One thing I found is that the Jem_* constants didn't have values which match up with the byte codes in the .jem / jem.bin file. They've been numbered consecutively whereas the numbers in the .jem file take account of the paging in the SX firmware.

Peter Verkaik
01-25-2008, 04:07 PM
Hippy,
I have neither TV nor VGA, just serial debug output.
So I put together a DebugSelect object which you can
set to either TV, VGA, propeller TX/RX pins (30/31) or spin stamp SOUT/SIN pins.
I defined a init method that initializes the selected debug device,
and a debugOut method that just prints a nullterminated string
to the selected debug device.
That way we can all run the code by just using debugOut.

I am going through your code (thanks for adjusting the JEM opcodes)
and I think your stack code is not quite right. The stack elements are word size,
not long size. This is because integers are 16bit here.
Boolean, byte, char, short are all extended to int internally and therefor take
1 pop/push each. The long and float (to be added later) would be double word size
and these then take 2 pop/push each.
What I understand from the JVM specs, the stackpointer is never to be manipulated
directly, except by push and pop, but that is just a recommendation I guess.
I also undertstand there are several stacks involved, and these need not be contiguous,
so stack areas can/should be allocated from the heap, as are objects.

regards peter

Peter Verkaik
01-25-2008, 07:36 PM
Understanding jem.out.
I have this simple test program:

import stamp.core.*;
public class testJVM2 {
· static ADC p = new ADC(CPU.pin0,CPU.pin1);
· static void main() {
··· int i = p.value();
··· while (true) {
··· }
· }
}

jem.out·holds the following for the main method ( I added the //*****):
; Class = `testJVM2'
; (0411) Method main /* ()V */
0411:·dw·$25·;····· invokestatic <??.<clinit>>
0412:·dw·$00·;····· Offset hi = $00· //**** offset to start of file
0413:·dw·$33·;····· Offset lo = $33
0414:·dw·$25·;····· invokestatic <??.<clinit>>
0415:·dw·$02·;····· Offset hi = $02· //**** offset to start of file
0416:·dw·$B9·;····· Offset lo = $B9
0417:·dw·$25·;····· invokestatic <??.<clinit>>
0418:·dw·$03·;····· Offset hi = $03· //**** offset to start of file
0419:·dw·$B7·;····· Offset lo = $B7
041A:·dw·$26·;··· 0 getstatic #15 <Field testJVM2.p>
041B:·dw·$00·;····· $00 //***** static offset ???
041C:·dw·$00·;····· $00
041D:·dw·$24·;··· 3 invokevirtual #21 <Method stamp/core/ADC.value>
041E:·dw·$02·;····· Object offset = -$02·· //***** class index (why the - in front??)
041F:·dw·$11·;····· $11· //***** offset to start of class
0420:·dw·$10·;··· 6 istore_0 //****** i = p.value()
0421:·dw·$43·;··· 7 goto 10
0422:·dw·$00·;····· //***** offset to $0421
0423:·dw·$03·;
0424:·dw·$43·;·· 10 goto 10· //***** while (true) ;
0425:·dw·$00·;····· //***** offset to $0424
0426:·dw·$00·;

The class ADC:
; (0060) Class = `stamp/core/ADC'
0060:·dw·$01·; Superclass offset hi = $01
0061:·dw·$D3·; Superclass offset lo = $D3
0062:·dw·6·; Number of (non-final, non-static) fields = 3
; Method = `equals'
0063:·dw·4·; Number of parameters = 2
0064:·dw·0·; Number of locals = 0
0065:·dw·$00·; Flags hi = $00
0066:·dw·$04·; Offset hi = $04
0067:·dw·$E7·; Offset lo = $E7
0068:·dw·$00·; Empty exception table hi = $00
0069:·dw·$00·; Empty exception table lo = $00
; Method = `address'
006A:·dw·2·; Number of parameters = 1
006B:·dw·0·; Number of locals = 0
006C:·dw·$00·; Flags hi = $00
006D:·dw·$04·; Offset hi = $04
006E:·dw·$F2·; Offset lo = $F2
006F:·dw·$00·; Empty exception table hi = $00
0070:·dw·$00·; Empty exception table lo = $00
; Method = `value'
0071:·dw·2·; Number of parameters = 1
0072:·dw·0·; Number of locals = 0
0073:·dw·$00·; Flags hi = $00
0074:·dw·$04·; Offset hi = $04
0075:·dw·$66·; Offset lo = $66
0076:·dw·$00·; Empty exception table hi = $00
0077:·dw·$00·; Empty exception table lo = $00
; Method = `start'
0078:·dw·2·; Number of parameters = 1
0079:·dw·0·; Number of locals = 0
007A:·dw·$00·; Flags hi = $00
007B:·dw·$04·; Offset hi = $04
007C:·dw·$7D·; Offset lo = $7D
007D:·dw·$00·; Empty exception table hi = $00
007E:·dw·$00·; Empty exception table lo = $00
; Method = `stop'
007F:·dw·2·; Number of parameters = 1
0080:·dw·0·; Number of locals = 0
0081:·dw·$00·; Flags hi = $00
0082:·dw·$04·; Offset hi = $04
0083:·dw·$CF·; Offset lo = $CF
0084:·dw·$00·; Empty exception table hi = $00
0085:·dw·$00·; Empty exception table lo = $00
; Method = `install'
0086:·dw·2·; Number of parameters = 1
0087:·dw·0·; Number of locals = 0
0088:·dw·$80·; Flags hi = $80
0089:·dw·$00·; Offset hi = $00
008A:·dw·$2C·; Offset lo = $2C
008B:·dw·$00·; Empty exception table hi = $00
008C:·dw·$00·; Empty exception table lo = $00
; Method = `<init>'
008D:·dw·6·; Number of parameters = 3
008E:·dw·0·; Number of locals = 0
008F:·dw·$00·; Flags hi = $00
0090:·dw·$04·; Offset hi = $04
0091:·dw·$D4·; Offset lo = $D4
0092:·dw·$00·; Empty exception table hi = $00
0093:·dw·$00·; Empty exception table lo = $00

When I use my interpretation after the //*****
then I get to ADC.value, by using a class index ($02) and method offset ($11).
I think this is right, more so because of the following:
with only a byte offset, a class can hold 3 + k*7 = 255 where k is the number of methods.
This yields k = 36 and I have noticed that is the number of methods above which
the IDE generates an error: too many methods in class.

regards peter



Post Edited (Peter Verkaik) : 1/25/2008 11:54:30 AM GMT

hippy
01-26-2008, 02:01 AM
Peter Verkaik said...
I am going through your code (thanks for adjusting the JEM opcodes) and I think your stack code is not quite right. The stack elements are word size,
not long size. This is because integers are 16bit here.
Boolean, byte, char, short are all extended to int internally and therefor take 1 pop/push each. The long and float (to be added later) would be double word size and these then take 2 pop/push each.


I was working on the principle that ints will become 32-bit and shorts will stay as 16-bit once PropDirect gets modified to support 32-bit ints. ILOAD/ISTORE is the operation used to load/store byte(8), char(16), short(16), boolean(32) and int(32) hence going for 32-bit as the basic size of every local stacked variable. In fact, the .jem file is okay already for byte(8), short(16)/int(16) and int(32) with the only change needed in the DW's which currently indicate how many byte(8) to allocate on the stack. I'm currently fudging that to make it work. The fact that one cannot yet write a .java to put a 32-bit constant into an int(32) I have ignored.

I prefer to bring PropDirect+JVM up to what's needed - int(32) - rather than dumb-down to what the Javelin had to have to fit its constraints - int(16).

With the fullness of time, adding float(32) plus FLOAD/FSTORE etc would perhaps make sense, but I don't really see much need to add long(64) or double(64), LLOAD/LSTORE and DLOAD/DSTORE etc. I'd have to see a compelling argument for the later to justify the code bloat it would cause.


Peter Verkaik said...
What I understand from the JVM specs, the stackpointer is never to be manipulated directly, except by push and pop, but that is just a recommendation I guess.


That's all part and parcel of the sandbox nature of 'real Java'. We should also be pushing type to the stack as well as value and checking type on every pop but as we don't have any dynamically loaded classes we can be pretty sure that argument/parameter types are compatible and ignore that issue.

One consequence is that we will not have a "Jave(TM) VM", but it will be no less 'Java' than any of the other Java(TM)-like JVM's. Naming/licensing is quite complex with respect to "Java", no doubt why it's "JavelinStamp" not "JavaStamp". Our JVM is really "Jem VM" so that's okay ( at least with respect to Sun/Java(TM) ).


Peter Verkaik said...

I also undertstand there are several stacks involved, and these need not be contiguous,
so stack areas can/should be allocated from the heap, as are objects.


I believe only one stack is needed if there's no threading and it seems simpler to start with something which uses a traditional stack going up, heap ( if any ) coming down, and we can worry about Version 2 once we have something simple working first.

But yes, with threading, allocating each stack frame from the heap does make sense and helps garbage collection.

I've assumed my roadmap as -

1) Get a JVM running, no threads, no GC, supports int(32), no objects ( 'new' ).
2) Modify PropDirect to cater for short(16), int(32).
3) Support native methods.
4) Extend native methods for Propeller specifics
5) Add object support.
6) Add float support.
7) Add threads.
8) Add GC.

6 is just code-bloat for desired capability so should be straight forward. We can take that or leave it.

7 and 8 would probably require major re-writes and additional code, GC particularly and requires knowledge/design, and I suspect we may breach the Prop Mk 1's capacity.

1-4 gives us a reasonably credible JVM, 1-5 gives us a usable JVM of no less capability than the JavelinStamp or NanoVM and its ilk.

I'm looking short-term involvement 1-3, medium-term 1-5 and likely happy to leave 6, 7 and 8 to others who want to pick it up and run with it.

Peter Verkaik
01-26-2008, 02:26 AM
Hippy,
I really think ints should be made 16bits.
Long and float will become 4bytes.
Double could be made equivalent to float, if only to allow
importing existing code that uses double without requiring us to
edit all double to float.

regards peter

hippy
01-26-2008, 05:11 AM
Not sure I, or Java programmers, would like that, the Java language defines int as 32-bit and long as 64-bit and there's no overwhelming reason on the Prop not to retain that standard, although truncating long and double to 32-bit I'd support.

Edited : That could cause major problems for the PropDirect tool, but if not I'm still in favour, otherwise I'm against on grounds of unnecessary work. Long and double are defined by Java spec to be two entries on the stack frame and the compiler will have generated DUP_* code assuming that is the case. One would have to try and find all the cases where this were so to fixup the opcodes to what they should be. That could be hard if the compiler is optimising and using those opcodes to pull other tricks.

Shorts can already be used as 16-bit so I don't see any problem for people who want to use 16-bit. Jikes and PropDirect already generate the correct bytecode for short(16) and int(32) usage and it doesn't need any change to the JVM either if it uses 32-bit as its basic type-size. Adding long(32) wouldn't need any JVM change either. With a basic type-size of 16-bit there's a lot of extra JVM code to add to support long(32), plus all the converting of 16-bit values to 32-bit and back again to use in math.

With byte(8), short(16), int(32), long(32), float(32), double(32) one would only need to add "word" as a synonym for "short" in the Jikes source for 'Java' to support the primitive types the Propeller natively supports while remaining entirely Java(TM) compatible except for long(32) and double(32).

If we only had conditional compilation we could do both :-(

Post Edited (hippy) : 1/25/2008 10:16:26 PM GMT

Peter Verkaik
01-26-2008, 06:15 AM
Since the bytecodes are generated from the javelin IDE (or will be),
the existing javelin classes should run unchanged on the prop. Many classes
that use 32bits have used two ints to form longs. Float32
for example. Besides that, leaving ints 16bits, saves alot of memory, and·all the
current javelin documentation and examples·remain valid also for the prop.
Since no code is yet written for the prop, people can just use long to use 32bits.
And I wouldn't worry about pc java compatibility (or portability)·as that really
is non-existent. I·use javelin java as an C extended with classes,
which is just a great·programming language.
However, you could define a INTEGERSIZE constant, to be 2 or 4, but remember,
boolean,char,byte,short are all promoted to int for internal computations.
Also note, that the headers in the generated bytecodes sometimes contain
bytesizes, and these were calculated for a 2byte int. To make that 4byte int,
the linker must be adjusted.

regards peter

jazzed
01-26-2008, 08:23 AM
I have to agree with Peter on supporting the existing base of users.
On the other hand, one reason I stopped bothering with Javelin was
because of it's Java "issues".

So, from a market perspective ... where money can be made ...
duplicating the existing feature set seems important. The opportunity
for a replacement and then a follow-on product appears fairly clear
judging by the amount of effort not being exercised by Parallax.

From a more computer science purist and eventually bigger market
perspectives, making the product more Java compliant would make
it more valuable. But one must also consider the competition and how
attractive the solution can be relative to the available alternatives.

Sometime back I suggested hammering out a specification.
Perhaps it's time to consider that since it appears timely?
Trying to hit a moving target can be difficult and discouraging.
Any takers ?

hippy
01-26-2008, 11:43 AM
Peter / jazzed : I've been reflecting on what we are trying to achieve and it became clear to me there are two potentially goals ...

Turning the Prop into JavelinStamp Mk II ( JVM supports existing JavelinStamp user's code base, minor changes to the toolset ) or, a Java ( as best it can be compatible to the Java spec ) targeted specifically at the Propeller.

With their two potentially target audiences ...

The existing JavelinStamp user who wants to move to the Propeller and take their code with them with as few changes as possible, and the person who wants to use the Propeller and prefers to program in Java.

I can understand the arguments in support of and against both. Ultimately, are we delivering "Javelin" or "Java" for the Propeller ?

Pragmatically the best solution would seem to be to port Javelin to the Propeller as is, no changes to int (16-bit), no long, no float, no double, no significant alterations to PropDirect. Get that done and take it from there. It gives a well defined goal and we can all debate where we go and form a final target spec while that work is going on.

jazzed
01-26-2008, 04:34 PM
Ok, Sounds like we have some concensus.
I have started a writeboard document for specification and edits.
Please see: http://123.writeboard.com/efc5805a4ca8d7ae3
The password for now is guest. I will change it later.
If you make a non-trivial change other than a cosmetic edit,
save it as the newest version.

BTW Hippy, can you provide an example of a spin method for
implementing a jemcode operator/operand that is being invoked
by the PASM code. I think I get it, but I would rather not guess
too much. Oops. I forgot about the one's you provided already.
·
The JVM init from the jemcode needs to be added; it seems
appropriate to do this in SPIN before your "start" method. No?

Thanks.

Post Edited (jazzed) : 1/26/2008 9:02:32 AM GMT

Robot Freak
01-26-2008, 07:26 PM
Don't make the same mistake as they did with the Javelin.
Yes, it works fine and I am a happy user of it, but it's expensive because it has to be manufactured separately.

When you create a JavProp (or how you would like to call it) to be compatible with the Javelin IDE, you are creating another new and expensive product.

Creating a Java compiler/VM for the propeller people can still buy the low priced Propeller kits and even program in Spin and ASM if they'd like.
Less expensive, more possibilities.

A technical advantage is that a compiler can be updated with a new VM, if bugs are found.
The Javelin VM can't be updated or extended. (as far as I know / without disassembling it)

I hope this makes sense.
With kind regards,
Robot Freak

Peter Verkaik
01-26-2008, 08:16 PM
@RobotFreak,
This is purely a software solution, no new hardware is involved.
The javelin IDE provides a mature environment for compiling
and linking programs written in the java language.
You would load the JVM into the prop with the proptool, just
as any other propeller program, like propForth or FemtoBasic.
Because the linker is public, we can add support for floats and
longs natively so you would not need Float32 for example.
First step is to have a JVM that can execute Javelin programs.
This then directly gives a large codebase for many devices.
Once the JVM is stable, we can add support for 32 I/O pins,
longs and floats, userdefined native functions or Virtual Peripherals,
threads and garbage collection.

regards peter

hippy
01-26-2008, 09:43 PM
jazzed said...
I have started a writeboard document for specification and edits.
Please see: http://123.writeboard.com/efc5805a4ca8d7ae3

The JVM init from the jemcode needs to be added; it seems appropriate to do this in SPIN before your "start" method. No?


Thanks for the whitecboard.

Yes, do everything in Spin IMO. The PASM code was firstly just to see if it could be done, and secondly to give a framework to move fairly painlessly to PASM when the time comes There's a 'design flaw' at present with what I have because it gives precedence to PASM then falls back to Spin and it should be the other way round; if it's in Spin run Spin otherwise pass over to PASM. Spin should always gets precedence unless it's decided to let PASM handle it. That way any flaw or incompleteness in PASM won't impact on the primary Spin implementation.

Peter Verkaik
01-26-2008, 10:31 PM
Attached is a .out file for some test program that uses
a·try/catch/finally block. The test program source is included,
together with an updated .jem File Format description that
matches the generated code.

regards peter

jazzed
01-27-2008, 02:05 AM
@RobotFreak,
Your opinion is very much appreciated. I hope others offer opinions also. Not every single suggestion can be commited of course.

As you suggested and Peter has confirmed. The JVM should work on any Propellor chip (as long as it's properly connected similar to the schematic in the Propeller Manual v1.01.pdf). This is a requirement of the first design.

I suppose Javelin Stamp cost "as is" would be an issue for volume production. Components for similar product would cost about $10 now without a board for mounting (packaging is the stamp value add). Spin Stamp is about half price of Javelin Stamp. Propellor Proto Boards are half price of Spin Stamp and can have VGA, mouse, keyboard, or "anything else" attached :) Of course for Propellor you need a programmer but only one per developer.

As far as IDE, etc.... somehow I got the impression that Peter has the source for this (@Peter verify?). If not open-source command line tools are available to do everything JIDE does (compiling, linking, downloading, etc...) except for debugging and even that could be arranged using Eclipse as the front-end with a little work of course. Eclipse is a much better environment IMHO for Java anyway (and it's free of course). I've done several non-trivial projects with Eclipse.

Peter Verkaik
01-27-2008, 02:58 AM
@Jazzed,
That's right, I have been given the source for the IDE and have created the IDE beta.
I made an agreement with Parallax not to publish the source so I will not, but am free
to add whatever feature I see fit. One such feature could be debugging. If you
look at the IDE you will see there is a plain download command and a debug command,
that downloads the program plus some debug code. So I can add an option to specify
wether to download/debug a genuine javelin or prop.

regards peter

Robot Freak
01-27-2008, 04:46 AM
@Peter,
That would be the most easiest for the end-user.
But to achieve that, a command-line based tool is needed to download programs to the Propeller.
As far as I've searched, there aren't any.

@jazzed,
I've also worked with in Eclipse but for me there are so many functions that I don't really need, that it makes developing code slower.
But the end-user can always make that decision on its own.

Peter Verkaik
01-27-2008, 05:23 AM
@RobotFreak,
You misunderstand. Either the Javelin IDE beta, or the PropDirect tool can
generate a jem file. This file is included with the JVM using the propeller IDE.
And from the propeller IDE you download the new program to the propeller.
At this moment you cannot download from Javelin IDE to propeller.

regards peter

Ale
01-27-2008, 05:33 AM
Would be nice if this info could be added to the propeller wiki http://forums.parallax.com/images/smilies/smile.gif

jazzed
01-27-2008, 07:21 AM
@Peter, our current method is just an intermediate step for development right?
I thought one of the end-zone goals was to have Propeller have a loader that would
behave just like Javelin that could also be used for user single-step debugging.

@Ale, This project is still in early development. Perhaps the wiki can contain a pointer.
See Hippy's wiki: http://propeller.wikispaces.com/Programming+in+Java
You can also watch the specification via RSS at:
http://123.writeboard.com/efc5805a4ca8d7ae3/feed/084e0343a0486ff05530df6c705c8bb4 (http://123.writeboard.com/efc5805a4ca8d7ae3/feed/084e0343a0486ff05530df6c705c8bb4)
http://123.writeboard.com/efc5805a4ca8d7ae3/feed/d69403e2673e611d4cbd3fad6fd1788e


Post Edited (jazzed) : 1/27/2008 7:51:18 PM GMT

Peter Verkaik
01-27-2008, 07:53 AM
@Jazzed,
That's right. It's possible to add downloader code to the JVM that lets us
download bytecodes to the prop using the javelin download protocol,
if the prop is running a JVM.
For loading the JVM itself (and userdefined native methods), we still
need the proptool and propeller compiler.

regards peter

hippy
01-28-2008, 12:33 AM
I'm not sure where anyone is with their own coding / research / testing, but I stripped my code of all PASM and rewrote entirely in Spin. With a number of caveats it is running code in 'main' calling static methods in the same and other classes and calling native methods.

I haven't included Peter's Native Method execution handlers, nor jazzed's debugging routines. I've extended the AiChip_JemFile to include Native Method numbers and Type codes.

I'm okay with the 'processing side' of the JVM but not at all clear on the data structure side so I just hacked the code to get an array from the heap for the static variables of testJVM class and I skip the <??.<clinit>> calls at the start of 'main'. I therefore don't handle object/type creation or handling nor exceptions; that's all outside my experience. For a simple class, primitive types only, no arrays, it appears to work so far. For example, this code runs okay ...




import stamp.*;
public class testJVM
{
static int iStatic;
static int incr( int a )
{
return a + 1;
}
static void main()
{
iStatic = 0;
while (true)
{
iStatic = java.lang.Math.min( incr( iStatic ), 10);
stamp.core.CPU.delay(iStatic);
}
}
}





Anyone have any good on-line links to what JVM runtime data structures are meant to look like ? How class initialisation etc is meant to work in practice ?

jazzed
01-28-2008, 02:16 AM
Do you guys use some instant messenger? Would like to talk about software design.

@Hippy, Good progress :)
I've included a version of your code with my monitor debug stuff (described below).
Can you PM an email addr to me so I can invite you to edit the writeboard spec?
The password has changed. Peter got his invitation already.

The Jazzed_JVM_MonDebug.spin allows a user to define the display type preference
and for the serial interface, there is a provision in the init to wait for a keyboard hit.
I spent some time with the code on a weight reduction plan this morning, and it's
underweight for it's height. You can set VGA debug object to TV in the file if you like.
Debug information will appear on both serial IO and monitor of your choice. Just
for purposes of sharing I have not turned on the JVM debug

I'm also trying to glue together some libraries that individual contributors can change
and import without interfering significantly with eachother's module work. I have one
for Peter's native code and started one for me. I did not attempt to make either work
yet. You can keep this idea or toss it, but work is easier integrated if we change
separate files to add features rather than one big one. A common file will still have
changes, but they should be easer to handle.

I'm finding that we are kind of "big" .... There are still some integration issues.

jazzed
01-28-2008, 02:28 AM
Jeez Hippy, you've implemented practically everything.
No complaints :)

Bye the way, the code I posted before in it's current definition requires
the user to send a character to the serial·port before anything happens.
You can remove this by taking out the "repeat while"·statement in
Jazzed_JVM_MonDebug.spin



Jazzed_JVM_MonDebug.spin ...


PUB init
{{
/**
* module init
*/
}}
'mon.start(16)
mon.start(31, 30, 0, 9600)
repeat while(mon.key == 0) ' remove this to let code start without serial input
CLS

Post Edited (jazzed) : 1/27/2008 7:04:23 PM GMT

Peter Verkaik
01-28-2008, 03:42 AM
Good work guys.
I am working on the download protocol to download jembytes to a running JVM.
Here is the protocol:

Description of Javelin download protocol

IDE toggles pin DTR of comport
Javelin resets, then transmits 0x0F,0x50 and waits for a little time for a command
IDE sends command kComDownloadOK
if Javelin is ready to receive a new program, it responses with (kComDownloadOK | 0x80)
if IDE receives response (kComDownloadOK | 0x80) then the IDE will send packets
Packets consists of 2 startbytes, 16 jembytes, checksumbyte -> total 19 bytes
first startbyte is kComProgram
second startbyte is 0x01 for first packet, 0x00 for following packets
next 16 bytes from the jemfile, advancing the filepointer 16 bytes for each packet
the checksumbyte equals (((sum of bytes 1 to 18) xor 0xFF) + 1) and 0xFF
This packet of 19 bytes is then bytestuffed which leads to a new packet
Bytestuffed means: if a byte <b> has the value 0x7D or 0x7E, it is replaced by 0x7D, (<b> xor 0x20)
This new packet is then transmitted (which can have more than 19 bytes, worst case 35 bytes)
The javelin receives the bytestream, unbytestuffing the stream until 19 bytes are received
The javelin checks the checksum (and byte 1 and byte 2)
if the checksum is ok, the 16 bytes are copied to eeprom and then the javelin responses with (kComProgram | 0x80)
if the IDE receives a reponse different from (kComProgram | 0x80) or not at all, or the last packet
has been sent, it stops downloading, otherwise the next packet is sent
IDE resets javelin by toggling pin DTR of the comport

What this means is the prop has a download state in which it keeps receiving packets
until reset by the IDE.
Complicating factor is that the IDE expects a hardware echo to be present. I have a spinstamp
and can use the SOUT/SIN/ATN pins which have the hardware echo. I believe the normal prop
TX/RX/RESET (pins 30/31/RESET) does not have this echo but the RESET is tied to the DTR pin
(as is ATN for spinstamp). On the spinstamp ATN is not tied to RESET so I use a COG to monitor
the ATN pin and when it becomes high I do reboot.
Second complicating factor is that the IDE expects to receive 0x0F, 0x50 after resetting the
javelin. When using the prop TX/RX, what does the prop output after reset? And at what
baudrate? The IDE uses 28800 baud. I can make provisions in the IDE beta (special release,
only posted here) that allows turning on/off the echo and skip any bytes received from a booting
prop that are not sent by a running JVM. That way we can send a download directly from the IDE.

I can develop the spin code to receive such a download and store received packets in a
ram array without the need for a running JVM, just the download state code. This brings up another
issue. The javelin has its entire 32KB ram available for jembytes, static variables, heap and stack.
(jvm and native methods are flashed into the SX48). On the prop there will be less ram available.
All the debug facilities in the IDE expect the total ram to be available (top ram address set to $7FFF).
For the prop I can lower that top address but it means the jembytes, static variables, heap and
stack must be in a contiguous area.·So I would like to propose to just set aside a large
DAT area.·Does that conflict with·the FILE keyword (for other testing purposes) or can we somehow
define an alias area larger than FILE size but that starts at the FILE start address?

regards peter

hippy
01-28-2008, 04:49 AM
jazzed said...
Jeez Hippy, you've implemented practically everything.
No complaints :)


It's a yes and no there. The straightforward stuff is there ( just fiddling with the stack really ) but the hard, more complicated, stuff I haven't really touched on. So it's a bit deceptive, a lot done, but the smaller amount left is actually a bigger task. I'm wading out of my depth on those bits. I was quite surprised how much does run with just the kludging I've done.

I'll download your code and then get back to you.


Peter Verkaik said...
Second complicating factor is that the IDE expects to receive 0x0F, 0x50 after resetting the javelin. When using the prop TX/RX, what does the prop output after reset? And at what baudrate?


AFAIK, nothing, on reset it waits for the PropTool to communicate with it, times out and then boots the user program, at which point the JemCode Loader can take over TX/RX, send the 0x0F,0x50 and goes to work. Might have to tweak the Javelin IDE to allow enough time for the Prop boot.


Peter Verkaik said...
I would like to propose to just set aside a large DAT area. Does that conflict with the FILE keyword (for other testing purposes) or can we somehow define an alias area larger than FILE size but that starts at the FILE start address?


I don't see a problem with that. It should be possible to just put "DAT long 0[SIZE]" after the FILE= to add padding. The JVM could then either run the preloaded jem.bin or any downloaded code which has overwritten it.

Peter Verkaik
01-28-2008, 05:08 AM
@Hippy,
A constant SIZE will not do because then the virtual top address depends
on the size of the file.
How about

DAT
· jemstart
· FILE = "jem.bin"
· jemend
· byte 0[JEMDATA - (@jemend - @jemstart)]

that would set the area to a fixed size of JEMDATA for any filesize < JEMDATA.
Is that possible?
The IDE top address for debugging would then become JEMDATA-1
JEMDATA would be set to the highest possible value (or close to it) that the prop compiler allows.

regards peter

jazzed
01-28-2008, 05:10 AM
@Peter,
Not having enough memory available for the JVM could be a deal breaker.
We'll see.

@Hippy
Hmm. I don't think the separate library approch will work because
of context .... Back to inlining :<

I've made some special TV_Text and VGA_Text that uses hub memory
where you can use the monitor code in any object where the
Jazzed_JVM_MonDebug module is included (but not initialized).
The tv stuff is not tested, but the change just moves variables
into global space, so it should work also.

Peter Verkaik
01-28-2008, 11:38 PM
@Hippy,
I found this info in the sources.

/* Stack frame format:

· +---------------+
· | Local0······· | <- JVM_FP
· | ...·········· |
· | LocalN······· |
· +---------------+
· | Method MSB··· | <- JVM_FP + numLocals
· | Method LSB··· |
· +---------------+
· | Old FP MSB··· |
· | Old FP LSB··· |
· +---------------+
· | JVM_PC MSB··· |
· | JVM_PC LSB··· |
· +---------------+
· | Stack0······· |
· | ....········· |
· +---------------+
···················· <- JVM_SP

*/

const int kMPOffset = 0;
const int kFPOffset = 2;
const int kPCOffset = 4;

#define STACK_WORD(x) (stack->Items(x+1)|(stack->Items(x)<<8))
#define UNWIND_MP STACK_WORD(fp + kMPOffset + numLocals)
#define UNWIND_FP (STACK_WORD(fp + kFPOffset + numLocals)-stackBase)
#define UNWIND_PC STACK_WORD(fp + kPCOffset + numLocals)

There are a number of commands sent to the Javelin that aid in debugging (file TSXComm.cpp):
··// Ask the SX its status.
void __fastcall TSXComm::QueryStatus(int *pc, int *activity, int *bytecode)
· ·// Ask the SX the size of its stack/heap and its program memory.
void __fastcall TSXComm::QueryConfig(int *memSize, int *progSize, int *heapBase)
· ·// Retrieve a portion of the JVM heap.
void __fastcall TSXComm::QueryHeap( int rangeStart, int rangeLength, unsigned char *data, int *hp )
··· // Download a list of breakpoints to the SX.
void __fastcall TSXComm::DownloadBreakpoints( int *bpList, int count, int stepBP )
···// Ask the SX to single step.
void __fastcall TSXComm::Step()
···// Ask the SX to run.
void __fastcall TSXComm::Run()
···// Ask the SX to stop.
void __fastcall TSXComm::Stop()

These commands are handled identical to the download command (bytestuffed packets)
so I will add these to the command handler state machine. Since there is no command
to retrieve the values for static variables, we must assume the static variables are the
first to be allocated from the heap. Since there is no garbage collection, we only need
to remember the address from which to allocate next (single word pointer).
Also note that arrays are allocated from the heap, but references are on the stack if
locally declared.

regards peter

Peter Verkaik
01-29-2008, 04:56 AM
The file memory.java has a method freeMemory():

· /**
·· * Find the number of bytes of memory SRAM.
·· *
·· * @return the number of bytes of free SRAM.
·· */
· public static int freeMemory() {
··· int stackPointer = (CPU.readRegister(JVM_STACK_POINTER+1)<<8)|CPU.readRegister(JVM_STACK_POINTER);
··· int heapPointer = (CPU.readRegister(JVM_HEAP_POINTER+1)<<8)|CPU.readRegister(JVM_HEAP_POINTER);

··· return heapPointer - stackPointer;
· }

The result is positive, and combined with the stack frame from the previous post,
that yields following memory map:

······ Memory map layout
$0000· +---------------+
······ | jemcodes····· |
······ | ...·········· |
$XXX0· +---------------+ stackbase
······ | Local0······· | <- JVM_FP
······ | ...·········· |
······ | LocalN······· |
······ +---------------+
······ | Method MSB··· | <- JVM_FP + numLocals
······ | Method LSB··· |
······ +---------------+
······ | Old FP MSB··· |
······ | Old FP LSB··· |
······ +---------------+········ stack frame
······ | JVM_PC MSB··· |
······ | JVM_PC LSB··· |
······ +---------------+
······ | Stack0······· |
······ | ....········· |
······ +---------------+
······ |·············· | <- JVM_SP
······ |···· free····· |
······ |·············· |

······ |·············· |
······ |···· free····· |
······ |·············· |
······ +---------------+
······ |·············· | <- JVM_HP
······ |·· allocated·· |
······ |·············· |
······ +---------------+
$7FFF··················· heapbase

Obviously, for the prop heapbase is the last byte from the reserved DAT area for java code
and it will be less than $7FFF. $0000 corresponds with the first byte of the reserved DAT area.

regards peter

jazzed
01-29-2008, 08:09 AM
Hi. I've made some progress with Jem_NEW, Jem_GETFIELD, Jem_PUTFIELD, and Jem_LDC ...
Hippy started Jem_LDC code. I've added some get heap, copy constant, and push to stack code;
some analysis of what else needs to be done for LDC ... I've added string handling for now to get
past failing LDC in case such as below. I'll post spin code for review later today.
String s = new String("Hello World");
System.out.println(s.toString());"



public class mytest {
static void main() {
String s = new String("Hello Java");
System.out.println(s.toString());
while (true) {
}
}
}

Post Edited (jazzed) : 1/29/2008 1:59:50 AM GMT

Peter Verkaik
01-30-2008, 01:50 AM
I am close to get the Javelin IDE working with the prop. The IDE
recognizes a prop as javelin (correct version and echo, only GotStatus is still
not working because it not quite clear what the IDE expects).
I have put all known addresses and register names in my test file.
I defined 2 areas: javaProg that holds the jembytes,statics,stack and heap.
jvmRegs that holds all the jvm and native method registers.
This reflects how the SX jvm is used.
(currently jvmRegs is 256 bytes but I think that can be reduced).

I simulate a reset by setting the variable reset from a cog that is only used
to check the ATN pin (spin stamp pin 3).
I would like the serial driver to check that pin (saves a cog) and set the reset variable,
but I have no idea how to do that, so if anyone can figure that out, please.

The serial driver is an adapted fullduplexserial that has the native methods
message() and getByte() implemented. This makes it easy to send debug messages
directly to the Javelin IDE message window. Having a spin stamp really benefits here,
as the SOUT and SIN pins do not interfere with the prop TX/RX pins for downloading
new JVM firmware.

regards peter

jazzed
01-30-2008, 03:12 AM
@Peter, Good progress on downloader.

@Hippy, I'm down in ARRAY land now.
In at least one case "newarray char", the operand for NEWARRAY is the "type".
The length comes off the stack. I'm finding the java bytecode wiki instructive.
http://en.wikipedia.org/wiki/Java_bytecode

I'll post code after I've answered more questions that are bothering me.
BTW: I've gotten quite used to your latest design and am fairly impressed.
Please don't re-architect unless absolutely necessary :)
I'm putting·what I can discern into the spec i've started.
·

jazzed
02-01-2008, 05:43 AM
Hi guys. My frustration meter has been pegged for about 1.5 days now.
Time to pass the baton to the next runner. I don't really want to hold my
breath waiting for the widely anticipated C compiler, but that is attractive
right now. I haven't spent this much time looking at·a stack in 20 years.

My frustration usually means I've misinterpreted something. I've interpreted
the JVM code so far as object reference and parameter passing on stack and
"constant table" entries as pointers on the object reference. So a "block"
diagram looks something like this:



vertical columns represent stack-wise manipulation


horizontal rows are object reference/fields storage





main ->






class init -> "constant table"
-> "function table"


-> "class field array"


... instructions with stack manipulation ...


... ldc/getfield/putfield with class fields ...


... etc ...






-> class init -> "constant table"
-> "function table"


....





... other instructions/method calls ...





... other main instructions, etc....



Thing is i've had this mostly working except for one or two stack accounting
problems. The InvokeStatic and InvokeVirtual methods are tough and tougher:)
InvokeStatic is a method call as far as I can tell, but the stack gets off by a
16bit word pointer near the beginning. As far as InvokeVirtual goes, well either
we dynamically suck in the function table (not desirable for memory reasons)
or try to keep track of it on an "as needed basis" (worse performance).

At this point, I'll leave a little thought to you with a couple of pointers to
what I believe I've resolved in line below. Maybe you will notice something
completely off base here. Beats me.



PRI doNEW | objectref, data, classAddr, superClass, numFields, type, len
{{
/**
* see case jem#Jem_NEW comment for basic operation description.
*/
}}
if jazzDebug
tv.Str( String($d,"New " ) )
tv.Hex( pc-bytecodeStart, 4 )

classAddr := Operand_BytecodeAddress

superClass := byte[classAddr+0] << 8
superClass |= byte[classAddr+1]
numFields := byte[classAddr+2] '>> jemFileCountAdjust

' allocate heap pointer for class
' get enough storage for superClass and numFields
' fields are stored in the stack ???
'
objectref := GetFromHeap(jem#T_ANY, numFields<<1+1)
GetHeapInfo(objectref, @type, @len, @data)

'save this class name
classAddr -= bytecodeStart

word[data] := classAddr
'push "this"
Push (objectref)

if jazzDebug
tv.Str(string($d,"pc "))
tv.Hex(pc-bytecodeStart, 4 )
tv.Str(string($d,"this "))
tv.Hex(objectref, 4 )
tv.Str(string(" class addr "))
tv.Hex(classAddr, 4 )
tv.Str(string(" SC "))
tv.Hex(superClass, 4 )
tv.Str(string(" F$"))
tv.Hex(numFields, 2 )
tv.Str(string(" t$"))
tv.Hex(type, 2 )
tv.Str(string(" l$"))
tv.Hex(len, 2 )

result := 0


PRI LoadConstant(constantSizeInBytes, tableIndex) | constAdr, constLen, constOff, ptr, type, len, data
constAdr := byte[ct + tableIndex << 1 + 0] << 8
constAdr |= byte[ct + tableIndex << 1 + 1]
constAdr += bytecodeStart
constLen := byte[constAdr + 8] << 8
constLen |= byte[constAdr + 9]
constOff := constAdr + 10

' string table holds all constants
ptr := GetFromHeap(jem#T_ANY, constLen+1)
GetHeapInfo(ptr, @type, @len, @data)
word[data] := constOff
PushAddr(ptr)
if jazzDebug
tv.Str(string($d,"LDC "))
tv.Dec(constantSizeInBytes)
tv.Str(string(" "))
tv.Hex(tableIndex, 4 )
tv.Str(string(" co "))
tv.Hex(constOff-bytecodeStart, 4 )
tv.Out("=")
tv.Hex(constOff, 4 )
tv.Out(" ")
result := 0


PRI doGETFIELD | objectref, data, blockAddr, index, type, len, val, xlen
{{
/**
* case jem#Jem_GETFIELD Get 16bit field from object.
* Pop object/Push value
*/
}}
index := Operand_UnsignedWord
objectref := PopAddr
GetHeapInfo(objectref, @type, @len, @data)
if index =< len
PushAddr(word[data+(index>>1)])
else
if jazzDebug
tv.out($D)
tv.out("?")
tv.dec(index)
tv.out("<")
tv.dec(len)
Crashed(string("GETFIELD index out of bounds"))

result := 0


PRI doPUTFIELD | objectref, type, len, data, value, index
{{
/**
* case jem#Jem_PUTFIELD Set 16bit field in object.
* Pop value/Pop object
*/
}}
index := Operand_UnSignedWord

value := Pop
objectref := PopAddr
GetHeapInfo(objectref, @type, @len, @data)
if index =< len
word[data+(index>>1)] := value
else
if jazzDebug
tv.out($D)
tv.out("?")
tv.dec(index)
tv.out("<")
tv.dec(len)
Crashed(string($D,"PUTFIELD index out of bounds"))

result := 0

PRI doNEWARRAY | arrayLen, arrayType
{{
/**
* case jem#Jem_NEWARRAY Create new array of operand type
' .---------------------------------------------------------------------------------------------.
' | NEWARRAY $46 |
' | Meaning: Allocate new array. |
' | Description: A new array of a specific array type, capable of holding size |
' | elements, is allocated. The result is a reference to the new object. Allocation |
' | of an array large enough to contain size items of the specific array type is |
' | attempted and all elements of the array are initialized to 0. |
' | size represents the number of elements in the new array and must be an |
' | integer. The result is stored with an internal code that indicates the type of |
' | array to allocate. Possible values for the type of array are as follows: |
' | T_BOOLEAN(4), T_chAR(5), T_FLOAT(6), T_DOUBLE(7), T_BYTE(8), T_SHORT(9), |
' | T_INT(10), and T_LONG(11). |
' | Note |
' | A NegativeArraySizeException is thrown if size is less than 0. An |
' | OutOfMemoryError is thrown if there is not enough memory to allocate the array. |
' `---------------------------------------------------------------------------------------------'
*/
}}
arrayLen := Pop
'Operand_UnsignedByte ' ***** HACK **** This is $00 so what's it mean ?
arrayType := Operand_UnsignedByte ' $00 means *ANY* arrayType

case arrayType
0: arrayType := jem#T_INT
1: arrayType := jem#T_BYTE
other: arrayType := jem#T_BYTE

Push( NewArrayRef( arrayType, arrayLen+1 ) )
result := 0


PRI doANEWARRAY | arrayLen, index
{{
/**
* case jem#Jem_NEWARRAY Create new array of operand type
' .---------------------------------------------------------------------------------------------.
' | ANEWARRAY $47 |
' | Meaning: Allocate new array of objects. |
' | Description: A new array of the indicated class type and capable of holding |
' | size elements is allocated. The result is a reference to the new object. |
' | Allocation of an array large enough to contain size elements of the given class |
' | type is attempted and all elements of the array are initialized to null. |
' | size represents the number of elements in the new array and must be an |
' | integer. byte1 and byte2 are used to construct an index into the constant pool |
' | of the current class. When the item at that index is resolved, the resulting |
' | entry must be a class. |
' | The anewarray instruction is used to create a single-dimension array. |
' | Note |
' | A NegativeArraySizeException is thrown if size is less than 0. An |
' | OutOfMemoryError is thrown if there is not enough memory to allocate the array. |
' `---------------------------------------------------------------------------------------------'
*/
}}
arrayLen := Pop
index := Operand_UnsignedWord '... the class constant pool index (for array storage ?)

Push(NewArrayRef(jem#T_ANY, arrayLen))

result := 0

Peter Verkaik
02-01-2008, 06:22 AM
Jazzed,
The stack frame should look like
/* Stack frame format:

· +---------------+
· | Local0······· | <- JVM_FP
· | ...·········· |
· | LocalN······· |
· +---------------+
· | Method MSB··· | <- JVM_FP + numLocals
· | Method LSB··· |
· +---------------+
· | Old FP MSB··· |
· | Old FP LSB··· |
· +---------------+
· | JVM_PC MSB··· |
· | JVM_PC LSB··· |
· +---------------+
· | Stack0······· |
· | ....········· |
· +---------------+
···················· <- JVM_SP

*/



I use this as jvm reference, which is more understandable than the Sun reference.
http://www.opensitesolutions.com/books/comp_books/1-57521/088-6/
Chapter 24 is a detailed description of the jvm.

regards peter

jazzed
02-01-2008, 08:35 AM
@Peter, that reference is a·slightly more verbose than the original comments. Only the sun bytecode definitions are more verbose, but as you mentioned are difficult to understand. Some things about the jem.out class are mysterious. The only "constant table" that I can find·is a string table ... maybe it was just my test class snippet ? Have you created a class that caused a numeric constant table to appear?· Somethings bother me·such as·class names and jem.bin ... i see java/lang/Object, etc in the jem.out, but there is no such "string name" that I can tell in the bytecode. One question is "how does one pull class info from the bytecode list?" in the jem bytecode file ... there are implied delimiters but can one guarantee some of the details ?

Looking around I found a very detailed yet flexible description of JVM implementation theory. It has more answers than I have questions (the A's don't match the Q's in most cases) .... It goes into great detail about possible object data designs and stack implementation. If only there was such great detail about what is expected of the "short-cut" jem JVM we're stuck with.

http://www.artima.com/insidejvm/ed2/jvm.html

@Hippy, BTW i'm eating 32 bit words now :) This 16 bit stuff is just complicating things. You have some "macros" for dealing with this problem, but it is not always clear where such need to be applied. Have you given any thought to referencing class data -vs- instance data in an object ?

Thanks.· I'm taking a break for a few days. C ya.

hippy
02-01-2008, 01:32 PM
jazzed said...
Looking around I found a very detailed yet flexible description of JVM implementation theory.

http://www.artima.com/insidejvm/ed2/jvm.html

@Hippy, BTW i'm eating 32 bit words now :) This 16 bit stuff is just complicating things. You have some "macros" for dealing with this problem, but it is not always clear where such need to be applied. Have you given any thought to referencing class data -vs- instance data in an object ?

Thanks. I'm taking a break for a few days. C ya.


Thanks for the link. I'd found that site, but the pages didn't seem to give anything useful so I missed that entirely !

I tried to abstract the 16/32 issue away but it's still hard getting one's head round what should be what and I admit to running in 32-bit mode. Get it working ( 32-bit ) then improve ( eg 16-bit ) is a reasonable approach. The biggest problem I found was trying to design/implement the small bits without understanding the Big Picture (TM). I ran up against the same wall with classes / class and instance data, it's all in a big cloud marked "huh?" http://forums.parallax.com/images/smilies/smile.gif

I think that if we knew what the JVM was, we'd be able to understand how the JEM stuff fits in with that, but looking at the JEM code doesn't reveal the JVM. I'm expecting some 10kW light bulb to suddenly come on and The Scheme of Things to be revealed in crystal clarity, but that hasn't happened yet.

You probably guessed that I'm into my break as well. Sorry I haven't given any feedback / encouragement. I'm still here, still intending to do more, but needed to step back to position myself for a new attack - - - and I was hoping you'd crack it and save me the effort http://forums.parallax.com/images/smilies/smile.gif http://forums.parallax.com/images/smilies/smile.gif

I look at it this way; we're designing a JVM, in two weeks from having taken off our diapers. It ain't going to happen. But it will all fall into place at some point. It's an up-hill struggle and I think you've done remarkably well. Take that well deserved break.

Peter Verkaik
02-01-2008, 06:23 PM
Let me give the memory layout as I think it is used in the sx jvm.
But first the way the datatypes are handled. In the java specs,
an int is 32bits, (in Jazzed's link that is defined as a machine word),
anything smaller than a wordsize gets promoted to wordsize before placing it on the stack.
There are two types, long and double, that have doubleword size.
In the sx jvm, an int has 16bits meaning wordsize is 16bits. The smaller types boolean,
byte, char, short are all promoted to wordsize. Yet unsupported types long, float and double,
will eventually be doubleword size (float is immediately promoted to double by the linker,
as is short promoted to int). So we are still dealing with wordsize and doublewordsize units.

Assuming we set aside a DAT area that represent the memory space available,
the first part are the jembytes. At entry $0012 there is a word that holds the stackbase value.
At entry $0003 there is a byte that holds the bytesize for the static variables (0 identifies 128 variables).
Each static variable has wordsize (2 bytes in our case).
Static variables are accessed by index number (after getstatic etc). We can either place the statics
at the stackbase, or at the far end of the reserved memory area (which is the end of the heap).
I prefer to place them at the stackbase. That means the stack starts at address stackbase+staticsSize.
Frames are allocated from the stack. For each method call, a new·frame is 'pushed', upon return that
frame gets 'popped'.
Objects are allocated from the heap and never garbage collected (for now). This means we can use a simple
heappointer that points to the last allocated block.·Object references are wordsize. Arrays are objects.
If you use
· int[] myArray = new int[12];
two things happen: a wordsize variable myArray is created, and a block·with size (2 +·12*2) bytes is
allocated from the heap. The first 2 bytes (=wordsize) of that block holds the length of the remaining
of the block (myArray.length)

So here is the memory layout as I see it.

········ Memory map layout
· $0000· +---------------+ @javaProg (reserved DAT area for·java program)
········ |··· header···· |
· $0014· +---------------+
········ | jemcodes····· |
········ | ...·········· |
· $XXX0· +---------------+ stackbase
········ |·············· |
········ | static vars·· |
········ |·············· |
········ +---------------+··························· ---
········ | Local0······· | <- JVM_FP·················· ^
········ | ...·········· |···························· |
········ | LocalN······· |···························· |
········ +---------------+
········ | Method MSB··· | <- JVM_FP + numLocals
········ | Method LSB··· |
········ +---------------+
········ | Old FP MSB··· |
········ | Old FP LSB··· |
········ +---------------+······················ stack frame
········ | JVM_PC MSB··· |
········ | JVM_PC LSB··· |
········ +---------------+···························· |
········ | Stack0······· |·operand stack·············· |
········ | ....········· |···························· V
········ +---------------+····························---
········ |·············· | <- JVM_SP (mailto:JVM_SP@jvmRegs)
········ |···· free····· |
········ |·············· |
········ |·············· |
········ |···· free····· |
········ |·············· |
········ +---------------+
········ |·············· | <- JVM_HP (mailto:JVM_HP@jvmRegs)
········ |·· allocated·· |
········ |·············· |
········ +---------------+
· JAVASIZE················ heapbase


@Jazzed, you are right about the constant pool only storing the strings. Static final {type}·constants are
treated as #defines and·resolved by the linker so these take no storage space. Static initializers
(eg. static int p = 3;) are done in code (<clinit>), instead of a·static variables area with preset values.

regards peter



Post Edited (Peter Verkaik) : 2/1/2008 11:09:07 AM GMT

Peter Verkaik
02-03-2008, 01:50 AM
Succesfully downloaded javelin program to prop, directly from Javelin IDE program.
The spin sources are for a spin stamp, as that has the hardware echo on its
SOUT and SIN pins. I use its ATN pin to simulate a reset. This means I can just
download the jvmJIDE to ram, then do Project->Program in Javelin IDE.
After programming, the javelin is reset and the message window comes up.
Still need to tweak it for optimum timing.

regards peter

hippy
02-03-2008, 02:55 AM
Excellent stuff Peter. It would have taken me forever to unravel the mysteries of TSXcomm.

We so far have ...

A Javelin IDE used for end-user development
Direct download from the IDE
The ability to run everything using just the PropTool for JVM debugging
A JVM which can do basic flow control, handle primitive types and call native methods
Core native methods implemented
Access to the tools needed to add / change native methods
Comms back from the JVM to the Javelin IDE
Some more advanced JVM code

That's quite an achievement in such a short time.

Is the next thing worth looking at; how the Javelin IDE does interactive debugging ? Would that be the easiest way to see what was working and what wasn't in the JVM ?

Peter Verkaik
02-03-2008, 03:26 AM
Hippy,
Attached is·the latest jvmJIDE. This one does generate a negative reply if a packet
is received corrupted. In the previous version·I always gave a positive·reply. Turned out
to be a misunderstanding of the checksum. The checksum is the negative sum
of all·leading packetbytes, so adding all packetbytes including checksumbyte
must be 0 for an errorfree packet.
I also added some democode how to display values. I use the Format object
to generate asciiz strings which are then simply displayed in the IDE message
window. Next step is to get·input from the IDE message window. That gives
us the power to do interactive debugging directly from the Javelin IDE.

regards peter

Peter Verkaik
02-04-2008, 09:09 PM
Found out there·is an error in the description of the protocol used
to send messages to the Javelin. The description states the messages
are bytestuffed using values $7E and $7F.·However, the values used
for bytestuffing are $7E and $7D, the same as for·packets.
The fact I·did not discover this before, is that it only matters if you
use characters with ascii code $7D, $7E or $7F, which I·never use.

Attached are two pictures of debug screens·for·a real javelin. These
combined with the jem.out must gives us hints on how to initialize
jvm parameters (the names are the names used in the IDE sources):

jvmPC: current program counter
jvmSP: current stack pointer
jvmFP: current frame pointer
jvmMP: current method pointer
jvmHP: current heap pointer

Further properties of interest are:
MemoryTotal: available·memory space = JAVASIZE (reserved DAT area size for java program)
MemoryCode: bytes occupied by code
MemoryStrings: bytes occupied by strings
MemoryStatic: bytes occupied by static variables
MemoryHeap: bytes allocated from heap
MemoryStack: bytes occupied by stack
MemoryFree = MemoryTotal - sum of memoryblocks

The pictures are valid for no·bytecodes executed (all variables are still uninitialized),
so this gives us info how to initialize the jvm parameters, as the outcome must
be as specified·in the status debug window,·below program source.

regards peter

jazzed
02-05-2008, 04:11 AM
Ok Guys. Got this sucker running down to InvokeVirtual. Will look at that more later.
The code posted by default uses serial io and vga for debug. Start console program
and strike any key to make it run. Most debugging is turned off now. There are two
flags debugging and jazzDebug. Var debugMsDelay is used to control execution speed
or pause for input ... if value < 0, pause for input ... CR single steps, space lets it run.

--jazzed

jazzed
02-05-2008, 08:34 AM
I've updated the writeboard design document with initialization and heap design information. API descriptions are also updated. Also I've registered for a sourceforge.net repository and waiting for approval. This can be a CVS repositiory if you guys are up for it; if you're not up for it, I can host the repository temporarily on one of my linux servers.

Peter Verkaik
02-06-2008, 12:03 AM
Some more debug info.
I captured the communication between a javelin·and the IDE,
after giving the command Project->Debug.
The details are in the pdf.
It turns out that some debug commands sent to javelin, require
that a resetflag ($7E, same as end of packet indicator) is sent
back to the IDE.

It is imperative to use the stack frame layout as described in the attached
jvmJIDE.spin file, because the source level debugger uses that layout.
This spin file, when loaded into the spin stamp, allows us to use
Project->Debug, that downloads the jembytes, then resets the javelin,
and enters debug mode.
The picture shows the succesful completion of the Project->Debug command.

Next, I will try to figure out what the Step Into and Step Over commands
of the debugger do and expect. That should give us more clues on how the
jvm parameters must be updated. If possible, I will try to singlestep bytecodes.

regards peter

CJO
02-06-2008, 02:16 AM
First of all, let me just say that you guys are gods among men.

Moving on to more fruitful topics:

1) With the existence of a TV/VGA screen with input devices, you get to where an O-O language can really shine: UI creation and manipulation. It seems to me that particularly without a GC, something like Swing is too complex, as it relies so heavily on dynamic object creation. However, something more in the Observer pattern might well be possible. Ultimately, I think that this would require some native methods, particularly to deal with keyboard/mouse position.

2) While I haven't near your understanding of Spin to help with the project, I am quite solid with O-O design, and would be happy to help with the 'System' type classes.

3) A GC and dynamic object creation would be really useful

4) "Thread/Runnable" native methods would be really cool

5) If you guys have SF cvs, etc that's great, otherwise, I have a server where I can provide svn/web hosting space (gratis, of course)

~ Christopher

jazzed
02-06-2008, 03:57 AM
Hi,

The included package will run "Hello World" on the Propeller Protoboard.
Have not tested SpinStamp since I don't have that product.
Download, connect with terminal program, hit any key.

Peter, I've added framing information; you may need to check it.
The only native method that should work +for now+ is nm_core_CPU_message.
Source used is in the box below.

--jazzed ... to be meerly a meekly mortal.



public class mytest {
static final int gBee = 0x1BEE;
static void main() {
int p1;
System.out.println("Hello World");
while (true);
}
}

Post Edited (jazzed) : 2/5/2008 8:13:18 PM GMT

Peter Verkaik
02-06-2008, 04:39 AM
I have been playing around with adding/removing static variables from my
test program and I found out the following relationship:

Edit: just discovered heapsize is calculated as 0x8000-jvmHP, instead of heapBase-jvmHP
(for the javelin heapBase = 0x7FFF and this makes the +1 which really is virtual, so no last byte)

When using Project->Debug, the used heapsize as given by the debug memory usage window,
equals static variables size + 1, no matter how·many static variables I declare.
This also means, in contrast to what I thought, that static variables are allocated
from the end of the heap, and·are not located at stackbase.

So here is the updated memory layout.

········ Memory map layout
· $0000· +---------------+ @javaProg
········ |··· header···· |
· $0014· +---------------+
········ |·· jemcodes··· |
········ |·· ...········ |
· $XXX0· +---------------+ stackbase················ ---
········ | Local0······· | <- JVM_FP················· ^
········ | ...·········· |··························· |
········ | LocalN······· |··························· |
········ +---------------+··························· |
········ | Method MSB··· | <- JVM_FP + numLocals····· |
········ | Method LSB··· |··························· |
········ +---------------+··························· |
········ | Old FP MSB··· |··························· |
········ | Old FP LSB··· |
········ +---------------+······················ stack frame
········ | JVM_PC MSB··· |···························
········ | JVM_PC LSB··· |··························· |
········ +---------------+··························· |
········ | Stack0······· | operand stack············· |
········ | ....········· |··························· V
········ +---------------+·························· ---
········ |·············· | <- JVM_SP
········ |···· free····· |
········ |·············· |

········ |·············· |
········ |···· free····· |
········ |·············· |
········ +---------------+
········ |·············· | <- JVM_HP
········ |·· allocated·· |
········ |············ · |
········ +---------------+
········ |· static vars· | size := byte[@javaProg + JVM_STATIC]·· 'size in bytes
········ |· each var···· | if size == 0
········ |··· 2 bytes··· |·· size := 256
········ +---------------+··························
· JAVASIZE················ heapbase (on javelin $7FFF)

A note on the jvmdebug_details.pdf I uploaded earlier.
On the last page (QueryHeap) the value for heap[0] is $1D.
This is the byte[@javaProg], so QueryHeap is used to retrieve
a block from the entire memory used by the java program, not just
parts of the heap.
Also note that the checksum that follows $1D (=kDebugMagic), is always 0
(and therefore mostly incorrect) and that the IDE does NOT check this checksumbyte.
I can only guess the javelin·did not have enough space left to calc the checksum
for the QueryHeap·command.

regards peter




Post Edited (Peter Verkaik) : 2/5/2008 8:58:31 PM GMT

Peter Verkaik
02-06-2008, 07:04 AM
@jazzed,

I was reading your code and I think your heap code is more (complex) than needed.
As there is no garbage collection, all we need is

PUB allocate(size):ptr
'allocate size bytes from heap
'return address of block or null
· if jvmHP - size =< jvmSP· 'jvmHP cannot go below jvmSP (see memory map)
··· return 0
· jvmHP -= size
· return jvmHP+1 'jvmHP holds address of last free byte

When an object must be stored on the heap

· ptr := allocate(objectsize)
· if ptr == 0
··· activity := kPassive 'QueryStatus command from IDE will read activity
··· exception(OUT_OF_MEMORY) 'this will display the runtime·error OUT_OF_MEMORY in the IDE status window
··· jvmHalt 'halt jvm

regards peter

jazzed
02-06-2008, 08:08 AM
@Peter,

I agree the heap code is complicated. Hippy wrote the heap code; I added wrappers to keep me from breaking the heap :). Your approach is simpler if different types are not required. In defence of the original design, saving a string as a sequence of longs/words whatever is quite wasteful, and memory is tight. However, if one uses only word-size elements the impact is not so bad. Another item is that having the type byte define in-use or free is easier than some of the other first fit heap ideas (using the pointer to next address lsb for example can work but is difficult). If you want a generic malloc, that can be added as a wrapper with little grief. For me a wrapper is the right approach for now since there is so much more left to do. Free and collect should be fairly easy to implement when the time comes.

I'll add a variant of your allocate API function to the next JVM posting. If there are other API you would like, please don't hesitate to ask. We should discuss integration ... I would like to add some of the VGA_text style functions to you jvmSerial.spin so we can use the same file. Having two serial drivers doesn't scale. Another item that is interesting is "how much can the JVM code be a separate object?" Using DAT ... variables, the serial port is easily shared by different .spin files barring reentrancy issues. The big question I have is "can you try to use the JVM demo file?" ... how would you do that? Very little is public today but that could be easily changed of course.

I have all of your native methods getting parameters now. I looked around and it seems the message function is the only one that takes a "string" pointer. ... Please verify .... Also, i've commented most of the jazzDebug stuff and the code lost weight.

@Christopher,

Your comments on implementing swing are very relevant and welcome, it's possible that you have read the living spec I keep on the writeboard feed. Swing would be impossible on Propeller version 1 ... we are tight for space already and the JVM can only today do "Hello World" http://forums.parallax.com/images/smilies/smile.gif Of course anything half serious in this realm must have garbage collection, and it is on the radar. The follow on Propeller with 256KB hub memory is a more likely candidate for AWT or Swing ... I hope that Parallax can afford a bigger memory with same cogs as now at some point; guess that depends on how much more memory could be added.

At this point, havng a thread class is not an option. I understand the desire as I've used threads in many projects. This would be reserved for the follow-on product though.

If you're interested ... there are several test cases in some of the other VM examples that would be nice to follow for functional testing. Let me know if you want to persue this. I am very aware of the often negative developer impulse regarding test, but this would be a great way for you to contribute after the JVM is a little more mature. If you like, I can send you pointers to that code.

Peter Verkaik
02-06-2008, 08:51 AM
@Jazzed,
I do not have indepth knowledge of the heap specifics, but for it to work
with the source level debugger in the IDE, there must be a contiguous block
of memory as specified by the memory map. There is a heap object in the
object exchange (written by me) that is fully selfcontained in a byte array and could·be used
when garbarge collection is implemented, because you can let it start at any address,
and blocks can be allocated and freed in any order. It should only be adapted for
descending addresses, it currently uses ascending addresses.
StringBuffers and arrays of char, byte·and boolean all have byte elements (not words)
plus 4 bytes overhead (a 2byte object reference and a 2byte size field). There is no
need to specify a type field because the linker/compiler already has done the typechecking (and throws
an error if there is a type cast error).
I see the benefits for garbage·collection when more ram·comes available, for 32KB minus
the space required for the JVM and the native methods, having garbarge collection may
in fact leave us with less space than without·it, due to the size of the garbarge
collection code.

I consider the code I am working on as the frontend, downloading jembytes and initializing
the jvm parameters·and restarting to either run the jvm or run the jvm in debug mode.
At some point we must integrate but I think the frontend, the jvm and the garbage collection
can be made independant,·with just the java memory map layout and jvm parameters shared.

There are only three more debug commands I·need to check out and get working. Then I will
compile a new IDE, probably with an option to disable the expected echo. That should be sufficient
to let us download jemfiles using the prop TX/RX pins via the usb connector. The IDE releases
the serial port if it is not downloading or debugging so it can be shared with the proptool.

regards peter

jazzed
02-06-2008, 10:28 AM
@Peter,

I respect the fact that you are a talented programmer. Please don't forget it.

Yes, I've seen your heap code and was wondering when that would come up.
Having been in this trench too long already, however, I would rather leave things as
they are for now since the basic requirements are being met until a more compelling
argument for change is made ... and/or when I have time to attend to the issue.

The front-end should not care much about the back-end implementation except that
the interface API layer be sufficiently defined. There is obviously some whitebox
character necessary in the JVM, but this should be expressed in an API.
I suggest you seriously consider an API layer now and offer suggestions.

As I understand it today the API requirements are for stack and heap inspection, some
stack manipulation, debug step/run control. You know this better than me, but I offer
the list below after looking at your jvmJIDE.spin in an effort as an amicable team player.

Please review and respond.
Cheers.

"Public JVM API"

PUB jvmStep
{{
/**
* This is a debug control command.
* Allow JVM to run one instruction (opcode/operand)
*/
}}

PUB jvmRun
{{
/**
* This is a debug control command.
* Allow JVM to run the bytecode program.
*/
}}

PUB jvmStop
{{
/**
* This is a debug control command.
* Stop the JVM from executing the next instruction and abort the current one.
*/
}}

PUB getJvmPC
{{
/**
* This is a debug status command that returns the value of the relative bytecode offset program counter.
* The absolute address of the program counter can be derived by subtracting the bytecode array base address.
* @returns value of the program counter.
*/
}}

PUB getJvmSP
{{
/**
* This is a debug status command that returns the "absolute" value of the stack pointer.
* The absolute value in this case means the SP value that the JVM keeps (not math absolute value definition).
* @returns value of the stack pointer.
*/
}}

PUB getJvmSB
{{
/**
* This is a debug status command that returns the "absolute" value of the stack base pointer.
* The absolute value in this case means the SB value that the JVM keeps (not math absolute value definition).
* This value is a representation of the JVM's internal BP or base pointer.
* @returns value of the stack base pointer.
*/
}}

PUB getJvmFP
{{
/**
* This is a debug status command that returns the "absolute" value of the Frame Pointer.
* The FP is defined as the beginning of the stack for the currently executing method.
* @returns value of the frame pointer.
*/
}}

PUB getJvmMP
{{
/**
* This is a debug status command that returns the relative bytecode offset value of the currently running
* Method's start address. This value is is the constant table method start address + the bytecode base address.
* The absolute address of the MP start can be derived by subtracting the bytecode array base address.
* @returns value of the method pointer.
*/
}}

PUB getJvmHeapStart
{{
/**
* This is a debug status command that returns the "absolute" current start position of the Heap pointer.
* @returns value of the heap pointer lowest memory position.
*/
}}

PUB getJvmHeapEnd
{{
/**
* This is a debug status command that returns the "absolute" current end position of the Heap pointer.
* @returns value of the heap pointer highest memory location.
*/
}}

Peter Verkaik
02-06-2008, 11:59 AM
@Jazzed,
That's the idea, except that all addresses must be relative to @javaProg, the DAT area
that will hold the jembytes, stack, heap and static variables.
The IDE uses 0 as the start of that area.
Also, there must be a
PUB init
in the jvm object that initialises the parameters without running the jvm.

PUB jvmStep
{{
/**
* This is a debug control command.
* Allow JVM to run until a breakpoint
*/
}}

PUB jvmSingleStepBytecode 'not sure if this is possible
{{
/**
* This is a debug control command.
* Allow JVM to run one bytecode instruction (opcode/operand)
*/
}}

Up to 10 breakpoints can be downloaded into the javelin, a breakpoint
is the address (relative to @javaProg) at which the jvm must pause,
waiting for a new command from the IDE.
So the jvm also needs access to the JIDEComm routine in the frontend,
this must therefore be placed in a seperate object so it can be included
by both jvm and frontend.

When I think of other required methods I will let you know.

regards peter

Peter Verkaik
02-07-2008, 02:03 AM
The attached zip contains 4 files:

testJVM4.java - my testfile
jem.out - the generated jembytes (135 kB)
status_stepinto.out - a detailed capture of communication between IDE debugger and javelin (1.02 MB)
status_singlestepbytecode.out - even more details, singlestepping bytecodes (5.75 MB)

I open the 3 .out files in notepad++ which makes it easy to go from one file to the other.
To see what really happens, observe the following entries:
sendSimpleCommand(3) = Step, lets javelin do next step
QueryStatus, returns jvmPC, activity, bytecode
Also of interest are QueryHeap that returns between 20 and 50 bytes
and QueryStack.

These debugfiles hold all the info we need to figure out how the bytecodes
are executed. The interesting stuff starts on line 130 in the·singlestep·file.
You can trace the program flow by comparing it with jem.out


regards peter

jazzed
02-07-2008, 12:19 PM
@Peter, those are fascinating traces. I'm a regular Notepad++ user. Nice tool.
I've coded the API we discussed plus several more. Added a "debug menu"
to the JVM main for unit testing. All the API functions work. I'm having a little
trouble running jvmInit more than once; it will cause run and continue·to fail.

Now, when the "standalone" jvm boots, you can hit enter to see the debug menu
incase it scrolled by before you got connected. The "menu" describes commands.
I believe you have the public API's in this package necessary to start using it
at your pleasure from the GUI. They are in the doxygen marked ____ PUB ....

I'm including the JavaPropDesign and the Doxygen API specs in this post.

Guess I'll do more test and debug now.

Enjoy.

Peter Verkaik
02-07-2008, 02:16 PM
@Jazzed,
I have also reorganized my code. I now have all reusable objects
that each deal with a very specific part.

jvmMain - top object, monitors reset and does initialization
and allows easy adding of userdefined native functions

jvmData - declares the shared data, using API as you suggested

jvmComm - communication with the IDE via the 'programming' port

jvmSerial - serial driver for the 'programming' port

jvmNative - the default native functions

jvmEngine - the bytecode interpreter


I have declared in jvmMain (but currently commented out):
OBJ
· jvm: "jvmEngine"

When I include that object the compiler throws an error
and I do not understand why, because that object only includes
objects that are already included.
Can you see what is wrong (or is this a compiler bug)?

regards peter

jazzed
02-07-2008, 11:50 PM
Yes, I think you've hit a compiler bug/limit. I've seen other issues in having too many
layers/modules also, so i've generally tried to avoid too much "organizational engineering".

Take the files/structure below. Without including bigtest, the "data" in bigdata can be up to
$7700 or 30464 bytes. Including bigtest, the most "data" can be is $4fd4 or 20436 bytes.
If I include bigtest in test.spin, but leave out bigdata, the "data" can be up to $7700 bytes.
So, the problem appears to be a number of layers issue where bigdata is included, rather
than the number of times it's included issue.

CON
{
test.spin
}

OBJ
big: "bigdata"
inc: "include"
tst: "bigtest"

PUB main
inc.include

CON
{
include.spin
}

OBJ
big: "bigdata"

PUB include
big.get

CON
{
bigtest.spin
}

OBJ
big: "bigdata"
inc: "include"

PUB main
inc.include

CON
{
bigdata.spin
}

DAT
data byte 0 [$5000]

PUB get
return data

Peter Verkaik
02-08-2008, 02:10 AM
I found a reasonable workaround by putting the large array into
its own object file that is only included by the top object file.
Other objects that must reference the array get the array properties
via their init routine.

@Jazzed,
I added an error object (jvmError) that has all the·jvm errors that are defined
by the IDE. These are runtime errors that can occur, either when the jvm just
runs or runs with·the source level debugger active.

I understand you like to use VGA for your jvm debugging (and this is seperate
from the jvm running with the IDE source level debugger).
I think it is possible to only include the VGA object in the top object file,
by extending my main loop.

· repeat 'keep running
··· jd.init(jprog.getJavaProgram,jprog#JAVASIZE)· 'initialize jvm registers and pass javaProg properties
··· if comm.isReset
····· comm.doReset
····· comm.clearReset
····· repeat
······· c := comm.doDebug
····· until c == -1
··· else
····· 'mainloop
····· repeat while NOT comm.isReset
······· if jd.debugger
········· c := comm.doDebug 'check for debug commands
······· c := doBytecode···· 'execute next bytecode
······· case c
········· < 0: jvmDebugPrint(c) 'print errormessage for jvm debugging
········· 0..47: nf.doNative(c)
········· 'add userdefined native functions here

If we allow doBytecode to return a negative address,
the error messages can be generated from the mainloop.·The positive address
would be an array of parameters used by a generic error print routine,
which only needs to be included in the top object file.
I would include a serial object, where you would include the VGA object.

regards peter

jazzed
02-08-2008, 03:39 AM
Glad you found a workaround Peter. I've been using a serial object that also prints to VGA.
At this point, having VGA is not buying much. My original interest in VGA was to have a
display of JVM internal register, stack, heap, and error activity while the jvm runs. I may
implement that in the background in the near future.

At this point we should merge on a serial strategy. It would be reasonable to have the
small subset of TV/VGA API functions in the serial driver, i.e. Out, Str, Hex, Dec, & Bin.
There are other API's I'm using which would be fairly easy to add. I propose the jvmSerial
should have some added ... serial variants of those listed are in my Jazzed_SIO_Text file.
I'll get to merging this stuff later this evening. I have my real job to do today :)

I'm a little uncertain of your current approach. The JVM I've presented has an equivalent
of your "doBytecode" call. The JVM also contains a working set of your native code with
parameter passing ... if we could abstract the main native interface a little more, it could be
separated from the JVM file.

A lot of work has been done that fits mostly with what your doBytecode while loop is doing.
The biggest hole in the JVM at this point is lack of exception handling ... a WIP as they say.

By the way, can you please zip me a binary of the JIDE so I can help with integration?
You could do this via private message if you like.
TIA

Peter Verkaik
02-08-2008, 05:40 AM
Jazzed,

What I did was creating objects for dedicated parts, rather than having
most in one jvm file. That framework is complete and works. All that my code
is lacking is a running jvm. That's where your code comes in. I only
created a doBytecode in the top object file to make it compile.
I will be calling jvm.doBytecode which·does a single step and then
returns a value. This returning value makes it possible to call a native
function from the mainloop. The big advantage is that one·can add
userdefined native functions, preferably located in their own object,
much like jvmNative, by including a different object in jvmMain.
To create a new 'jvm firmware' it is only necessary to create a new jvmMain,
without the need to change any of the other objects.
Actually, now that the javaProg array is in its own object, that also makes
it easier to define that area using FILE. You only need to include the new
jvmJavaProg in the jvmMain file. No other objects need changing.

Regarding the jvmSerial, this is a very basic driver and still has some code in it
that must be removed, like flush and stop methods because that is not needed.
There is no point in adding format methods to that driver as they cannot be used
for the IDE communication. The native Uart receive and Uart transmit·are different
from the IDE serial driver in that these must·maintain buffers using VP registers.
These drivers also do not use formatting methods. All formatting is done using
java code.

I understand you do want to format your debugging messages while debugging the jvm code.
However, this must be regarded as temporary code that will not be included once we are
convinced the jvm is running properly. That's why I suggested the negative address
value because that allows to print debugmessages from the mainloop. It means
the jvm code itself has no knowledge to where these messages will be printed.
So each can have its own jvmMain, with the required driver. This jvmMain·needs little
to no change once created for the display device you want.

I hope my·explanation is understood.·I believe this setup allows us to have different
functional·JVM's by only changing jvmMain and/or jvmJavaProg.

regards peter



·

jazzed
02-08-2008, 06:57 AM
Ok Peter. Yes, I understand every word. I think integrating the JVM using your approach
is partly doable. I look forward to the time when I can use the JIDE.

I too would prefer to see the native code in a separate module, and as I said above
it is possible with a little more abstraction (a closer reading would have revealed this).
There are some challenges with native, but challenges always come up. The problem is,
a method call takes more than just using a return code from a bytecode handler function.

The native case handler needs access to the JVM stack for parameters and return codes.
A client of a well encapsulated design should never directly access the design's internals.

You are aware of this of course. Looking at the some of the requirements though we are
violating encapsulation in a big way by exposing the stack. Native functions should be
like any other API, and not expose internals of "the box" to outside "writing". As such,
I recommend having the native methods in a separate file, but the case handler should
remain in the JVM core unless a separate stack for passing parameters can be created.

On the serial stuff, I'll add a "shim layer" in spin for what I need; this will "cost" more
than just putting the code in the driver, but apparently I'll have no choice. The only
"formatting" is converting a number into its text string equivalent. I have no intention
of producing any serial io output while under control of jvmMain. I expect several items
will be commented and changed in the JVM. I'll be moving the debugger menu code
(done primarily for unit test) to another module as well.

Later....

Peter Verkaik
02-08-2008, 02:39 PM
Jazzed,
I shall give priority to the IDE so it can be used without a hardware echo present. I considered
several options how to do that, but only one is appealing: changing the firmware revision number.
For a true javelin (and spin stamp when downloading using SOUT/SIN pins) this number is $50
(eg. a capital P), for the propeller board and the spin stamp, both downloading using the
propeller TX/RX pins, I have·selected the value $70 (small print p).·When I have this
working I shall post the new IDE·in this thread.

regards peter

Peter Verkaik
02-08-2008, 10:16 PM
I got the IDE to recognize different devices (javelin, spin stamp, propeller),
except that the propeller device is not responding at the moment.
I also managed to retrieve the memory available on the device, as is
shown in the attached picture.

For the spin stamp I simulate a reset. A reset is performed by toggling the
com port DTR pin. For the propeller, using the TX/RX pins via the propclip or propplug,
the DTR is directly connected to the PROP's reset pin.
Question is: can I run a spin program that downloads some bytes into ram,
then toggles DTR without actually resetting the propeller.
If not, I must download to spin program to eeprom, which I rather do not during
development.

Any thoughts on this?

regards peter···

Post Edited (Peter Verkaik) : 2/8/2008 11:49:14 PM GMT

jazzed
02-09-2008, 07:03 AM
Good work Peter.

There are some settings for the PropPlug device ... tried to disable DTR toggling. Nothing.

However, I'm using VBTerm from VisualBasic and there is a DTREnable flag there, and
if I disable that, I don't get a reset. It's part of the MSCOMM control. Maybe that helps.

Peter Verkaik
02-09-2008, 07:46 AM
Jazzed,
Attached is a new IDE. Unzip it in the javelin ide folder. Use the javelin.exe to start the
IDE (do not use the Javelin Stamp IDE.exe)
Also attached are my updated jvm files. This has the correct jvm initialisation
for any given javaProg size.

In jvmMain, select commPort = 1 and select the propeller clock settings.
Then download it to the propeller eeprom.
If you now do Project->Identify in the IDE, it should detect the propeller (version $78)
with memory size 16384, no loopback, no echo, got status
Open testJVM4.java (extracted from javelin.zip) and do Project->Program
The download should complete without error.

The download is only to ram, then the prop is reset, after which the jembytes
are of course lost.

I need an I2C driver that·allows page writes for 16byte blocks.
With that driver I can download the jembytes into eeprom
so that after a reset the javaProg is automatically loaded with the stored jembytes.

Can you point me to or provide an assembly driver for I2C?

Let me know if you have any trouble with the above tests.

regards peter

Mike Green
02-09-2008, 07:52 AM
Peter,
The assembly I2C driver used in FemtoBasic does paged writes and block reads. Have a look at sdspiFemto.spin
in the FemtoBasic archive from the Object Exchange. It also includes low level (block read/write) SD card routines.

jazzed
02-09-2008, 08:11 AM
Thanks for posting the zips Peter.

I'll hack my protoboard hardware to temporarily remove DTR control and give it a try.
Since you have the JIDE source, I assumed you would have access to the serial control.

I2C is well documented and I have several examples. If I can't find an existing driver,
I'll put something together in spin. I'll hack an assembly version later ....
@Mike, thanks a bunch for the pointer.

Asking Parallax to provide an option to disable DTR flopping in their prop-plug driver is
not unreasonable, but it will most likely take them a while to do it :). The hardest part
of asking for any feature is correctly identifying and clearly communicating the requirement.

Peter Verkaik
02-09-2008, 08:28 AM
Thanks Mike. It is a bit too complex for me to extract the code I need.
I need a minimal driver for reading and writing bytes to the first 32KB.
Blocks are always 16 bytes and are always on 16byte boundaries.
Byte read/write is for native functions, the block write is only
for the downloader part.

Jazzed, you can have the propeller tool·open and download
a new spin file anytime, because the IDE disconnects from the
serial port after downloading. The only·time the IDE keeps
the port occupied is when a debugsession is in progress.
Command Debug->Exit debugger will release the port so
it can be used by the propeller tool again.

regards peter

Mike Cook
02-09-2008, 08:35 AM
Maybe this will help............

deSilva posted a small I2C driver coded in *.spin

http://forums.parallax.com/showthread.php?p=703283

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike (http://www.allsurplus.net/)

Peter Verkaik
02-09-2008, 05:43 PM
Jazzed,
I found the Propeller Eeprom.spin object and included it.
Just unzip the attached jvm.zip

With this new version downloaded to eeprom,
you can now use Project->Debug from the IDE
and the source level debugger comes up.

I am investigating if I can send·new commands, to
either download jembytes to ram or eeprom, and also to·simulate a reset
without using the DTR line when downloading using the prop TX/RX lines.

regards peter

Peter Verkaik
02-10-2008, 03:11 AM
Jazzed,
I added 3 commands to the IDE (under Project menu):
download to RAM
program to RAM
debug to RAM
In case the device is a true javelin, these commands execute as
download
program
debug
For the spin stamp (using SOUT/SIN) and propeller (using TX/RX)
I added command kComDownloadRAmOK that saves wether the
received jembytes must only be·copied to ram.

So now you can download new spin code to ram, then using the IDE
to download new jembytes to ram also. This prevents wearing out
the eeprom.

Resetting is simulated by sending command kComReset from the IDE.
If there is no valid reset response from the device, the IDE tries
to reset the device by toggling the DTR. This ensures the device
is reset,·wether that is a javelin or a propeller/spinstamp.


regards peter

deSilva
02-10-2008, 03:20 AM
Peter Verkaik said...
I need an I2C driver that allows page writes for 16byte blocks.

Sorry I delayed the posting of my drivers so long. I thought no one would need them seriously ... But Mike's stuff will certainly work fine...

Peter Verkaik
02-10-2008, 03:25 AM
I used the "Propeller Eeprom.spin object" and that works fine.
I fixed the bug you mentioned in another thread (writing to end of page
even if end address is < end of page).
I attached the bugfixed version.

regards peter

Peter Verkaik
02-10-2008, 08:38 AM
Jazzed,
I added a debug command to the IDE so you can send debugmessages
directly to the IDE status window, so these messages do not interfere
with normat java program output that goes to the IDE message window.
See picture how it looks. This means all debugging can be done from
the IDE, no need for either a TV/VGA or extra serial driver.
I minimalized my Format object to help in formatting debugmessages.
The example message is generated by
····· fmt.sprintf(@buf,string("[JVM] debugging started: pc = $%04x"),1024)
····· comm.status(@buf)

regards peter

jazzed
02-10-2008, 08:46 AM
Good Peter, I'm sure i'll find some use for that. I have a big piece of integration done.
I'll update more tonight.

jazzed
02-10-2008, 03:17 PM
Well, it's been a long day. I've made some progress, but not as much as I would like.
I have jvmEngine plugged in, and it seems to run code, but it needs more work.
The command and control GUI features need gluing together, and a better run abort
mechanism than I've considered needs to be in place (if i cog the jvm, it works ...
exactly once :) I'll post a zip package tomorrow morning if I can find a good stopping
point quickly. I have a work deadline, and that's my agenda for tomorrow.

Peter Verkaik
02-11-2008, 05:14 AM
Jazzed,
Now that the IDE is adapted, I focussed on the debug mechanism to find out
how it exactly works.·I shall try to explain it so that will become clear.

As far as the IDE concerns, the jvm is in one of 4 states, the state is held in parameter
activity (in file jvmData). This means the main entry point (actually the only entry point)
in the jvm is the public method doBytecode.

PUB doBytecode: value | state,c
{{ Execute a bytecode }}
· state := jd.getActivity
· case state
··· jd#kRun··· : 'JVM running
················ c := doStep
················ if jd.mustNotifyStepDone
·················· comm.notifyStepDone
················ return c
··· jd#kBreak· : 'JVM reached breakpoint
················ 'wait for IDE to send debug command (run/step/stop)
················ return -32768
··· jd#kPassive: 'JVM was running but has stopped (exception,stopped,end)
················ return -32768
··· jd#kJog··· : 'appears not to be used
················ 'so change state to kPassive
················ jd.setActivity(jd#kPassive)
················ return -32768
···
· return -32768

·········
PRI doStep: value
{{ perform a step }}


The state is set·from method doDebug·in file jvmComm.·The initial state is·set in method
init in file jvmData, to either kPassive (java program downloaded using Project->Debug)
or kRun (java program downloaded using Project->Program).
When the initial state is kPassive, meaning the source level debugger comes up, states
are changed by issueing debugger commands run, stop, step into, and step over.
When the initial state is kRun, the state will only change·when an exception occurs
that is not handled by an exception handler.
This change can only be to state kPassive or kBreak (when a breakpoint is reached).

If you remember I·used to include the file jvmError because I thought the jvm would
throw these errors. That is not so. The jvm has a very specific way to deal with
exceptions and 3 other events.

1) When the java program ends, the jvm· must call method end in file jvmComm.
The state will change to kPassive.

2) When the jvm reaches a breakpoint, the jvm must call method breakpoint in file jvmComm.
The state will change to kBreak.

3) When the jvm detects an unimplemented/unsupported jembyte, the jvm must call
method errOpcode in file jvmComm. The method errOpcode takes one arguments:
the unimplemented/unsupported jembyte.
The state will change to kPassive.

4) When an unhandled exception occurs, the jvm must call method errException in file
jvmComm.·The method errException takes two arguments:
the class offset and the program counter value.
The state will change to kPassive.

The IDE, when the device is connected, will receive these 4 specific·messages
and, if·necessary,·retrieves the filename, classname and line number from its internal copy
of the running java program and displays appropiate messages in the IDE status window.

The first 2 events are not errors, but the IDE uses their notification for follow up actions,
like retrieving values from the heap, doing another step·etc. Note that when 'step over' is
performed, the IDE sends the same commands as when doing 'step into', with the difference
that when a call is to be performed (any of the four invoke variants), the IDE sets a breakpoint
at the next possible line, and then lets the jvm run.

It is mandatory that any address or reference·stored in a static variable or instance variable,
is relative to @javaProg, the DAT area that holds the entire java program + variables.
The IDE source level debugger expects this and uses these values to retrieve heap blocks.

Finally, a word on the native methods. You said these should not manipulate the jvm stack.
To keep things simple I propose to look upon native methods as extended bytecodes.
Like the IADD that pops two arguments and pushes one result, a native method that takes
N arguments, must pop N arguments and push one result (or no result if the method returns void,
however I am not sure about this. It could be the jvm then simple discards the result).
For this reason I·propose to put the stack manipulation methods in their own file, jvmStack,
and while we are at it, lets also put the heap manipulation methods in their own file, jvmHeap.

I attached my·updated jvm files that now fully support the IDE debugging mechanism.
You will notice in jvmMain that I removed the timeout in doDebug when running the
mainloop. Only after a reset there is a timeout used because the device must wait
for IDE commands anyway.

regards peter

jazzed
02-11-2008, 06:15 PM
Hi Peter,

You can see from the picture that JIDE can run "Hello World" ... there's tons more work to do. I believe you are positioned best·to get the IDE stuff going. The·API's we talked about are still there, so it should be easier.

You will note that I moved the jvmNative object down from jvmMain to jvmEngine. You should also note that I added a client-push owner-pop mechanism to jvmNative. I also had to add a push parameter count·at the JVM core for this to work. Currently, the JVM core jvmRun is empty as I wanted to be able to load two separate jvmNatives, so don't use that API please. You will note the queue version of the breakpoint manager is moved out of the JVM core in favor of the simpler set index value, get index methods. The isBreakpoint function has a skip once·variable that I use; hope it doesn't get in the way.

I find that·code is tight even with cutting down the·JavaProg array to 12KB. I'll look around for places to trim. I removed Format.spin temporarily. After we are further in, I'll get rid of the Jazzed_SIO_Text.spin. I'll take out the VGA stuff last.

Enclosed are two packages built from mostly the same files. You will have to change the _clkmode parameters, etc... for SpinStamp to run correctly of course ... by default they are set for Prop Protoboard.

BTW, your IDE behaviour explanation was very helpful. I'll add it to the·design spec.

Later ... Jazzed

Peter Verkaik
02-11-2008, 06:39 PM
I just ran the Jazzed_jvmMain_JIDE package.
It does run on the spinstamp (I use commPort = 1). I don't get Error IDE-0015 (stack trace is corrupt)
so I assume you did two attempts without restarting the IDE.
I noticed the cursor stays after Hello world, it should have moved
to the start of line 2. System.out.println(s) does first a System.out.print(s)
followed by a System.out.print("\n").

I will study your code now in detail and maybe I'll find out
what happened to the newline.

Edit: I just did Project->Debug to RAM (earlier I did Project->Program to RAM)
and now I do get the Error IDE-0015. This is probably because the stack behaviour
as done in the jvm is not what the debugger expects. So I will take a very close look
on how the stack is manipulated.

regards peter


Post Edited (Peter Verkaik) : 2/11/2008 11:02:15 AM GMT

Peter Verkaik
02-11-2008, 09:53 PM
Jazzed,
I am struggling through the jvm code (Jazzed_JVM_Engine_009) and it is ALOT.
I did find out why the debugger throws the stack trace error. The jvm uses a local
set of jvm parameters, rather than the set defined in jvmData. When the debugger
queries the jvm, items from the jvmData set are returned to the debugger.

Rather than editing the current jvm source, I think we should rebuild the engine,
taking the current jvm as guideline, from bottom up, starting with the code for the jemcodes.
We can put logical groups of jemcodes in their own file:
stack related jemcodes in jvmStack
heap related jemcodes in jvmHeap
call related jemcodes in jvmInvoke
etc.
The code in these files will use the API's defined in jvmData.

What about the rebuilding of class info in local tables (method LoadClassInfo and related methods) ?
These require quite a bit of storage and codespace. On the javelin this kind of storage is definitely
not allocated from the 32KB ram, and I·do not see how they could exist inside the SX48.
The SX48 has 15 banks of 16 bytes, 7 banks are fully assigned·to virtual peripherals. Leaving
just 128 bytes for jvm parameters. So there must be a cleverer way of retrieving class/method info.

I will start creating files for the jembytecodes.

regards peter

Peter Verkaik
02-11-2008, 11:37 PM
Jazzed,
I have grouped the java bytecodes and suggested·filenames.

If you find this OK or perhaps a slightly different grouping,
let me know.

regards peter

Post Edited (Peter Verkaik) : 2/11/2008 3:52:27 PM GMT

jazzed
02-12-2008, 12:54 AM
Yes, the registers are not correctly hooked up. I saved that for you to do :)
As I said ... you are better positioned to do this.

The newline problem started upon moving the native code out of the JVM core;
I looked at it briefly, but at 2AM local time some things are less important.

Hippy's heap code and my wrappers seem to be too big. If you rewite your
heap to grow down, I'll try using that.

Yes, the LoadClassInfo stuff can be zapped. The ShowHeap and ShowStack
code can be moved out to the client. Doing this and removing some debug
code saves about 1600 bytes.

InitConstantTable or some variant must stay; LDC/GetField/PutField all use
object references that must be created.

Putting body of doJazzedLib called methods into the "big case" will save a
tiny fragment of code space but make·JVM even harder to understand.

As far as the SX48 goes, I bet that code is impossible to understand much
less maintain :) Often other's code appears ugly to us even though the
author thinks it's their best work. You should see the IOS sources :)

I've learned there is no point in "inventing a huge headache" especially if
that's what pays the bills, because at some point you lose all interest in it
and either sell it to the next "bigger fool" or let it die.

Regarding javaBytecodes.spin ... each method costs 2 bytes minimum.
Are you sure you want to add 400 bytes ?

I'm including a chopped down JVM here. A line in jvmEngine.spin needs
to be removed for compile. By the way, to make the code I posted
previously work, I had to cut the JavaProg array to 8K not 12K :<

Later....

Peter Verkaik
02-12-2008, 01:26 AM
Jazzed,

I did the jvmStack. I could not find any reference how stackwords are stored, either
big endian or little endian, so I used little endian. It should make no difference as long
as we stick to whatever we decide. On the other hand, I noticed the stack frame stores references
using big endian.·So if you think we should use big endian all the way let me know.
Returned values and arguments are of course always little endian (LSB in byte0).

To support both litte endian and big endian I added 4 API's to jvmData.
PUB writeJavaIntBE(address,value)
PUB readJavaIntBE(address):value
PUB writeJavaIntLE(address,value)
PUB readJavaIntLE(address):value

I have no intention to make subroutines for all java bytecodes. We only need the jem bytecodes.
It was just to show the grouping.

regards peter

jazzed
02-12-2008, 02:05 AM
Peter said...
I have no intention to make subroutines for all java bytecodes.
We only need the jem bytecodes. It was just to show the grouping.
But you·DO want methods for each jemcode apparently. That's fine if you
don't mind the incremental growth. Organizationally having different
modules is best, but memory and performance are usually adversely
affected. It's a trade off. I'll pick a section and do it later.


Peter said...
... I could not find any reference how stackwords are stored, either
big endian or little endian, so I used little endian. ...
... I noticed the stack frame stores references using big endian.
Didn't realize the JIDE was using big endian .... Prop is obviously little endian
from the dumps i've seen. The $7FFF below gives it away. Using little endian for
JVM core is best for performance of course. JIDE can use big endian wrappers.


ShowObject type $7FFF this $0063 Super $0118 Fields $7DC0 0063 000C 7D9E
JVM> p ADDR $> 7d9e
7D9E: 08.00.0C.00.48.65.6C.6C.6F.20.57.6F.72.6C.64.00 ž...Hello World.
7DAE: FF.7F.02.00.00.00.FF.7F.02.00.00.00.FF.7F.02.00 ....ÿ....ÿ...
7DBE: 00.00.FF.7F.06.00.63.00.0C.00.9E.7D.FF.7F.06.00 .ÿ..c...ž}ÿ...
Back to coding that pays cash for now http://forums.parallax.com/images/smilies/rolleyes.gif
--Jazzed

Peter Verkaik
02-12-2008, 02:10 AM
I just checked the IDE sources. Any stack or heap access that assembles
values (because we cannot assume word alignment) uses big endian.
So I made the wrong choice (naturally).·I updated jvmStack to
use big endian.

regards peter

Peter Verkaik
02-12-2008, 03:00 AM
Here are the logic functions.
Next I will do jvmConvert.

regards peter

Peter Verkaik
02-12-2008, 01:09 PM
Here is jvmConvert.
Next I will do jvmConst, jvmLoad and jvmStore

regards peter

jazzed
02-12-2008, 01:59 PM
Printing problem solved. There was a small bug in Hippy's heap implementation.
On a 16 bit system with the given implementation one wants all heap pointers
to be aligned on even boundaries. Code was there, it was just off by a line :)

I'm taking the rest of the night off :) Looks like the rest that you've not planned
to do other than jvmMath will need a heap ... unless they are broken up. I suggest
that heap related bytecodes such as follows be moved to a separate file:

PUB jb_newarray
PUB jb_anewarray
PUB jb_multianewarray
PUB jb_arraylength
PUB jb_invokevirtual
PUB jb_invokevirtual
PUB jb_invokenonvirtual
PUB jb_invokestatic· ... not for heap, just grouping
PUB jb_invokeinterface

PUB jb_putfield
PUB jb_getfield
PUB jb_putstatic ... not for heap, just grouping
PUB jb_getstatic
PUB jb_new
PUB jb_instanceof
PUB jb_checkcast ... not sure about this one

PUB jb_ldc1 ... need to build an object based constant table
PUB jb_ldc2
PUB jb_ldc2w

Later ....


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--jazzed ....

http://en.wikipedia.org/wiki/Silicon_Valley

hippy
02-12-2008, 06:56 PM
jazzed said...
Printing problem solved. There was a small bug in Hippy's heap implementation. On a 16 bit system with the given implementation one wants all heap pointers to be aligned on even boundaries. Code was there, it was just off by a line :)


Apologies for that and the debugging caused. An opportune time though to say I'm still here and following the work you're both doing. Well done, it's moving along quickly. As another hand stirring the soup is going to complicate matters further I'm happy to lurk in the shadows until everything is more stabilised and becomes more unified.

Peter Verkaik
02-13-2008, 02:18 AM
It may be that Hippy's code required to be word aligned (possibly because word[...] was used),
but we should not rely on that. The reason is that boolean/byte/char arrays are allocated from the heap.
For example·char[] p = new char[13] requires 13 bytes + 4 bytes overhead.
As far as I know that size is not incremented to the nearest even number of bytes.

@Jazzed,
You mentioned "build an object based constant table", however I do not think that
is necessary. The only constant pool is the String index table. Scalar constant values
are loaded into variables using code, not a constant pool.
For example:
· static char[] p = new char[]{'a','b','c','d','e'};
will create a new char array in the heap, and then a loop is used·to fill the array.
That is even so when declared final.


I attached a new javelin ide. I added seperator lines like
[---------- Step Into ----------]
to the status window. This aids in locating what messages were sent
since the last action when using the source level debugger.

regards peter

jazzed
02-13-2008, 02:33 AM
@Hippy,
Fortunately it was just a little puzzle requiring little time. I figured you were still lurking here :)

Have you ever considered what it might take for opensouce jikes to create propeller bytecode?
That would be a good research canditate for JavaPropII.

@Peter,
Please consider function of LDC, GETFIELD, and PUTFIELD. I could have mis-understood them.
Perhaps I'll experiment with other implementations today.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--jazzed·... about·living in ·http://en.wikipedia.org/wiki/Silicon_Valley

Peter Verkaik
02-13-2008, 03:18 AM
Jazzed,

I attached the jem.out and status.out for the testJVM5.java file.
This is the debug output for a true javelin.
I programmed the javelin using Project->Debug
and then only did Step Into until the while (true) line in main() gets selected.

I think we both need to study this, because for the source level debugger
to work with the prop, the stack frames and heap use must be identical
to the true javelin.

regards peter

jazzed
02-13-2008, 05:12 AM
Well it's pretty clear the PC printed is the one straight out of the jem.out file.
Stack and heap appear to be known in advance. Not sure what to make of it.
I'll look at it more tonight.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--jazzed·... about·living in ·http://en.wikipedia.org/wiki/Silicon_Valley

Peter Verkaik
02-13-2008, 05:35 AM
Jazzed,
Minor update.
Going through the debug files, I realized when QueryStack command is executed, the entire stack
is always returned. So I changed stack[offset] to stack[address]. This makes it much
easier to locate stackframes (=fp).

I attached an updated status.out for the example I gave in my previous post.
Also attached the updated javelin ide.

Also note that when QueryHeap command is executed, the returned block sometimes
wraps around $7FFF. This is due to the fixed size (20 bytes) block·that is read.
Obviously the heap starts at $7FFF and only grows downwards.

Another thing I noticed, when a java program ends, the byte at $0000 changes from
$1D (=kDebugMagic) to $ED. Then after clicking reset, it changes to $1D again.
Apparently the value $ED signals end of program, just as the packet $05,$05,$7E does.

Also note that in both heap and stack, big endian is used.

regards peter

Peter Verkaik
02-13-2008, 09:34 PM
Here are jvmConst, jvmLoad and jvmStore.
Note that unsupported bytecodes are commented out.

I also edited status.out by including parts of jem.out so it easier
to follow what is happening. I added comments to identify recognized values.

Now I will do jvmMonitor and jvmMath.

regards peter

Peter Verkaik
02-13-2008, 10:41 PM
Here are jvmMonitor and jvmMath.
Because some math operations (like division by zero) lead to exceptions,
I added a variable mathException to jvmData, together with API's to
set, clear and test the mathException condition.
Also note that the math methods set the carry if the result is
larger than 16 bits.

Now I will do jvmArray.

regards peter

Post Edited (Peter Verkaik) : 2/13/2008 2:48:18 PM GMT

jazzed
02-14-2008, 12:21 AM
Hi Peter, tracing status.out is less tedious with jem.out snippets in line ... hope you have a tool to do that :)

It seems pretty clear that the JIDE at least has some knowledge of the stack ... question is, are there
queries from JIDE to JVM to get the stack pointer or does the JIDE use stack accounting from the bytecode?
Similar question for heap ... are there queries for the heap pointer from JIDE to JVM ?

If there are any queries, they are not part of the status.out. Please look for this in JIDE.
TIA

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--jazzed·... about·living in ·http://en.wikipedia.org/wiki/Silicon_Valley

Peter Verkaik
02-14-2008, 12:41 AM
There are four queries from IDE to JVM:

kComStatus: this retrieves the current pc, activity and bytecode.
Look for [QueryStatus] in status.out

kComConfig: this retrieves the device memorysize, programsize and heapbase.
Look for [QueryConfig] in status.out
Note that the returned programsize is a constant and does not reflect true programsize
(the debugger however calculates it correctly from stackbase).

kComHeap: this retrieves a·block of memory, the command sends startaddress and length,
the jvm returns the current hp and the requested memory bytes.
Look for [QueryHeap] in status.out

kComStack: this retrieves the current sp, current fp and current mp plus all the stackbytes
from stackbase to current sp.
Look for [QueryStack] in status.out

So all the values you get are actual values retrieved from the javelin/propjava.
What the IDE does is using the pc value to convert a jemline ( = address of bytecode sequence)
back to the names of a javaclass and method, and the·line in the source file. That's how it is
possible you see the selected line move from file to file while single stepping.

regards peter

jazzed
02-14-2008, 04:42 AM
Peter Verkaik said...

There are four queries from IDE to JVM: ...


So, the JIDE never asks for a description of the heap other than the initial configuration and these status messages?
Stack is fairly easy to predict. How does the JIDE know what heap addresses to query ?
Until I understand how JIDE knows the addresses to query, I can't help with this.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-14-2008, 05:29 AM
The debugger collects information based on which static variable is expanded or collapsed.
Variables that are collapsed (+ in front) do not get updated in the debugger screen until expanded by
the user (by clicking on the + in front of the variable, that then changes to a -).
See attached pictures how variables are organized (locals appear under the call stack).

regards peter

Peter Verkaik
02-15-2008, 04:02 AM
I extracted part of the outputpass() function in file CJEMLinker.cpp in·PropDirect package.
It shows what is exactly outputted after specific bytecodes. Especially lookupswitch
and tableswitch are interesting because the initial padding is left out, but there is padding
at the end to match the·javaclass it is generated from. Not sure why this·is done
in this way. Looks to me the orginal 4byte values would yield the same size, now 2byte values
are used because the javelin only supports 16bit ints.
Anyhow, this gives a detail insight in the jem.out bytecode format.

regards peter

jazzed
02-16-2008, 09:20 AM
Peter,
Have you considered how to put the modules you created for the new JVM design together?
There is more work to do in this area of course. It would be neat if we could use a branch
table, rather than a big case.
I'm considering some experiments with the method/class tables with LDC and GET/PUTFIELD
this weekend. I'll search for an alternative to having object references for these operations;
thing is however, the GET/PUTFIELD are almost certainly operations on an object ... possibly
LDC may not be.

Later ....

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-16-2008, 05:42 PM
Jazzed, Hippy,

I have put in code for all supported bytecodes. I think most code is ok,
some code may be quite wrong, so I would like you to take a look at it.
I inserted comments regarding the JEM format for all bytecodes.
I also made heap management much simpler because no garbage
collection is supported at this time.

Before we move on to integration, I would like the code for the bytecodes
to be completed. There are a few·bytecodes that may need to be revisited.
The math bytecodes for example, I could have misinterpreted the order of
arguments. For comparisons, I did not quite grasp the difference between
ifeq and if_icmpeq for example, as they both branch if two parameters
are equal (or so I understood).
Also not finished are the invokevirtual and invokestatic bytecodes. I did
put two subroutines pushframe() and popframe() in the jvmStack file,
based on the framelayout but it doesn't handle return values yet. So that
needs to be looked at also.

All code uses the API's from jvmData, so if a new global jvm parameter is
required, add it to jvmData and add API's for it, but I think all required parameters
are already·there.

@Jazzed,
I wish there was a ongosub command in spin so we could directly call
a routine based on an index rather than using case but for now I think
we better stick to case to keep code clear rather than optimized.

I've got a good understanding of how objects are created, see new, newarray and anewarray,
and I think that code is ok. If there is anything unclear, please say so and I can try to explain
it better. Also, if you have any specific javelin code that you need true debug info for, please post it
and I will run it on a javelin and generate debug info from that.

regards peter

hippy
02-16-2008, 07:00 PM
@ Peter : I'll take a look.

I did not quite grasp the difference between ifeq and if_icmpeq for example

Without anything in front of me I recall the first is pop two parameters and compare, while the second is pop one parameter, compare with an immediate operand, both then followed by an address as an immediate operand. - wrong !

Post Edited (hippy) : 2/16/2008 2:15:36 PM GMT

Peter Verkaik
02-16-2008, 07:36 PM
The JEM format for both is the bytecode followed by two bytes, which is an offset
to add to the programcounter in case the compare yields true.
The only difference I noticed is that icmpXX pushes either 1 or 0 back onto
the stack depending the compare yielded true or false.

I attached an updated set, I have put in the jvmEngine code (except for native method
handling which requires a return value from doStep).

With all the current code and a JavaProg arraysize of 16KByte, there are still over
1000 longs available.

regards peter

hippy
02-16-2008, 10:13 PM
@ Peter : My mistake - ifeq pops two items, compares and branches or not, ifcmpeq pops one item then compares with zero and branches or not.

Peter Verkaik
02-16-2008, 10:18 PM
@Hippy,
ok, so my icmpXX code needs some changing. What about the comparisons?
There was mentioning of pushing back values -1, 0 or 1 if v1<v2, v1==v2 or v1>v2.
Where does that come in? I haven't seen any bytecodes for just comparisons.

regards peter

Peter Verkaik
02-17-2008, 12:32 AM
Unable to locate Sun's java bytecode descriptions from an
earlier link given in this thread, I googled and found:
http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc.html

These at least provide all info, including stack movements.
Attached is the updated jvmCompareJump file.

regards peter

Post Edited (Peter Verkaik) : 2/16/2008 4:51:39 PM GMT

Peter Verkaik
02-17-2008, 06:40 PM
Going through the text for invokevirtual and invokestatic, I came up with
the following stack movement (texts are included)

{{
· invokevirtual
· Operation: Invoke instance method; dispatch based on class
· Format: invokevirtual,indexbyte1,indexbyte2··
· Operand Stack: ...,objectref,[arg1,[arg2 ...]] --> ...,
· Description
· The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
· current class, where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant pool item
· at that index must be a symbolic reference to a method, which gives the name and descriptor of the method as
· well as a symbolic reference to the class in which the method is to be found. The named method is resolved.
· The method must not be an instance initialization method or the class or interface initialization method.
· Finally, if the resolved method is protected, and it is either a member of the current class or a member of
· a superclass of the current class, then the class of objectref must be either the current class or a subclass
· of the current class.
· Let C be the class of objectref. The actual method to be invoked is selected by the following lookup procedure:
· If C contains a declaration for an instance method with the same name and descriptor as the resolved method,
· and the resolved method is accessible from C, then this is the method to be invoked, and the lookup procedure
· terminates. Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the
· direct superclass of C ; the method to be invoked is the result of the recursive invocation of this lookup
· procedure. Otherwise, an AbstractMethodError is raised.
· The objectref must be followed on the operand stack by nargs argument values, where the number, type, and order
· of the values must be consistent with the descriptor of the selected instance method.
· If the method is synchronized, the monitor associated with objectref is acquired or reentered.
· If the method is not native, the nargs argument values and objectref are popped from the operand stack.
· A new frame is created on the Java virtual machine stack for the method being invoked. The objectref and the
· argument values are consecutively made the values of local variables of the new frame, with objectref in local
· variable 0, arg1 in local variable 1 (or, if arg1 is of type long or double, in local variables 1 and 2),
· and so on. Any argument value that is of a floating-point type undergoes value set conversion prior to being
· stored in a local variable. The new frame is then made current, and the Java virtual machine pc is set to the
· opcode of the first instruction of the method to be invoked. Execution continues with the first instruction
· of the method.
· If the method is native and the platform-dependent code that implements it has not yet been bound into the Java
· virtual machine, that is done. The nargs argument values and objectref are popped from the operand stack and are
· passed as parameters to the code that implements the method. Any argument value that is of a floating-point type
· undergoes value set conversion prior to being passed as a parameter. The parameters are passed and the code is
· invoked in an implementation-dependent manner. When the platform-dependent code returns, the following take place:
· If the native method is synchronized, the monitor associated with objectref is released or exited as if by
· execution of a monitorexit instruction. If the native method returns a value, the return value of the
· platform-dependent code is converted in an implementation-dependent way to the return type of the native method
· and pushed onto the operand stack.
· Runtime Exceptions
· If objectref is null, the invokevirtual instruction throws a NullPointerException.
· Notes
· The nargs argument values and objectref are not one-to-one with the first nargs + 1 local variables.
· Argument values of types long and double must be stored in two consecutive local variables, thus more
· than nargs local variables may be required to pass nargs argument values to the invoked method.
}}
{{
· invokestatic
· Operation: Invoke a class (static) method
· Format: invokestatic,indexbyte1,indexbyte2··
· Operand Stack: ...,[arg1,[arg2 ...]] --> ...,
· Description
· The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
· current class, where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant pool item
· at that index must be a symbolic reference to a method, which gives the name and descriptor of the method as
· well as a symbolic reference to the class in which the method is to be found. The named method is resolved.
· The method must not be the class or interface initialization method. It must be static, and therefore cannot
· be abstract.
· On successful resolution of the method, the class that declared the resolved field is initialized if that class
· has not already been initialized.
· The operand stack must contain nargs argument values, where the number, type, and order of the values must be
· consistent with the descriptor of the resolved method.
· If the method is synchronized, the monitor associated with the resolved class is acquired or reentered.
· If the method is not native, the nargs argument values are popped from the operand stack. A new frame is
· created on the Java virtual machine stack for the method being invoked. The nargs argument values are
· consecutively made the values of local variables of the new frame, with arg1 in local variable 0 (or, if arg1
· is of type long or double, in local variables 0 and 1) and so on. Any argument value that is of a floating-point
· type undergoes value set conversion prior to being stored in a local variable. The new frame is then made current
· and the Java virtual machine pc is set to the opcode of the first instruction of the method to be invoked.
· Execution continues with the first instruction of the method.
· If the method is native and the platform-dependent code that implements it has not yet been bound into the Java
· virtual machine, that is done. The nargs argument values are popped from the operand stack and are passed as
· parameters to the code that implements the method. Any argument value that is of a floating-point type undergoes
· value set conversion prior to being passed as a parameter. The parameters are passed and the code is invoked in
· an implementation-dependent manner. When the platform-dependent code returns, the following take place:
· If the native method is synchronized, the monitor associated with the resolved class is released or exited as
· if by execution of a monitorexit instruction. If the native method returns a value, the return value of the
· platform-dependent code is converted in an implementation-dependent way to the return type of the native method
· and pushed onto the operand stack.
· Notes
· The nargs argument values are not one-to-one with the first nargs local variables. Argument values of types long
· and double must be stored in two consecutive local variables, thus more than nargs local variables may be required
· to pass nargs argument values to the invoked method.
}}
{{
stackframe just before invoke··· stackframe just after invoke··· stackframe just after return
···· |············ |·················· |············ |················· |············ |
···· +-------------+·················· +-------------+ <- fp··········· +-------------+
···· | aref / arg0 |·················· | aref / arg0 |················· | return val· |
···· +-------------+·················· +-------------+················· +-------------+ <- sp
···· | arg0 / arg1 |·················· | arg0 / arg1 |
···· |··· .....··· |·················· |··· .....··· |
···· +-------------+ <- sp············ +-------------+
······································ |·· locals··· |
······································ |··· .....··· |
······································ +-------------+
······································ | old method· |
······································ +-------------+
······································ |·· old fp··· |
······································ +-------------+
······································ | return addr |
······································ +-------------+ <- sp
}}

What it comes down to, is that the aref and arguments appear to be popped off the operand stack
and onto the new frame, but in fact the new frame pointer is adjusted to include the aref and
arguments. As these are removed upon return from the invoked method anyway this should be
no problem.
Comments?

regards peter

jazzed
02-17-2008, 10:21 PM
The aref object pointer, the result of new,·is apparently always the first stack entry unless the method is static like main. The method descriptor·to use·(this is not immediately obvious) is the constant table class descriptor start address + index.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-17-2008, 11:28 PM
The address of the current method descriptor is held in variable mp. The value
of mp is stored in the new frame as old method (and restored upon return), then the new value for mp
is calculated from byte1 and byte2 following the invoke bytecode.

aref is indeed the result of an earlier new bytecode and is only present in case
of invokevirtual. It represents the this identity.


regards peter

jazzed
02-17-2008, 11:31 PM
Peter Verkaik said...
... then the new value for mp is calculated from byte1 and byte2 following the invoke bytecode.

That's right, but when you scratch your head about how to resolve that, refer to my post :)

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-18-2008, 12:15 AM
The calculation of mp is not a problem. I just wanted to show that the implementation
can be more simpler than the texts indicate. This is of course possible because the entire
code is statically linked. Everything is resolved except for objects created at runtime.
Therefor we do need to check for null references.
That's where athrow comes in.

{{
· athrow
· Operation: Throw exception or error
· Format: athrow··
· Operand Stack: ...,objectref --> objectref

· Description
· The objectref must be of type reference and must refer to an object that is an instance of class Throwable
· or of a subclass of Throwable. It is popped from the operand stack. The objectref is then thrown by searching
· the current method for the first exception handler that matches the class of objectref.
· If an exception handler that matches objectref is found, it contains the location of the code intended to
· handle this exception. The pc register is reset to that location, the operand stack of the current frame is
· cleared, objectref is pushed back onto the operand stack, and execution continues.
· If no matching exception handler is found in the current frame, that frame is popped. If the current frame
· represents an invocation of a synchronized method, the monitor acquired or reentered on invocation of the
· method is released or exited (respectively) as if by execution of a monitorexit instruction. Finally, the frame
· of its invoker is reinstated, if such a frame exists, and the objectref is rethrown. If no such frame exists,
· the current thread exits.
· Runtime Exceptions
· If objectref is null, athrow throws a NullPointerException instead of objectref.
· Notes
· The operand stack diagram for the athrow instruction may be misleading: If a handler for this exception is
· matched in the current method, the athrow instruction discards all the values on the operand stack, then pushes
· the thrown object onto the operand stack. However, if no handler is matched in the current method and the
· exception is thrown farther up the method invocation chain, then the operand stack of the method (if any) that
· handles the exception is cleared and objectref is pushed onto that empty operand stack. All intervening frames
· from the method that threw the exception up to, but not including, the method that handles the exception are
· discarded.
}}

From this text I understand all frames are dropped until we reach we a method that has
in its descriptor an exception field that is non-zero.
Do you think that is right?
When I know how to deal with the exceptions, I can complete jvmInvoke and do some
test runs using a simple·java program.

regards peter

jazzed
02-18-2008, 12:33 AM
Peter, in summary, your description of throw behaviour appears correct.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

CJO
02-18-2008, 06:29 AM
@all,

It's nice to see work progressing and I am waiting with baited breath to see what you guys come up with next.

@jazzed,

Just drop me a message and I'll what (if anything) I can do when you think that the platform is ready

In the meantime, I'm going to get me a prop clip and start trying some of this out.

~ Christopher

Peter Verkaik
02-21-2008, 02:22 AM
Breakthrough !!
I have the jvm running for invokevirtual, invokestatic and native functions (only message native
function tested). Also working are the arrays, putfield, getfield, putstatic, getstatic, all stack related
bytecodes (after long debugging I discovered the pc was incremented multiple times during stack
movements).

Attached is a picture of a running program. Something is wrong on the last line (s1.indexOf(s2))
so there are still things to debug, but we can print and do math.
Also attached a new IDE, that bugfixes some debug messages like heap[$xxxx] where $xxxx
was sometimes negative or beyond memorysize.

At the moment the native functions are called from jvmInvoke which is fine for now.
The current spin program size is 6967 longs (that includes the·$4000 bytes for java program)
and there are still 1221 longs free.

regards peter

jazzed
02-21-2008, 03:54 AM
Good work Peter. I'll look the design in more detail.

I'm curious to see how the Native stuff turns out. I did provide a stack based interface
you might consider using and is connected between main and the jvm in my last zip post.

The basic interface flow is: The parameter "push" point is in call method. The parameter
"pop" point is in the Native call's parameters which seems reasonable since the type of
data is prearranged by native id. A return code is pushed by the native wrapper as
required, and finally the jvm return method pops the result.
Stack interface already implemented :)

Later.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Post Edited (jazzed) : 2/21/2008 5:20:23 AM GMT

jazzed
02-21-2008, 01:25 PM
Peter I was able to integrate your package with my text based debugger
with only one change in jvmEngine.spin doByte to PUB. Very flexible :)
Having all those files make compile long, but only annoying for F8 build.

Good work.
Time for test suites ?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-21-2008, 02:07 PM
Compilation takes slightly longer, but editing and locating specific routines goes
much quicker :-)
I am now looking at throwing exceptions. It seems there are 4 standard exceptions:
nulllpointer, outofmemory, illegalargument and indexoutofbounds.

For test suites you can use many of my javelin math test programs, for example
the UnsignedIntMath_test.java program (I already tested this and it fails
so there still are issues we need to fix).
http://tech.groups.yahoo.com/group/JavelinCode/files/Javelin%20Stamp%20IDE/lib/stamp/math/

Also usable are the Int32 package·and FloatLite6 package.
http://www.parallax.com/tabid/430/Default.aspx

These math programs do not require native functions and are therefore most suitable
for testing the jvm, as they also use the String and StringBuffer classes.

When these math programs run properly we can be sure the jvm is operating correctly.
I rather postpone working on the native functions until the jvm runs properly, although
the native functions can be tested independantly using spin test programs I suppose.

regards peter

Peter Verkaik
02-21-2008, 04:51 PM
Update.
Cause of s1.indexOf(s2) not working in my previous post, was that all values
are truncated to 16 bits, which means the comparisons did not function
properly. So I fixed the jvmCompareJump and jvmMath to sign extend 16bit values
before using the values. (Rather than sign extending the pop return values which
will make other functions disbehave because they rely on unsigned values).

regards peter

Peter Verkaik
02-21-2008, 05:58 PM
Update. Made tableswitch and lookupswitch bytecodes work.
if. if-else, for, while,·do-while also work.
Attached is the updated jvmCompareJump file.

regards peter

Peter Verkaik
02-22-2008, 12:07 AM
Major update.
My math program f3 (16bit floating point) didn't work because I had swapped the arguments
in jvmLogic. That is fixed.
Also made readRegister and writeRegister native functions working, which means the
EEPROM and Memory class can be used (EEPROM read/write needs to be checked).
Also updated the instanceof bytecode to search for superclasses.

Now my f3 class yields the same results on the propeller as javelin,
so I am pretty convinced the jvm is running properly at this moment.

regards peter

jazzed
02-22-2008, 12:25 AM
I'm getting a compile error in jvmNative.spin
> address %= jd.getMemSize 'to compensate for size 0x8000 in true javelin
changed to this and compiles
> address &= jd.getMemSize-1 'to compensate for size 0x8000 in true javelin
similar issue in two places.

Can you change jvmEngine.spin PRI doByte ... to PUB doByte ... ?
Thanks.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-22-2008, 12:49 AM
Sorry about the jvmEngine. The % needs to be //
Attached are updated files, made doStep PUB.

regards peter

jazzed
02-22-2008, 12:57 AM
No problem. Thanks for the edit.
Using addr &= val-1 is probably faster, but only correct for val as a power of 2 :)

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-22-2008, 02:43 AM
I have tested all my math classes and they all work. :-)

Downloading a java program to propeller goes faster than to javelin, but output to message window
is slower on the propeller than on a true javelin. So porting the jvm to assembler is wanted.
The only thing still missing regarding the java language,·is the try/catch/finally
construct. And of course the implementation of remaining native functions
and Virtual Peripheral code (ADC,DAC,PWM,Timer,UartRX,UartTX).

regards·peter

jazzed
02-22-2008, 03:00 AM
Yes, I've also done more testing and found the following work: A recursive
Fibonacci sequencer up to 20 items, a sieve of Erathosenes primes less than
500, and an inheritance test. This is pretty simple stuff, but don't have time
to get too involved for much more today.

How to do asm functions with the current code structure is beyond my propeller
knowlege cache. I suppose one could put the alternatives in jvmEngine, but that
would put us back a bit :) I am very interested in your approach to it.

Let me know which outstanding element you're addressing so we don't duplicate.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-22-2008, 03:22 AM
I will work on the exception handling.
That leaves the native functions. These need to be tested
and optimized (eeRead and eeWrite for example could use the jvmEeprom object).

Since most native functions rely on a 8.68 usec tick, that should be the first
VP implemented. Having that timer base we can compare results with a
true javelin. VP parameters are passed via registers (using readRegister and writeRegister
and these already work). I think the VP code must be in asm.
Application note AN001 seems to provide the code we need.
http://www.parallax.com/tabid/442/Default.aspx
I think the propeller is fast enough to combine ADC/DAC/PWM/Timer in one COG.
On the javelin all vp code for 6 VP's is executed every 8.68 usec.

regards peter

Kaio
02-23-2008, 06:44 AM
Nice to see how the code is growing in this short time. I'm very interested in this project because I'm a java programmer.
I had downloaded the code the first time this week and was looking about the content of files. It looks very good for me.
I had also downloaded the javelin ide, but I doesn't the jvm on the prop while I had trouble with the ide.

Peter has mentioned that it could be time to port to assembly. I thought it would be helpfully if someone would do that. So
I will present you the work of the first night and some hours of today. http://forums.parallax.com/images/smilies/wink.gif

It was not to difficult to implement the byte code handler as they are mostly small. I have it not tested yet because it is
also not complete. But it should demonstrate how I think it could be realized. At the end it should be allocate 3 cogs
perhaps only 2 cogs with assembly.

Currently the mainloop is still in Spin but this should be later also in assembly.

I have only 3 files changed and currently no methods removed in Spin code. You can copy the attached files to the others
and open the jvmMainAsm at first.

Any comments appreciated.

Thomas

Peter Verkaik
02-23-2008, 07:14 AM
Great work Thomas.
I can't say anything about the asm code as I have no·knowledge of all
the PASM conditional statements. But it looks good.
Is it possible to have more than 64 entries in the JemCodeJmpTable ?
(spin case only allows 64)

regards peter

Kaio
02-23-2008, 07:31 AM
Yes it is possible. There are no restrictions about that in assembly.

Thomas

jazzed
02-23-2008, 09:12 PM
Hi Thomas,
Welcome to this effort.
Do you have or know of any benchmark comparisons between spin and asm for the same algorithms?
Javelin beats Propeller running spin JVM by roughly 15x today with a 100 prime Sieve of Erathostenes.
Thanks.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-23-2008, 10:17 PM
Jazzed,
Do you have a javelin? If not, how did you come up with that number?

regards peter

deSilva
02-23-2008, 10:40 PM
Hippy, Peter,

I am sure a lot of people have NOT followed this extremely comprehensive and for most parts quite technical thread. Although I have the suspicion that the interest in Java is as high as in FORTH (whatever I am saying with this) I think it is one of the most interesting developments here before (and maybe even after?) the advent of the C-Compiler.

So my request is: Can you prepare a description how to use the complete system for the simple Java User, in the near future?

My main point of interest is this: I have to accept the fact that the required use of SPIN is too high a threshold for many users to be, independent of its peformance, merrits or the opposite of it. The C compiler will bring up different issues...
But something like a free (!) Java implemention, based on something which already has a generic maturity will find acceptance. At least German universities use Java throughout in their CS education.

Also I see no reason why a piece of Java should run considerably slower than SPIN.

jazzed
02-23-2008, 11:07 PM
@Peter,
Yes, I have a Javelin. Had to dust it off. I don't normally pull data out of the air :)
Here's the source I used for comparisons (not mine). Times were relative, not absolute.

@deSilva
Today spin is interpreting a subset of java bytecode generated from mostly
compliant java source (i am quite annoyed that i must remove args from main).
As far as a user guide goes, I think the Javelin IDE / manual are good starting points.



//
// Erathostenes.java
// class Erathostenes {
public static void main() {
final int end = 542;
int count = 1;
System.out.println("Sieve of erathostenes");
// primes initieras till false
boolean[] primes = new boolean[end];
for(int i = 0; i < end; i++) {
primes[i] = true;
}
System.out.println("Array initialized, end = " + end);
for(int i = 2; i < end; i++) {
if(primes[i]) {
System.out.println(count + ". prime: " + i);
count++;
for(int j = 2*i; j < end; j += i) {
primes[j] = false;
}
}
}
System.out.println(" ... OK");
}
}

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Post Edited (jazzed) : 2/24/2008 2:23:32 AM GMT

Peter Verkaik
02-23-2008, 11:24 PM
Update.
Attached are updated jvmObject and jvmData.
The new bytecode used to check if size of the new object > 0.
However that need not be the case for a class without variables,
as in the following code.

import stamp.core.*;

public class ReadRegisterTest {
·
· static public class JVM {
··· public JVM() {
··· }
··· public void test() {
····· System.out.println("T");
··· }
· }

· static void test2() {
··· System.out.println("T2");
··· j.test();
· }
·
· static JVM j = new JVM();
·
· static void main() {
··· test2();
··· System.out.println("M");
··· while (true) {
··· }
· }

}

Note that (local) class JVM has no·variables, only a constructor and a method.
The size of the object created on the heap for j, is 0 bytes (meaning only the class reference
and the size are stored).

@DeSilva,
One only needs to download the jvmMain to the propeller (select right clock settings) using PropTool,
then startup the javelin ide and program java into the prop from the ide.
Jazzed is right about the javelin manual being the best·source, as it emphasizes the
difference between pc java and javelin java.

regards peter

deSilva
02-23-2008, 11:28 PM
@Jezzed:
This could be a miusunderstanding. I shall not do anything in the direction of finding clues or doing real work for getting JAVA running http://forums.parallax.com/images/smilies/smile.gif I will use it if it does!

I just wanted to point out that it will be useful, if you bring it to a state of good documention and easy use! And I know peole you will definitely like it!

What I can do is provide you with some benchmark value for Eratosthenes for SPIN and PASM, if you want it...

For this you should put the printing ( System.out.println(count + ". prime: " + i); ) into a later, untimed loop.
Also the outer loop should stop at SQRT(end); but I also can remove my optimizations...

However Eratosthenes is not a good benchmark candidate as local manipulations (size of vector items, ByteFill,...) will influence its performance tremendiously...

jazzed
02-24-2008, 12:19 AM
deSilva said...
@Jezzed:
This could be a miusunderstanding. I shall not do anything in the direction of finding clues or doing real work for getting JAVA running http://forums.parallax.com/images/smilies/smile.gif I will use it if it does!
...

Nothing misunderstood or·assumed··:)

However, if you provide an apples to apples comparison between performance of spin -vs- asm·for some reasonable benchmark, however you please to write it, that would be outstanding.·Others will certainly appreciate your effort.

A very simple user guide for getting started with JavaProp or whatever in the Javelin environment would be useful. Peter has outlined pieces here for a tinkerer to get started, but a "product" requires a good package.

As far as optimizations go, one should optimize for the given goal. Here the goal was not to do a Sieve performance measurment, but to use a somewhat non-trivial code sample for a CPU-JVM side by side comparison. Having the ...println... is fine the way it is especially since part of the performance measurement is checking how well the JVM can deal with virtual calls. May not be the best example, but it fit the need. As needs change, so will implementation. One would expect at some point to need a performance measure based on an industry standard, but we're not there yet.

Cheers :)


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

deSilva
02-24-2008, 02:13 AM
Jazzed: I understand all your points.. But I have seen two very promising projects fail now (FORTH as one) where people asked for...

The people I am thinking of will:
(a) .. be new to the Propeller
(b) .. know nothing of Parallaxes great other products
(c) .. want to learn things to do with the Microcontroller
(d) .. have a more or less good understanding of (some even recent programming practice with ) JAVA
(e) .. expect something "out of the box"

The benchmark topic came to mind, as we need SOME reference wrt SPIN (faster will be good - and not so difficult!) And using two COGS will be no problem either...


said...
@DeSilva,
One only needs to download the jvmMain to the propeller (select right clock settings) using PropTool,
then startup the javelin ide and program java into the prop from the ide.
Jazzed is right about the javelin manual being the best source, as it emphasizes the
difference between pc java and javelin java.


Tell me when it's safe to work according to that directives http://forums.parallax.com/images/smilies/smile.gif I shall do!!
But not today .. my schedule is more around March 15...

Post Edited (deSilva) : 2/23/2008 6:19:29 PM GMT

Kaio
02-24-2008, 06:05 AM
Jazzed,

I don't know how fast it will run exactly if the engine including the main loop is located in assembly.
The first step I will do is only to implement the engine in assembly. I expect for this a execution time
of 40 µs per Java bytecode. This is related to the execution of mainloop which is in Spin. But this should
be at minimum 5 times faster than running all in Spin.

If we could move the mainloop also in assembly this should boost the speed again by factor 5 to 10.

Thomas

jazzed
02-24-2008, 09:50 AM
@Thomas,
Well, at least there is some progress that can be made in performance.
I like your coding style. I've had to do assembly mainly for boot code,
ISR, and gdb (yuck) to support C mostly with gnu asm, but don't care
for it mostly. You're style offers a refreshing perspective in the dark art.

@Peter,
I've been looking at the Virtual Peripheral stuff, and came up with this
list of requirements. Please review and comment when you have time.

/**
* Implementing Virtual Peripherals (VP) requires a process to run in the background.
* This is a good opportunity for Propeller, although it takes another COG out of
* the user's hands. (We don't have a strategy for the user to control a cog anyway.)
*
* The elements that need a background process are: ADC, DAC, PWM, Timer, and UART.
* Being able to do all of these in one COG would be nice, but we are limited to
* counters per COG. If more VP are needed, more COGs will be used.
*
* Common VP design requirements:
*
* - Up to 6 VP should run at once.
* - All VP elements should run every 8.68us.
* - VP pin usage is mutually exclusive.
*
* - Can we have have 6 PWM or 6 ADC or 6 DAC or 6 Uart run at a time ?
* The java code clearly uses only 1 timer at any given moment, but
* there are 4 timer variables ... this is very confusing.
*
* - It is unclear how any VP would be stopped ... this means a fixed configuration.
*
* Design requirements for ADC:
*
* - ADC will be initialized by native call.
* - ADC should be readable by user ... I see no provision for this in jvmNative.
* - ADC pins should be selectable one for input one for reference output.
* - External RC network is required on the input pin for ADC to function.
* - Input measurements are limited from 0 to 3.3VDC.
* - Up to 2 ADC will be usable at once (unless more cogs are added).
*
* Design requirements for DAC:
*
* - DAC will be initialized by native call.
* - DAC should be writeable by user ... I see no provision for this in jvmNative.
* - DAC output pins should be selectable.
* - External RC network is required on the output pin for DDC to function.
* - Output measurements are limited from 0 to 3.3VDC.
* - Up to 2 DAC will be usable at once (unless more cogs are added).
*
* Design requirements for PWM:
*
* - PWM pins should be selectable (done in native code for now).
* - PWM will be initialized by native call.
* - Each PWM pin's pulse cycle characteristics can be updated any time.
*
* - Up to 2 PWM's should run at once now (allow for 4) ? To use the built-in
* counters for PWM, one needs 2 COG to get 4 PWM, or 3 COG for 6 PWM.
*
* Design requirements for Timer:
*
* - Timer should tick every 8.68us.
* - Timer should start when initialzied by native call.
* - Timer value should latch on demand from native call.
* - One timer will run at a time.
*
* - It is not clear how a timer would be stopped; need input.
*
* Design requirements for Uart:
*
* - Uart will operate in one direction per instance.
* - Uart will buffer input or output at 256 bytes each.
* - Uart receiver using HW flow control will stall sender when 16 RX buffer bytes are free.
* - Uart baud rate will be selectable from 600 to 57600 BPS.
* - Uart stop bits will be selectable from 1 to 8.
* - Uart level sense can be inverted.
*
* - Up to 6 Uart will be allowed ? Looks like 2 for now.
*
*/

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-24-2008, 12:37 PM
Reading and writing parameters to Virtual Peripherals is done using the
readRegister and writeRegister native calls. Starting and stopping VP's
is done by native calls. In addition there are a CPU.installVP() and CPU.removeVP()
java methods. These maintain a list of installed VP's in java variables.

Before I explain the several VP's, where does this 8.68 usec come from?
The javelin uses a sx48 chip running on 25MHz with an interrupt period of 217.
That means the interrupt starts EXACTLY every 217 clockcycles.
217/25MHz = 8.68 usec
The number of clockcycles in the interrupt routine·must not exceed 214 (due to 3 cycles overhead).
The longest piece·of code is for the receive uart, something like 32 clockcycles.
With 6 running receive uarts that is 6x32 = 192.

VP's are installed in banks. Each bank is 16 bytes and the banks occupy addresses 0x80-0xDF.
In the jvmData these are simulated by·vpRambank byte 0[MAX_NUM_VPS*16].
The 6 banks are 0x80,0x90,0xA0,0xB0,0xC0,0xD0. The register addresses are offsets 0-15 ORed
with the allocated bank.
See CPU.installVP() and CPU.removeVP() for how the list of VP's is maintained.
Each VP has a java variable vpBank which either holds an allocated bank or -1 (NOT_INSTALLED).



/**
* Implementing Virtual Peripherals (VP) requires a process to run in the background.
* This is a good opportunity for Propeller, although it takes another COG out of
* the user's hands.
·· ***** (We don't have a strategy for the user to control a cog anyway.)
·· We can add this when extending the jvm with propeller specific enhancements.

*
* The elements that need a background process are: ADC, DAC, PWM, Timer, and UART.
* Being able to do all of these in one COG would be nice, but we are limited to
* counters per COG. If more VP are needed, more COGs will be used.
· ***** We do not rely on the counters, except for generating the 8.68 usec tick.

*
* Common VP design requirements:
*
* - Up to 6 VP should run at once.
* - All VP elements should run every 8.68us.
* - VP pin usage is mutually exclusive.
·· ***** The java code does not impose the mutually exclusive usage of pins.
·· Obviously, when using the same pin for uart receive and pulseOut both functions
·· won't work. So it is up to the programmer to select the proper pins for the application.

*
* - Can we have have 6 PWM or 6 ADC or 6 DAC or 6 Uart run at a time ?
·· ***** Yes, any VP type can be used/mixed for 6 total.

* The java code clearly uses only 1 timer at any given moment, but
* there are 4 timer variables ... this is very confusing.
·· ***** There is only 1 free running 32bit timer and it is only started when the
·· static globalTimerVP is null. Once started that is set to the first Timer object value.
·· (see Timer class). Each Timer instance has 2 16bits variables, startHi and startLo
·· that make up a 32bits start value. The start value is the latched free running timer
·· value when calling t.mark(). The several timeout methods use this startvalue
·· together with a latched free running timer value to find out if a timer has expired.
·· So there are an unlimited number of timers (while memory serves) using only 1 VP bank.

*
* - It is unclear how any VP would be stopped ... this means a fixed configuration.
·· ***** VP's are started and stopped by native calls. Each VP type has these native calls
·· defined in their class. They are called from the VP's start() and stop() methods.

*
* Design requirements for ADC:
*
* - ADC will be initialized by native call.
·· ***** ADC.start() and ADC.stop() start and stop an ADC. start() calls install(bank).
·· stop() calls CPU.removeVP()

* - ADC should be readable by user ... I see no provision for this in jvmNative.
·· ***** ADC.value() returns the current value. It calls the readRegister native function.

* - ADC pins should be selectable one for input one for reference output.
·· ***** These are passed to the ADC constructor, eg. when using ADC myADC = new ADC(inpin,outpin)

* - External RC network is required on the input pin for ADC to function.
* - Input measurements are limited from 0 to 3.3VDC.
* - Up to 2 ADC will be usable at once (unless more cogs are added).
·· ***** If we mimic the javelin approach we can run 6 ADC if necessary. The ADC VP code
·· accumulates the number of times the outpin is set high during 256 interrupts. All the ADC
·· VP code needs to do is to set the outpin to the inverted value of the inpin and incrementing
·· a register when the outpin is set high.

*
* Design requirements for DAC:
*
* - DAC will be initialized by native call.
·· **** DAC.start() and DAC.stop()· start() calls install(bank). Note that this is a different install
·· then the one used for ADC. The linker distinguishes both based on class name.

* - DAC should be writeable by user ... I see no provision for this in jvmNative.
·· ***** Done using method DAC.update(value) update() calls writeRegister native function.

* - DAC output pins should be selectable.
·· ***** Pin to use is passed via constructor.

* - External RC network is required on the output pin for DDC to function.
* - Output measurements are limited from 0 to 3.3VDC.
* - Up to 2 DAC will be usable at once (unless more cogs are added).
·· ***** Same comment as under ADC. The pin is set high for the number
·· of interrupts specified in value passed to update(). The remaining time
·· to complete 256 interrupts the pin will be low. Basically, DAC is just a simple PWM.

*
* Design requirements for PWM:
*
* - PWM pins should be selectable (done in native code for now).
* - PWM will be initialized by native call.
* - Each PWM pin's pulse cycle characteristics can be updated any time.
*
* - Up to 2 PWM's should run at once now (allow for 4) ? To use the built-in
* counters for PWM, one needs 2 COG to get 4 PWM, or 3 COG for 6 PWM.
*·· ***** Again, same comment as under ADC (if using software PWM)
*
* Design requirements for Timer:
*
* - Timer should tick every 8.68us.
* - Timer should start when initialzied by native call.
·· ***** The global 32bits timer is started when using Timer.start(), stopped when using Timer.stop()

* - Timer value should latch on demand from native call.
·· **** Native function latch does that. It sets the latchregisters which are readout
··· using the native readRegister calls.

* - One timer will run at a time.
·· ***** There is only 1 timer. See comments on timer above.

*
* - It is not clear how a timer would be stopped; need input.
·· ***** Timer.stop() calls CPU.removeVP() which deletes the Timer VP.
*
* Design requirements for Uart:
*
* - Uart will operate in one direction per instance.
·· ***** Method setDirection can change the direction at runtime for the same instance.

* - Uart will buffer input or output at 256 bytes each.
·· ***** Data is read/written directly from the buffer in java. Which address in the
·· buffer to access is determined by head and tail pointers. These are read/written via
· ·readRegister and writeRegister native calls.

* - Uart receiver using HW flow control will stall sender when 16 RX buffer bytes are free.
·· ***** and will allow transmission again when there are 16 bytes left in the buffer.

* - Uart baud rate will be selectable from 600 to 57600 BPS.
* - Uart stop bits will be selectable from 1 to 8.
* - Uart level sense can be inverted.
·· ***** for both datapin and flowcontrol pin
*
* - Up to 6 Uart will be allowed ? Looks like 2 for now.
·· ***** If we can do the VP code in as little code as on the SX (30 instructions)
·· we should be able to manage 6.
*
*/


I have named all the registers used for the VP routines in jvmData.

regards peter

Peter Verkaik
02-24-2008, 07:44 PM
Major update.
I implemented the try/catch/finally construct.
For this I moved jb_athrow together with a functions throw and throwException
to the file jvmException.
The function throw allows to throw a runtime error using the defined exceptions
· kIllegalArgumentException· = 1
· kNullPointerException····· = 2
· kIndexOutOfBoundsException = 3
· kOutOfMemoryError········· = 4
I have implemented these throws in new,newarray,anewarray and other
functions where a parameter must not be 0. So these functions now throw
an exception when some parameter is invalid. This does not apply to math functions
as there is no·standard math exception. It is up to the programmer to
use try/catch when dividing and the denominator may be 0.

I also implemented the bytecodes jsr and ret as these are used when using finally.

There are two issues yet to solve:
1. The line
·'if offset => jd.readJavaIntBE(exceptionTable + 1 + index) AND offset < jd.readJavaIntBE(exceptionTable + 3 + index)
in function throwException in jvmException.spin is commented out because else the catch never works.
I based that function on the tinyVM function throw_exception(Object *exception)
located in the timyVM source file .\vmsrc\exceptions.c (attached)

2. When using finally and an exception is not catched, the finally clause is repeated over
and over again.

I attached my test java file.
If anyone could take a look at the throwException function to see where I obviously must be
do something wrong (possibly removing one frame too many ??) that would help me, because
I tried to get the finally working for over half a day now.
BTW, finally works when an exception is catched.

regards peter

jazzed
02-25-2008, 01:55 AM
Peter,

On the throw issue, one thing comes to mind that the exception address for Object is -1 $ffff.
It seems that throwException vars e and exceptionTable should be checking for > 0 rather than <> 0.
I can't spend too much time on this though. I've been in such a "trench" many times, and I find
some things help: 1) have a conversation with someone about the problem fully describing the
approach and expectations of process/data on which you depend ... this forces you to explain
in sufficient detail so that you may realize something overlooked and it allows a devil's advocate
to challenge your assumptions. 2) take a long break and get a good night's rest ... answers can
come there ... try to wake up and write it down! 3) take a shower and/or do something mundane
that requires no thought for 15 minutes. This puts you in "alpha" state where answers can also come.

On the VP stuff ... Yes, it had occured to me that the only way to make all this work in a CPU
with no parallel processor, etc... would be to use a "task" fired from an interrupt periodically
similar to what an o/s does with scheduled timer procs. Thanks for the confirmation :)

On the UART, do we require 6 256 byte buffers or just 1 (managed by the java code) ?
I missed the part about inverting the control line too. Thanks.

We need to establish an IM connection. Please reply to my private message.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

CJO
02-25-2008, 04:26 AM
@deSilva, et al.

I am in the process of coming up with some basic guides to help people get "up and running", however, the JVM is still far enough from finished that there is little point in writing too much. In addition, I plan to get a prop stamp and make sure I can make that work, as I don't want to write something that is "incorrect" because I haven't actually tested my own instructions.

I'll hopefully get the prop stamp on monday or tuesday and then have some documentation in a day or two.

~ Christopher

Peter Verkaik
02-25-2008, 04:52 AM
A spin stamp is not required, you can use a propeller protoboard.
Communication between the Javelin IDE and propeller can be
done using the TX/RX pins used to program the propeller.
(same serial port). It just means you cannot use the proptool
to program new firmware (the jvm program) when the IDE connection is in use.

regards peter

Kaio
02-25-2008, 05:13 AM
@Jazzed,
thank you for your appreciation about my code style. I will do my best that everyone can understand my dark thoughts of coding.


@Jazzed, Peter
It seems that we would need 3 cogs to support 6 VP's at all. Each cog of the Propeller provides 2 timers which can be used for ADC, DAC, PWM or only as timer.

I would suggest that we use also the cogs which are running the bytecode decoder. Otherwise we would have 2 cogs for bytecode decoding and up to 3 separate cogs for VP's if necessary.
We could locate the smallest subroutines to the decoding cogs and the more comprehensive code to a separate cog. So the cogs would provide a static configuration about VP's. E.g. decoding cog1 supports 2 timer, decoding cog2 supports 2 PWM and another cog could be started to support 2 ADC, DAC or UART or a mix of 2 of this.

Thomas

Post Edited (Kaio) : 2/24/2008 9:19:08 PM GMT

jazzed
02-25-2008, 09:54 AM
@Thomas,

I'm hoping we can have a VP system equivalent to that on the Javelin SX48B i.e all timer process
functions (ADC, DAC, PWM, Timer, UART) can be performed in one "tick" of a COG.

Speculating that SX48B may be faster than one COG because of it's architecture ... I'm not sure.
I am attracted to the notion of having the counters perform the PWM tasks (timer can be done either
way it seems). It seems that having one COG doing it all for now is fine.

Perhaps copying this "VP set" to other COGS is a way to enrich the Javelin concept ? By providing
"N" times the number of Virtual Periperals, certain things become more possible like controlling
a 17 servo robot for example (current draw there would be a nightmare to coordinate though).

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

deSilva
02-25-2008, 10:31 AM
To me this sounds like a "Crossroad":

- Either emulate the VP "in the spirit" of the JavelinStamp, with some restrictions, also possibly needing external Hardware... ("Closed System") This has a huge advantage for an "out of the box solution", also taking advantage of existing documentation... It is in the spirit of a VM, but crippling the Propeller, as with all emulations

- Or define a framework (= interface) where a user can plug-in his Assembly Code for a COG, so he can define his own VM ("Open System"). There should be more than one VP per COG. A "reference implementation" is also required, of course http://forums.parallax.com/images/smilies/smile.gif

deSilva
02-25-2008, 10:33 AM
CJO said...
...get the prop stamp on monday or tuesday and then have some documentation in a day or two

http://forums.parallax.com/images/smilies/smile.gif

jazzed
02-25-2008, 11:02 AM
@deSilva,

That is a fascinating idea with great possibilities ... for a future phase. One of the reasons
we've gotten where we are is because we have a well defined specification. Until we meet
that specification, we shall not wander far off course. As you know, correctly specifying a
product is almost as hard as producing it. I've seen many multi-million dollard disasters.

Phase I first. Phase II is for the wish list. Your idea certainly merits phase II consideration.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-25-2008, 03:08 PM
I did some calculations:
On the javelin with 25MHz clock, 217 clockcycles make up 8.68 usec.
On the prop with a 80MHz clock, (80/25)*217 = 694 clockcycles make up 8.68 usec.
If each instruction in PASM executes in 1 clockcycle, as do most SX instructions,
there should be more than enough time to·run all VP code in a single COG.
This cog would emulate the SX48 interrupt routine.

Since the VP code only deals with the vpRambank registers,
and we·want the same flexible use of VP as on the javelin, meaning any type of VP
can be started while there are free banks, the following outline in spin code
should be·implemented in PASM.

CON
· 'Virtual Peripheral types
· NONE·· = 0
· TIMER· = 1
· ADC··· = 2
· DAC··· = 3
· PWM··· = 4
· UARTRX = 5
· UARTTX = 6
·
OBJ
· jd: "jvmData"

DAT
· vpBank· byte 0
···
PUB isr | i,type
{{ Run all VP code }}
· repeat
··· waitTick 'wait for 8.68 usec tick
··· repeat i from 0 to jd#MAX_NUM_VPS-1
····· vpBank := jd#nmPeriph0Bank + (i<<4)······················ 'set currently accessed bank
····· type := jd.readRegister(vpBank + jd#nmPeriphISRVec) & $0F 'nmPeriphISRVec holds VP type
····· case type
······· NONE:·· vpNone
······· TIMER:· vpTimer
······· ADC:··· vpAdc
······· DAC:··· vpDac
······· PWM:··· vpPwm
······· UARTRX: vpUartRx
······· UARTTX: vpUartTx
······· other:

PRI waitTick
{{ wait until 8.68 usec have passed since last call }}

PRI vpNone
{{ optional: wait an average time to minimize jitter }}

PRI vpTimer
{{ increment 32bits timer in bank specified by vpBank }}

PRI vpAdc

PRI vpDac

PRI vpPwm

PRI vpUartRx

PRI vpUartTx


To enhance (eg. in phase II) we can add the ability to include a userdefined set of additional VP's,
which would then run in a different cog from the default VP's.

regards peter

Peter Verkaik
02-25-2008, 04:27 PM
I solved the try/catch/finally issue.
The stored values were not offsets but absolute addresses, so I needed
to compare those against jvmPC.
Attached is the updated jvmException file.

The only issue still standing is when using 'step over' in the source level debugger.
This combines activity setting kRun with breakpoints.
I will focus on that next.

regards peter

Post Edited (Peter Verkaik) : 2/25/2008 8:37:28 AM GMT

jazzed
02-25-2008, 10:58 PM
Peter Verkaik said...

I did some calculations:
On the javelin with 25MHz clock, 217 clockcycles make up 8.68 usec.
On the prop with a 80MHz clock, (80/25)*217 = 694 clockcycles make up 8.68 usec.
If each instruction in PASM executes in 1 clockcycle, as do most SX instructions,
there should be more than enough time to·run all VP code in a single COG.


...
The datasheet says 4 clock cycles for xor and many typical instructions.
Measuring xor pin toggle time with pll16x, infreq 5Mhz, I see 4 clock cycles.
It seems·that for similar ASM in one cog, Prop will run slower than SX48b.


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-25-2008, 11:14 PM
Then actually the prop appears to run @20MHz giving (20/25)*217 = 174
But the prop can test multiple flags (c,nc,z,nz) in a single instruction (which the SX48 cannot).
That should be enough to make up for the missing cycles (I hope).

regards peter

Peter Verkaik
02-26-2008, 12:48 AM
Debug 'step over' works now. Only when using try/catch and there is a catch
the 'step over' continues to run further than one line. This is due to dropped
frames by the exception handler. (this is also so for a true javelin).

regards peter

Peter Verkaik
02-26-2008, 07:19 PM
I let jvmEngine return a positive value in case a native function must
be performed. So native functions are now executed from jvmMain.
The advantage of this is that only jvmMain needs editing for adding
new native functions (by including a new object for the new functions).

I also moved some constants that are local to specific objects, from
jvmData to those object.

The java method Terminal.getChar() is working, so it is possible to
use user input in the java programs.
The attached java test program will demonstrate this.

I believe the jvm now fully supports the bytecodes generated by
the javelin IDE. Some native functions may not work. The Virtual Peripheral
code needs still to be written. But it is possible to write java programs
that only require terminal input/output (such as the attached java program).
The source level debugger·is also working.

Edit: I also attached the latest Javelin IDE.
To use that, first install IDE version 2.0.3 that you can download from here:
http://www.parallax.com/tabid/443/Default.aspx
Install version 2.0.3 and then unzip javelin.zip into the IDE working folder.
Download the jvm firmware into the propeller using the proptool.
Then startup javelin.exe instead of "Javelin Stamp IDE.exe" from the working IDE folder.

regards peter

Post Edited (Peter Verkaik) : 2/26/2008 12:02:14 PM GMT

Robot Freak
02-26-2008, 08:37 PM
Are you saying all java-only bytecodes are working?
So the following things can be used:
- declaring variables (int, char, String, arrays)
- declaring void and int methods
- declaring objects with local variables
- doing math with variables
- using statements (if, else, do ... while, while, switch)

The modified Javelin IDE can recognize a PropJavelin, and download java programs into memory?

If so (or maybe some points not), you all have done a great job in such a short time!

Kind regards,
Robot Freak

Peter Verkaik
02-26-2008, 09:18 PM
That's right. All·javelin constructs can be used.
The same limitations apply: ints are 16bits, no floats or longs for now.
The new javelin.exe has additional commands:
Project->Download to RAM
Project->Program to RAM
Project->Debug to RAM
to support the propeller's ability to download only to ram.
Using the regular commands will copy the bytecodes into propeller eeprom.
At the moment the JVM provides a 16KByte memoryspace for the bytecodes.
(The javelin has 32KByte memoryspace).
There are still more than 1000 longs free so that space could be cranked up to 20KByte.
I hope once alot of the spin code is converted to PASM that we can
crank it up·to 24KByte.

regards peter

Robot Freak
02-26-2008, 10:15 PM
Wow, that's great you can confirm that.
One these days I get a pair of Protoboards to start testing the JVM.

All CPU native methods are done, and it looks like the PWM VP is ready?

Peter Verkaik
02-26-2008, 10:22 PM
Most native functions have code (in spin) but these need to be tested.
No VP code is available, meaning there also is no Timer. Since most
native CPU methods depend on a 8.68 usec tick, that needs to be realized
first. The CPU.readPort(), CPU.writePort(), CPU.readPin(),·CPU.writePin(),·CPU.shiftIn(),·CPU. shiftOut()
have code and do not rely on the timer tick, so these may work but they
need to be tested to be sure.

regards peter

Robot Freak
02-26-2008, 10:39 PM
After downloading the new IDE, I unzipped it, placed it in the existing IDE folder and renamed it.
After starting I get the message "Unable to open file (null)".
I tried clicking on "New" three times, the same error.
After clicking on "Open" and selecting a file, I get about the same error.

Did I do something wrong?

Kind regards,
Robot Freak

Peter Verkaik
02-26-2008, 10:42 PM
You probably have no printer installed in windows.
Go to start->settings->printers
and install a generic/text-only printer
Then restart the IDE and you should have no trouble.

regards peter

Robot Freak
02-26-2008, 10:53 PM
I've got a network printer installed,
I tried setting the "Microsoft XPS Document Writer" as default, but the same error comes up.

Kind regards,
Robot Freak

Peter Verkaik
02-26-2008, 10:57 PM
In that case, startup the IDE, goto Project->Global options.
A window pops up. Click OK. Exit the IDe. Restart the IDE.
That should do it.

regards peter

Robot Freak
02-26-2008, 11:04 PM
That did it, thanks.

Trying to download to my Javelin, but it didn't work.
So I guess this IDE can only be used with the PropJavelin?

Kind regards,
Robot Freak

Peter Verkaik
02-26-2008, 11:27 PM
It should work also·with a true javelin.
You need to make sure·the javelin is on the first available
com port (See Project->Global option, tab debugger, edit port list).
Even if you use Project->Program to RAM, when it connects to
a true javelin it will do Project->Program as you would normally use
with the javelin.

I usually edit the port list to only include the comport to which the device is connected.

Try Project->Identify.
If it finds a true javelin it should show version $50.
For a propeller/spinstamp programmed via the Propeller TX/RX pins
(setting commPort = 1 in jvm·spin program) the version is $78.
For a spinstamp programmed via the SOUT/SIN pins (setting commPort = 2 in jvm program)
the version is $70.

regards peter

Robot Freak
02-26-2008, 11:58 PM
I always made a list with the ports from 1 to 14, to make sure that the IDE found my Javelin.
(because my laptop assigns a different number each time I reconnect the USB2serial device)

After deleting the others, it worked.
Thanks!

Kind regards,
Robot Freak

deSilva
02-27-2008, 02:41 AM
re Propeller timings.
The timing of Propeller instructions is well known.... What is not well known is how they compare to an 8-bit machine. The enormious advantage of 32 against 8 bits cannot always be utilzed! On the other hand allow the conditional instructions terrific shortcuts.Third: The propeller instruction set is not well suted for VMs... Fourth: There is the panalty for HUB accesses. To write fast PASM code needs some good experience with it..... After reading the above I should not expect the Propeller VW running faster than the SX

Peter Verkaik
02-27-2008, 04:00 AM
@DeSilva, since you have better knowledge of PASM than me, do you expect
a PASM JVM would yield the same speed, or even considerable less?
I think you are right that hub access will put the greatest limit on the speed,
so someone with detailed knowledge of PASM should do the conversion to PASM,
and that isn't me.
The·JVM is running properly at this moment so I think we can keep it in this
state so it can be·converted. The fact that some native routines are not working
or not tested to be working should be not a problem for the JVM itself.

regards peter

simonl
02-27-2008, 06:04 AM
I think Peter's just set you a challenge deSilva!

@Peter: Astonishing work. I'll _have_ to learn Java now http://forums.parallax.com/images/smilies/smile.gif

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheers,

Simon
-------------------------------
www.norfolkhelicopterclub.co.uk (http://www.norfolkhelicopterclub.co.uk)
You'll always have as many take-offs as landings, the trick is to be sure you can take-off again ;-)
BTW: I type as I'm thinking, so please don't take any offense at my writing style http://forums.parallax.com/images/smilies/smile.gif

Peter Verkaik
02-27-2008, 06:12 AM
Javelin java is much simpler than pc java: no interfaces or implementations.
It's more like C with classes and objects.

regards peter

simonl
02-27-2008, 06:40 AM
I hear you Peter - I've already downloaded the Javelin doc's and will be studying them over the next few weeks and months I guess.

Thanks again.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheers,

Simon
-------------------------------
www.norfolkhelicopterclub.co.uk (http://www.norfolkhelicopterclub.co.uk)
You'll always have as many take-offs as landings, the trick is to be sure you can take-off again ;-)
BTW: I type as I'm thinking, so please don't take any offense at my writing style http://forums.parallax.com/images/smilies/smile.gif

Ron Sutcliffe
02-27-2008, 10:23 PM
@Peter, Jazzed and others in the Javelin Group.

Hi

I am complete Javelin Novice I have a read of the Javelin Stamp Manual today got the Prop JIDE up and running.

I don't seem to be able to access pins above 0..15, am I missing something ?
Could it be that there are only 16 pins available on Stamp ?
Compile Error Stamp/core/CPU .......no pin19 defined

Regards Ron

Peter Verkaik
02-27-2008, 10:42 PM
The true javelin has 16 I/O pins, and pins SOUT, SIN and ATN.
Those last three are also available on the spinstamp (for System.out.print and Terminal.getChar).
Support for propeller pins 16-31 is scheduled·for later,
that is when all native functions and VP code runs, as if the
propeller was a javelin.

regards peter

Ron Sutcliffe
02-27-2008, 11:45 PM
Peter said "Support for propeller pins 16..31 is schedued for later, that is when all native functions and VP code runs, as if the propeller was a javelin"

That explains everything, thanks.

regards

Ron

Peter Verkaik
02-28-2008, 05:09 AM
Attached is the jvmVirtualPeripheral spin file.
For the DAC I have inserted the vpDac method that needs to be converted
to pasm. This is a very simply task, the pin output is set to the overflowbit
after adding the dutycycle (0-255) to the·accumulator.
The idea is that this code is executed every 8.68 usec if the DAC is installed.

Who can help in translating this method into the most optimized pasm code?
Also, the method isr needs to be converted to pasm. isr the entry routine that
is to be started in a new cog from another spin file.

I also added code for method vpAdc. That too needs to be converted.

regards peter

Post Edited (Peter Verkaik) : 2/27/2008 9:46:22 PM GMT

Kaio
02-28-2008, 08:09 AM
Peter, Jazzed,

a short update from me. I'm currently testing the first PASM bytecode decoder. I have put the bytecode handler til Jem_SWAP in one cog. If I have this sucessfully tested I'll publish it and you could test it with some little Java progs. In the next two days I'm to busy to proceed the testing. But on the weekend I'll have more time.

@Peter
Good progress of coding vp's. It would be helpfully if someone could translate this to assembly.

Thomas

jazzed
02-28-2008, 08:47 AM
@Thomas, Sounds like you have some good progress.
I started looking at VP's in PASM and have at least the Timer working although the native code read/write interface doesn't seem to "get it" -- maybe Peter's example will bring some light. I'll continue following Peter's basic roadmap and the requirements previously discussed, but this is "teeth cutting" for me and my time is limited, so I can't define a delivery timeframe. I have a "curve" to condend with and certain "issues" to work out before I post anything. Wish I could be more timely and direct. Thanks to Insonix their PASD debugger :)

@Hippy, if you re-appear that would be great, but I'm not holding my breath. Hello ???? echo, echo, echo.

@Peter, I now remember other reasons my Javelin collected dust for years. The JIDE debugger doesn't have a "step out" button. That would be quite easy to implement from a JVM point of view given FP accounting. Why don't you do us all a favor and add that button? I also find the, "gee, didn't i hit the step button already?" factor intolerable ... I can see why it's done like that, but a step in source should step, not creep:) If there's anything that can be done, great otherwise <sigh text="oh well"/>

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
02-28-2008, 03:21 PM
@Jazzed,
Stepout might not be so simple. I can not just drop a frame. Currently the step over
puts a breakpoint after an invoke and then just runs.
So what you can do is put a breakpoint on the next source line while stepping into
the current line. The moment you want to step out just hit the run button.
I will have to go through the IDE sources to see if the current debugger structure
allows another 'virtual' breakpoint, without changing the structure setup, as this
is also·used during the linkage process to build the debugger tables.

regards peter

hippy
02-28-2008, 11:29 PM
@ Jazzed, Peter, Kaio, all : Still here, still paying attention. You guys have done astoundingly well and as I had nothing useful I felt I could contribute during recent times I was happy to step back and let those doing well simply get on with it.

Thomas (Kaio) seems to have taken the PASM version of the interpreter on which is great and also has a Java background as well. I'll be happy to throw my input into that as it develops but again I'm largely happy to let Thomas progress without interference. I'm not sure I'm well fitted to PASM coding the Virtual Peripherals as I don't have any Javelin experience.

Development drifted out of my comfort zone of knowledge and experience but with the progress done it's hopefully now mainly a learning curve for me. I've got to get up to date with the latest software and IDE but should be back into the thick of things quite soon and more able to be a useful hand.

deSilva mentioned the need for non-Java, non-Javelin people to have some quick-start guide to using what we have and I'd agree there. Christopher (CJO) seems interested in creating that. Maybe doing that on the Wiki or Whiteboard would be useful so it's not just one person the weight falls on ?

Once I'm up and running, I'll be very happy to contribute what I can. As I'm picking-up from where others would be starting from I'll keep notes on doing that which should hopefully help others get on the PropJavelin bandwagon.

Finally : You guys do realise you've gone from virtually nothing to what we have today in just five weeks ? That is a phenomenal achievement. Well done.

Peter Verkaik
02-28-2008, 11:54 PM
Attached is an updated jvmVirtualPeripheral.
Methods are still coded in spin, but this time I passed the
address of vpRambank to the isr routine which is the main pasm entry.
I believe this is the way to pass variables to an assembly routine.

Apart from the uart routines (at the file end) most code is simular
to SX code, although coded in spin. Only the isr and the private
methods need to be converted to pasm, as these run in a seperate cog.

So the code now never references another file, except jvmData for some
constants.

This should make it easier to convert to pasm.
Also note that now 255 VP types are supported because the vectorbyte
is entirely dedicated to the VP type, with value 0 indicating an empty VP slot.

regards peter

Peter Verkaik
02-29-2008, 11:41 PM
Two updates: jvmData has added methods eeWriteByte and eeReadByte,
these perform the stamp\core\EEPROM.java read() and write() methods.
jvmNative has updated methods readPin, writePin, readPort, writePort,
nap, setInput, setOutput, eeRead, eeWrite·and writeObject.
The last one writes a 16bit value into an implied 16 bits register
that is stored using Big Endian.
The others are updated to support 32 pins. For this I wrote a java file
PROP.java that holds the·pin and port constants for use with the propeller.
That file should be placed in ...\lib\stamp\core folder.

regards peter

··

Ron Sutcliffe
02-29-2008, 11:44 PM
Peter
When I input text to TerminalTest2. For example, if I was to enter cmd or flash, the message window will echo ccmmdd or ffllaasshh, invalid command.
I am a using Prop RPM proto board, wilh USB adapter, hence no flow control. All other output in normal.

Any thoughts.

Ron

Peter Verkaik
02-29-2008, 11:46 PM
Which IDE version are you using? Menu Help->About

regards peter

Ron Sutcliffe
03-01-2008, 12:02 AM
Peter
IDE 2.0.3 and other files per your post of 2/26/2008 @ 3.19
IDE was downloaded from Parallax link which you provided. JMV, Javelin and TerminalTest2 zips from you post.

Menu help...I am looking

regards Ron

Ron Sutcliffe
03-01-2008, 12:19 AM
Peter

IDE Version 2.2.0 Build 4

Ron

Peter Verkaik
03-01-2008, 12:35 AM
Something I forgot, since you have a fresh v2.0.3 installation.
Rename the file Terminal.java in folder ...\lib\stamp\core
to Terminal_org.java
and install the attached version.
Let me know if that resolves the issue.

regards peter

jazzed
03-01-2008, 05:02 AM
Having a little trouble here. Added some CPU write/read verify code
to the tick tocker (private copy) because I suspected reads not working.

Not sure about writes, but reads don't work ... adding some debug code
in the JVM shows that the address/value that should be read are
generally correct, but java never gets the right value.

I just realized my example was horrible. The address would never work.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Post Edited (jazzed) : 2/29/2008 9:24:17 PM GMT

Peter Verkaik
03-01-2008, 05:23 AM
Address 0xE0 is invalid.
The only valid addresses are listed under writeRegister and readRegister in jvmData.
These addresses are all used in core java files, the readRegister and writeRegister
should not be used directly in applications.

I have given the Timer VP in spincode in jvmVirtualPeripheral.

regards peter

deSilva
03-01-2008, 05:27 AM
hippy said...
... deSilva mentioned the need for non-Java, non-Javelin people to have some quick-start guide to using what we have and I'd agree there.

I was especially referring to people WITH some JAVA experience (and implicitely to people WITHOUT ANY Propeller experience)

Explaining JAVA is a lot. The great thing with C and JAVA is that you get it around all corners and you have only to explain the shortcommings ...ahem: "differences" http://forums.parallax.com/images/smilies/smile.gif

Missing "interface" is no good at all. Simple inheritance is not as useful as generally thought, and interfaces have always been JAVA's excuse for missing multiple inheritance....

I just have no time.... If you give me a piece of SPIN and ask me to convert it I shall do.. but nothing else before Easter...

Peter Verkaik
03-01-2008, 05:36 AM
@DeSilva,
We can use abstract classes. I have written many javelin classes and found that is all
that is really needed. You can write an abstract class where just the byte read and write
methods are abstract while the other methods in that class implement something useful,
like a filesystem. All that is then needed to support a filesystem via I2C or Uarts
is just extending the class with the proper read and write methods.

regards peter

jazzed
03-01-2008, 05:37 AM
Peter Verkaik said...
Address 0xE0 is invalid.
The only valid addresses are listed under writeRegister and readRegister in jvmData.
These addresses are all used in core java files, the readRegister and writeRegister
should not be used directly in applications.

I have given the Timer VP in spincode in jvmVirtualPeripheral.

regards peter



Ya, sure I tried 0x80 also. I suggest you to produce a working example with CPU read/write.


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

deSilva
03-01-2008, 05:46 AM
WRT Benchmarking: Speed:

Can someone run this benchmark perhaps on a JAVELINStamp?


PUB spinFibo(n)
if n>2
return spinFibo(n-1)+ spinFibo(n-2)
else
return 1




fibo(29) needed:
On the propeller: 26 sec with SPIN as given
1.8 sec with PHP on my mid-range Windows Notebook
800 ms with a transcript to PASM ( as posted in the "Assembly for Beginners" Sticky http://forums.parallax.com/images/smilies/smile.gif )
30 ms with a very efficient FORTH Implementation on same Notebook
15 ms PureBasic compiled to 16kB EXE-file on same Notebook.

I should expect a JAVA PASM VM (although most likely needing 2 COGs!) running similarly fast as SPIN (there is no reason why not). However it might be interesting to learn how the JAVELIN behaves... The reference should be the 26 secs it takes SPIN on the Propeller.

Note: Don't try fibo(29) with the current JAVA implementation, it could take 1 hour !

Peter Verkaik
03-01-2008, 05:57 AM
@Jazzed,
Attached is my register test program.
Works as expected.

regards peter

Peter Verkaik
03-01-2008, 06:08 AM
@DeSilva,
On a javelin, spinFibo(16) takes 419 milliseconds.
spinFibo(24) takes 19.243 seconds

regards peter

Post Edited (Peter Verkaik) : 2/29/2008 10:13:13 PM GMT

jazzed
03-01-2008, 06:16 AM
Peter Verkaik said...
@Jazzed,
Attached is my register test program.
Works as expected.

regards peter

Thanks for the reference Peter. Will have another look tonight.




▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

deSilva
03-01-2008, 06:17 AM
This is unexpectedly slow!! The Propeller PASM VM could be at least 10 times faster... This should be a motivation http://forums.parallax.com/images/smilies/smile.gif

Ron Sutcliffe
03-01-2008, 08:47 AM
Peter

New version Terminal.java fixed problem.
Will try some of my own stuff now.

Regards

Ron

Peter Verkaik
03-01-2008, 05:47 PM
@DeSilva or any pasm expert,
I attached the latest jvmVirtualPeripheral file.
I added a spin method start from which the pasm code needs to be started
in a seperate cog. All PRI methods are to be converted to pasm. All PUB methods
are initialization routines to set VP parameters.

The shared datastructure among the VP's is vpRambank byte 0[MAX_NUM_VPS*16]
declared in jvmData file. I understand the parameter passed to a cognew must be
a long. We can redefine to vpRambank long 0[MAX_NUM_VPS*4].

For best pasm optimization: Is it better to define vpRambank long 0[MAX_NUM_VPS*16]
so we reserve a long for each register of which only the lower 8 bits are used?

If you could convert only the PRI methods·isr, vpTimer, vpAdc, vpDac and vpPwm
then we would have a beginning. These methods are all very small.
The VP code for uarts can be ignored for now as this need to be revisited because of
the buffering involved.

I noticed all the VP·routines that access pins, use something like:
· pin := >| byte[vpRambank + vpBank + nmDacPin]
· case byte[vpRambank + vpBank + nmDacPort]
··· 1: pin += 8
··· 2: pin += 16
··· 3: pin += 24

I could change the writeRegister method in jvmData to convert the port:pin format
into a binary pin number as used by the prop. That way the VP code does not need
to convert the port:pin format. This saves cycles in the pasm code but it will increase
the writeRegister code. Is it wise to change the writeRegister method?
Edit: I just realized changing writeRegister won't do as it is unknown from where
it is called (Uart, PWM etc). But I can do the conversion of the port:pin format
in the VP initialization routines for the different VP's.

regards peter

Post Edited (Peter Verkaik) : 3/1/2008 10:33:16 AM GMT

hippy
03-02-2008, 03:21 AM
I've found some time to get back into this and am creating a "Fast-Track for PropJavelin" page on the Wiki as I go ...

propeller.wikispaces.com/Fast-Track+for+PropJavelin (http://propeller.wikispaces.com/Fast-Track+for+PropJavelin)

If anyone wants to add anything there they are welcome to. I started from a 'well defined point' which isn't the latest version and will add "bringing things up to date" as necessary.

jazzed
03-02-2008, 05:48 AM
Well, I finally realized that because of at least one bad Javelin java source
design feature (bug) in Timer.java, the virtual peripherals will almost never work
until the JVM is entirely done in asm. Fixing the bug·makes·real-time TickTock work.
The why follows immediately, possible solutions are listed afterwards:

Problem Description:

1. Timer.timeout(hi,lo) ... looks for an exact match in the timer value
rather than an inequality condition that most real-time systems would use.
It is not clear if such programming mistakes are made elsewhere, but
given this example from the "primary" author of the java source, it is likely.

2. For Timer.timout(hi,lo) to have any chance of working in it's current state,
Timer.latch would be responsible for ticking the timer. Well, since it takes
more than 100ms for a bytecode to execute with the .spin JVM, it is unlikely
that the desired result would be obtained in less than 20x the timeout.

3. The further affects of this problem are that since the java code is
apparently managing the VP's closely, devices such as Uart TX/RX will·most
likely be non-functional until the JVM is entirely rewritten in asm.

Possible Solutions:

1. Have JVM fully implemented in PASM ... hopefully this will allow the
current design time enough to function properly. Desired "apparent" solution.

2. Fix time sensitive bugs in Timer.java and other places and have a competent
real-time solution. Fixing java bugs is undesirable for compatibility, but possible.
In any event, I want whatever Peter feels is the right thing to happen because
he is obviously committed to the Javelin product and will have to lay in this bed.



> diff -c12 ~Timer.java Timer.java
*** ~Timer.java Sat Mar 1 13:21:34 2008
--- Timer.java Sat Mar 1 13:45:47 2008
***************
*** 131,154 ****
--- 131,162 ----
// Get the current timer value.
int l = tickLo();
int h = tickHi();
// Calculate the elapsed time since last mark.
if (startHi != 0 || startLo != 0) {
h = h - startHi;
l = l - startLo;
if (!CPU.carry())
h--;
}
+ // Check if elapsed time >= timeout value.
+ int currentTime = (h << 8) | l;
+ int previousTime = (hi << 8) | lo;
+
+ if (currentTime >= previousTime) {
+ return true;
+ }
+
// Check if elapsed time == timeout value.
if (h == hi && l == lo)
return true;





▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
03-02-2008, 06:10 AM
Now that you mention it,
there was a bug in Timer.java that I once fixed.
The constant 119 was used which must be 115.
I am not sure if this 119 error still exists in v2.0.3 IDE distribution·.
(just search Timer.java for 119)

I attached my version that also has an added passedMS() method
that returns the passed milliseconds since the last call to mark().

Just rename your current Timer.java to Timer_org.java and
install the attached version.

I agree that the JVM must be in pasm, as must the VP code, to
make it all work using 8.68 usec ticks.
We must wait for·Thomas what he comes up with.

regards peter

jazzed
03-02-2008, 08:45 AM
Peter Verkaik said...
Now that you mention it,
....

That file is vastly different from the original. Please provide a pointer to the latest stamp/... library.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Ron Sutcliffe
03-02-2008, 09:43 AM
peter

I tried the Tick Tock example a few days ago and could not get it to work.
I guessed the issue might be associated with VP code and the need to write this in PASM. I have undated my Timer.java file and will test again
when the VP code has been ported to PASM. I noticed that you have provided code to implement pins 16..31 on Prop. I have updated files to reflect these updates but still have the same compiler error if Iwhen try to read or write to these pins. Is this still, work in progress?

I have run other some simple code of my own, keeping away from anything in VP and have had no problems.

Ron

Ron Sutcliffe
03-02-2008, 12:09 PM
@jazzed

Thats fine, just lurking and learning, its good to see under the cover whilst you are both working on Javelin Prop.
If it doesn't work I assume its still Work in Progress.


Ron

jazzed
03-02-2008, 01:17 PM
Umm, I removed a post about TickTock; wish I hadn't now. Sorry Ron.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

Peter Verkaik
03-02-2008, 04:31 PM
@Jazzed,
The distribution of v2.0.3 is the latest and most up to date official release.
I have however modified some of the core classes to provide me more methods
or better implemented methods. I attached my core classes that can replace
the v2.0.3 classes.
In case of Timer, I wrote a class ScaledTimer16 that also uses the TickHi() and TickLo()
methods of Timer but then selects only 16bits to create a 16bits timer.
This is the timer I mostly use because you can define the timeunits.

@Ron,
Anything in this thread is a work in progress. The moment we have a fully working
jvm we will create a new thread for a first beta release.

If you install (some of) the modified core classes, make sure to rename the original
files·first, before installing the modified ones.

regards peter

Post Edited (Peter Verkaik) : 3/2/2008 8:40:55 AM GMT

Ron Sutcliffe
03-02-2008, 05:08 PM
@ peter

I have been renaming xyz_org or core_org folder in this case prior to updating

Thanks.

ron

Peter Verkaik
03-02-2008, 10:40 PM
Jazzed,
I updated the jvmVirtualPeripheral by moving the pin conversion code to the
VP initialization routines. This reduces the VP code itself and saves cycles.
I also moved the timer latch code into the timer VP code. The latch method
now only sets a byte to the passed bank value, and then waits for
the timer VP code to clear that byte. At that point the current timer count
is latched and valid.
I think it is sufficient for working VP code to have the PRI methods of
jvmVirtualPeripheral converted to pasm. The VP code only depends on
the 8.68 usec tick, which is generated in method isr. And since isr runs
in itw own cog,·the jvm should work, although less speedy than wanted,
while the jvm is not converted to pasm.

regards peter

Kaio
03-03-2008, 12:28 AM
Peter,

I'm currently working on the second part of byte codes. I'm wonder that the carry variable in jvmData will be set depending on result of some math calculation, but the state is never checked anywhere or I haven't it found yet?

Thomas

Peter Verkaik
03-03-2008, 12:34 AM
It is checked by CPU.carry() method.
(native function 14).

regards peter

Drone
03-03-2008, 03:07 AM
Hi Hippy,

Your Wiki addition "Fast-Track for PropJavelin" is great! But perhaps you could add a bit at the start about what PropJavelin is and how it works. Or at least a link to the pertinent "high-level" description for this application in the "JVM for Prop" thread (that is getting very deep indeed!)

It will help Newbies to this Topic understand just what this is about.

Best Regards, David

hippy
03-03-2008, 03:36 AM
I added a definition for PropJavelin under Propeller Lingo but never thought of that for the actual pages. It's a good point though as I often find things through Google, get to a page and it's not clear exactly what the page relates to.

I've added short explanations, and if anyone feels anything is missing ( there or elsewhere ), don't be afraid to dive in and start adding. No need to register to edit pages. No need to know Wiki markup codes; just type in what's useful and someone will pretty it up later.

propeller.wikispaces.com/Programming+in+Java (http://propeller.wikispaces.com/Programming+in+Java)

As PropJavelin has progressed so well, a lot on that page could be moved to a sub-page so it's primarily for what we do have, not what we might have.

simonl
03-03-2008, 05:58 AM
Hey hippy - I'll 2nd Drone there; excellent wiki page.

Hmm "PropJavelin" - bit of a mouthful, how about "JProp" ?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheers,

Simon
-------------------------------
www.norfolkhelicopterclub.co.uk (http://www.norfolkhelicopterclub.co.uk)
You'll always have as many take-offs as landings, the trick is to be sure you can take-off again ;-)
BTW: I type as I'm thinking, so please don't take any offense at my writing style http://forums.parallax.com/images/smilies/smile.gif

jazzed
03-03-2008, 06:16 AM
simonl said...
Hey hippy - I'll 2nd Drone there; excellent wiki page.

Hmm "PropJavelin" - bit of a mouthful, how about "JProp" ?



I'm quite fond of JavaProp :)


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley (http://en.wikipedia.org/wiki/Silicon_Valley)

Traffic is slow at times, but Parallax orders·always get here fast 8)

hippy
03-03-2008, 06:48 AM
"PropJavelin" ... I thought Peter had called it that, so i just used it, but now think I'm mistaken.

I'm not that keen on it either, doesn't really roll off the tongue.

"JavaProp" has a ring to it, but I suspect Java(TM) brings issues, hence why we have "Javelin Stamp" not "Java Stamp" already.

"JavelinProp" is perhaps better ? Whatever people want, I'll update all the pages. I think it's only courtesy though to give Peter final say or some veto on choices.