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 [noparse]:)[/noparse]
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
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.
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.
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.
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
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.
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.
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.
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 [noparse]:)[/noparse]. The hardest part
of asking for any feature is correctly identifying and clearly communicating the requirement.
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.
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.
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.
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.
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("[noparse][[/noparse]JVM] debugging started: pc = $%04x"),1024) ····· comm.status(@buf)
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 [noparse]:)[/noparse] 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.
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.
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.
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
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.
Yes, the registers are not correctly hooked up. I saved that for you to do [noparse]:)[/noparse]
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 [noparse]:)[/noparse] Often other's code appears ugly to us even though the
author thinks it's their best work. You should see the IOS sources [noparse]:)[/noparse]
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 :<
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.
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...ž}ÿ...
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.
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 [noparse]:)[/noparse]
I'm taking the rest of the night off [noparse]:)[/noparse] 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
Comments
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 [noparse]:)[/noparse]
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
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
·
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....
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
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
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.
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
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.
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 [noparse]:)[/noparse]. The hardest part
of asking for any feature is correctly identifying and clearly communicating the requirement.
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
deSilva posted a small I2C driver coded in *.spin
http://forums.parallax.com/showthread.php?p=703283
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
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
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
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
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("[noparse][[/noparse]JVM] debugging started: pc = $%04x"),1024)
····· comm.status(@buf)
regards peter
I'll update more tonight.
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 [noparse]:)[/noparse] 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.
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
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
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
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
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
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 [noparse]:)[/noparse] Often other's code appears ugly to us even though the
author thinks it's their best work. You should see the IOS sources [noparse]:)[/noparse]
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....
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
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.
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.
Back to coding that pays cash for now
--Jazzed
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
Next I will do jvmConvert.
regards peter
Next I will do jvmConst, jvmLoad and jvmStore
regards peter
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 [noparse]:)[/noparse]
I'm taking the rest of the night off [noparse]:)[/noparse] 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