@ 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.
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.
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.
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.
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
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.
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.
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 :-(
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.
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 ?
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.
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?
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
@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.
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.
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.
@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 [noparse]:)[/noparse] 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.
@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.
@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.
@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.
@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.
@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.
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 ?
Do you guys use some instant messenger? Would like to talk about software design.
@Hippy, Good progress [noparse]:)[/noparse]
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.
Jeez Hippy, you've implemented practically everything.
No complaints [noparse]:)[/noparse]
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
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?
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[noparse][[/noparse]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.
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.
@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.
Comments
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
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.
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.
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
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
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.
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) ).
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.
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
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
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
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 ?
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.
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
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
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
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.
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
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 [noparse]:)[/noparse] 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.
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
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.
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
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/d69403e2673e611d4cbd3fad6fd1788e
Post Edited (jazzed) : 1/27/2008 7:51:18 PM GMT
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
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 ...
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 ?
@Hippy, Good progress [noparse]:)[/noparse]
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.
No complaints [noparse]:)[/noparse]
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
Post Edited (jazzed) : 1/27/2008 7:04:23 PM GMT
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
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.
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.
I don't see a problem with that. It should be possible to just put "DAT long 0[noparse][[/noparse]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.
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[noparse][[/noparse]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
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.