Shop OBEX P1 Docs P2 Docs Learn Events
Spin feature request — Parallax Forums

Spin feature request

stevenmess2004stevenmess2004 Posts: 1,102
edited 2008-02-27 05:03 in Propeller 1
Is it possible to do the following in spin

Load an object from an SD card
run methods in that object

The first bit is relatively easy but the second will require a new function something like
runFunc(objectAddress,methodNumber,arg1,arg2....)

I realize that there would probably be no checking able to be done when compiled, but, imagine what could be done.

We could turn something like propdos into a proper OS instead of just a program that has to reboot the chip every time we want to change programs (not having a go at propdos, it's great, just making an observation).


Steven
«13

Comments

  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2008-01-02 21:57
    I would love to see this done! You're right, PropDOS would take on a whole new level with this..

    For all that matter this would uncap memory limitations for all kinds of interesting uses..

    OBC

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    New to the Propeller?

    Getting started with the Protoboard? - Propeller Cookbook
    Got an SD card? - PropDOS
    A Living Propeller FAQ - The Propeller Wiki
    (Got the Knowledge? Got a Moment? Add something today!)

  • Ym2413aYm2413a Posts: 630
    edited 2008-01-03 00:33
    Interesting, I was thinking of the same thing not that long ago.
    Although this could be done in some way or another. A simple design would load pASM code into the HUB-RAM and then lunch it. [noparse]:)[/noparse]

    This PASM loader would work for simple things.
    Spin would be a different story.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Share the knowledge: propeller.wikispaces.com
    Lets make some music: www.andrewarsenault.com/hss

  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-03 09:16
    Just guessing, it could probably be done with the current interpreter and so would only be a change to the prop tool. If the interpreter on the prop can't do it than maybe hippy's can. smile.gif The problem with that is that then we would need another spin compiler.

    Changes to the prop tool shouldn't be too much. Just another keyword and the ability to compile spin code without the 16 (byte?) header.

    Do any of the games around do this kind of thing?
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2008-01-03 14:51
    If the only problem is the header, couldn't it be removed and the code placed on the SD?
    Might be accomplished quicker to create a working model of what you have in mind....

    OBC

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    New to the Propeller?

    Getting started with the Protoboard? - Propeller Cookbook
    Got an SD card? - PropDOS
    A Living Propeller FAQ - The Propeller Wiki
    (Got the Knowledge? Got a Moment? Add something today!)

  • hippyhippy Posts: 1,981
    edited 2008-01-03 15:43
    @ stevenmess2004, et al

    I have been thinking about this; it seems a good idea but my first thoughts are, that could be hard. Two problems to overcome; where to load the object and how to link / call into it.

    An executing image consists of Spin/PASM/DAT code from $0000 up, followed by VAR variable space, followed by stack up to $FFFF. Unless space were pre-allocated ( how big ? ) using a dummy object any loaded objects would have to be placed at end of RAM with perhaps some extra space added for object's stack. Some variable would need to exist to point to the first loaded object and each object would have to daisy chain to the next as a linked list. The pointer to the first could be any variable in the user program but a long at RAM top would perhaps be a better place.

    Calling a loaded object could be done by specifying two numbers; the first the number of object as loaded and the second as an index into the list of methods to call. Both have difficulties because multi-cog programs could each be loading their own required objects so the order isn't known and a loaded object may load its own objects so the loaded order number cannot be a constant at compile time. For the method number indexing, PUB's are counted in the order they appear in source so it makes manually determining the index awkward and prone to error if anything changes ( 'DLL hell' ).

    A good mechanism would be a call which allows the 'name' of the target called to be specified ( both object name and method name ). This could be a 32-bit signature ( four ascii chars, five 6-bit chars, six 5-bit chars ? ). Matching signatures would be held in each object and method. Calls 'by name' would be fixed-up on first execution self-modifying the Spin bytecode.

    Obviously there's quite a lot of work there to be done and that is perhaps too much for the ROM Interpreter. An alternative interpreter could do it, but then so too could Spin or a Spin Object. I'd favour a Spin Object loading objects simply for the ease of debugging.

    It requires some understanding of object image format but a Proof of Concept should be possible with what we have; include an object, copy it to top of RAM, use it from there. Named fix-ups can come later and requires some detailed knowledge of Spin bytecode and run-time stack use, and a Propeller Tool means of creating a 32-bit named signature in-source would help there.
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2008-01-03 21:01
    Why not rewrite the eeprom and reset?
  • hippyhippy Posts: 1,981
    edited 2008-01-03 22:59
    stevenmess2004 said...
    We could turn something like propdos into a proper OS instead of just a program that has to reboot the chip every time we want to change programs (not having a go at propdos, it's great, just making an observation)

    If this is just a way to get a program into memory and executing then thinking in terms of dynamically loaded objects is perhaps wrong, although related. A main program is an object in its own right with an additional prefix. All objects are, unless I'm wrong, coded for position independence so why not just load them higher up in memory and execute them ?

    It's a bit more complex in practice but probably not as complex as full dynamic object loading.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-05 04:02
    With much experimenting and some of hippy's very useful documentation on spin objects.

    You can move spin objects around in memory and still run the methods in them although it is a bit of mucking around with pointers.

    The attached program demonstrates moving an object, setting it's all the bits where it was originally stored to zero and then running some methods in the object.

    Don't know what will happen if you try to access things in the VAR or DAT sections of the moved object yet so there is still plenty more to do but this is an encouraging start.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-05 05:38
    Just tried accessing things in VAR and DAT sections and they still seem to work (only tried in GEAR so far, not on a prop yet.)

    See attached

    Accessing things in the HUB from asm routines might be a different matter though.

    Post Edited (stevenmess2004) : 1/5/2008 8:02:17 AM GMT
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-05 05:48
    hippy, do you have any more info on the CALLOBJ spin opcode? Does it just call an object from the vector table in the current object, or does it go to the top object and follow the pointers to the next object from there?
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-05 08:15
    OK, you can also play around with the pointers so that they point to another object. See attached. The first lot of calls goes to testObj1 and the second lot goes to testObj2.

    I think that this is just about everything we need to dynamically load objects. Steps would be

    1. Load object into some free space
    2. Change pointer to next object in the just loaded object to point to the next object or start of VAR section
    3. Change sub object pointer in main program from dummy object to object that has just been loaded
    4. Change pointer in object before dummy object to point to the object that has just been loaded
    5. Adjust VAR offset in new object to point to some empty space (needs more research)

    These should probably all be done in a single method so that spin doesn't go into some weird place.

    Depending on how spin handles sub-object calls, the new object could even be a group of objects. With a bit more playing around, it may even be possible to allow the new object access to already loaded objects (such as keyboard, display drivers).
  • Sleazy - GSleazy - G Posts: 79
    edited 2008-01-05 09:17
    Cant femtobasic run spin progs from sd? whats the problem?
  • hippyhippy Posts: 1,981
    edited 2008-01-05 16:23
    @ stevenmess2004 : Well done for taking the initiative and diving in there. I haven't read your code yet, so you may already know all this, but the info I have is ...

    There are four 'base pointers' used by the Spin Interpreter ...

    Memory Base, always $0000
    Object Base, $0010 for the main program
    Variable Base, address of first VAR for the object
    Local Variable Base, address of first local variable for current method ( subroutine, function )

    All operations within the Spin Interpreter are relative to one of those bases. The 'result' variable is always the first local variable, parameters/arguments follow, then local variables.

    Every object ( and main program ) starts with a 'method pointer table' which indicates where a PUB or PRI method is, and where other objects are located.

    CALLOBJ has two operands, the first is an index into the current object's 'method pointer table', each entry is two words ( one long ) so CALLOBJ +5,+? means find the 5th entry after the first entry of the table ( +0 is the first entry ).

    The first word there gives the object base of where the 'method pointer table' is in hub memory for the called object ( relative to the calling object's own 'object base' - $10 for the main program - so add $10 to it to find the actual hub address of the called object's 'method pointer table' ).

    The second word is a byte count adjustment which needs to be added to the existing 'Variable Base'.

    To enter an object's method, CALLOBJ locates the entry in the 'method pointer table', saves the current Object Base and Variable Base to stack, adjusts both of those according to the entry found.

    It then uses the second operand to determine which method to execute for the new object. Again this is the same indexing into the ( sub-object's now ) 'method pointer table', the first word giving the address of the method ( offset by by the (sub-) Object Base ). The second word is a byte count of how much to increase the Stack Pointer, this reserves space for local variables.

    Returning is a simple (!) matter of restoring Object, Variable and Local Bases to what they were prior to the call.

    A look into AiChip_SpinVm_XXX.spin at FRAME/CALL/CALLOBJ should help clarify the exact workings. It was quite a slog getting that to work. What I push into a stack frame isn't exactly what the ROM Spin Interpreter does but does seem to work and is very close.


    In theory it should be possible to include a dummy object in the main program ( eg, PropDos ) with just a PUB Main, then when an object needs to be loaded, the entry in the 'method pointer table' for the dummy object can be patched-up to point to the object being called. Thus a 'dummy.Main' call will become a call to 'loadedObject.Main'.

    The only difficulty is that the adjustment to the Variable Base would probably ( I haven't investigated ) plonk the new object's variable's in the existing stack space used by PropDos. This shouldn't be a problem and can probably be overcome. One solution may be to Abort right back to PUB Main, trap the abort, call dummy.Main then restart SpinDos when it completes ...

    PUB Main
      repeat
        \PropDos
        dummy.Main
    
    
    



    As to the issue of the 'method pointer table' +0 entries forming a linked list of objects, I haven't determined why. If it wasn't needed it wouldn't likely be there, so there is probably some reason for it. It may explain the difference between SpinVm stack framing and the ROM Interpreter's.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-06 08:20
    @Sleazy yes it can, so can Oldbitcollector's propDos. But what if we want to be able to dynamically load objects? I am try to dynamically load objects and then allow all the different objects to communicate and I think that I have nearly achieved this.

    @hippy Thanks for the info. smile.gif

    Just a couple other things
    1. In the current implementation of spin, objects have a maximum of 32kB of program and 32kB of VAR. That means that the compiler, interpreter and object will have to change for the propII.


    Here is a new copy of dynobj. This one demonstrates moving an objects VAR section around. Again, I haven't tried this on a prop yet, just in GEAR.

    And now, I think I can make this work
    Dynamic loading of objects from an SD card, with all dynamically loaded objects able to call other dynamically loaded objects. It is simply (!) a matter of a small amount of self modifying spin code. (That I think I can do)

    Have a look at DOL.spin and testObj.spin and tell me what you think. They aren't finished yet but it would be helpful to get feedback because its easier to make changes now than later.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-06 10:40
    Here is the first working (kind of) copy of DOL. At the moment it just moves an object included in it around but it is demonstrating everything that we need to load objects. Haven't test calling DOL from the test object yet but hopefully that will work. Also, the VAR adjustment doesn't seem to be working yet. So there is still plenty to work on but this is a good start.

    Any suggestions?
  • hippyhippy Posts: 1,981
    edited 2008-01-06 15:38
    stevenmess2004 said...
    Just a couple other things
    1. In the current implementation of spin, objects have a maximum of 32kB of program and 32kB of VAR. That means that the compiler, interpreter and object will have to change for the propII.

    Almost certainly. I was thinking about that when writing SpinVM. At the moment word variables are often used to hold addresses and pointers ( 64KB addressing) and the Prop II will likely have 256KB.

    That may not be such a problem though as objects, variable areas, stack bases are all aligned on long boundaries, so the bottom two lsb's are always zeroed, leaving only 14-bit data. 256KB requires 18-bit addressing but also long aligned so only 16-bits are actually needed. The 18-bit address can be stored right-shifted into 16-bit words and then left-shifted when needed for use.

    However, if the pointer needs to point into ROM, above 256KB presumably, 18-bits isn't good enough, so words cannot be used unless alignments are adjusted to being double-long ( 64-bit ) aligned.

    Words could still be used as pointers but with different usage. I think it will depend on how easy it is to alter the Spin Interpreter whether the same word-sized pointers are used or long-sized pointers.

    The biggest impact is going to be on user code, and especially code in the Object Exchange, which may not work on the Prop II; no one can guarantee where an object/variable will be in memory, above or below the 64KB. Any code using word variables as pointers is going to run into potential problems. PASM coders aren't immune from problems either. I've started a separate thread on addressing that issue.
  • hippyhippy Posts: 1,981
    edited 2008-01-06 15:43
    Another 'limitation' of current Spin is that an object / main program can only have 255 methods plus object references. The operands for CALL and CALLOBJ are fixed byte-sized. That too could change.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-07 11:23
    Okay, DOL V_001 had a bug in that caused it to not do what I that it was but I fixed that. Here is a new version that runs Chips VGA_Text_Demo. It is still nowhere near finished until I can track down a couple of bugs. Moving the VAR section is not done yet but I think that once I get these couple of bugs fixed that will be easy.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-08 07:12
    Here is a new version of DOL that actually works properly (well at least in GEAR). Fixed a whole heap of bugs in how I was using the pointers to different things. This treats DYN_VGA_Text_Demo as if we are loading it and then calls some functions in it. Next job is to move the VAR section.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-08 10:55
    New version of DOL. Actually V_005 (V_004 was just a small change). This one moves the object as if it has been loaded, adjusts the VAR section for the test object to the end of the object and then also calls a method back in the top level object. And I have also tested it on a propeller and it works.

    Next is to try combining objectStartPtr and objectVARBase into a long so that calling other objects will be quicker. After that will be working from an SD card.

    I'm starting too get excited about this. We will be able to do fun things like event driven code with listeners and events and stuff. smile.gif

    Steven
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-08 11:04
    I should say. The 'acalled methodRunner!!!" shows that we are in the DYN_VGA_Text_Demo method selector. The address0001 and next address that we have called the top object and got a value back. And the last two address that we called the object again to display a number.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-09 10:49
    Here is a new version of DOL that uses Peter's heap manager and also has some constants defined for some of the things we need to be able to run (like a method to run the objectsmile.gif). I have given up the idea of combining the objectVARBase and objectStartPtr into a long because I need the address for use with the heap.

    Maybe someone with more knowledge can help me on one point though. In Peter's heap object on line 168 there is (was) a return. However, it never returned and just did the return at the end of the method. I changed it to an abort and it works fine. Does anyone know why?
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2008-01-09 11:24
    Check the value you pass to allocate. It must be less or equal than the
    largest available block and also > 0.
    if (trytoallocate > heap.available)
    · error(string("out of heap memory")
    else
    · if (trytoallocate =< 0)
    ··· error (string("illegal value"))
    · else
    ··· addr := heap.allocate(trytoallocate)

    where trytoallocate is the number of bytes that you would like to allocate.

    regards peter
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-09 11:30
    It's not that. The value that is getting passed is around 1700 and I have allocated an array of 4096*4 bytes. What really puzzeles me is that if I put a return anywhere in the method it doesn't return back to the calling method, it just goes the the end return and returns 0. What is really weird is that if you change any of the returns to aborts then they work. I put different values for all the different returns I tried and they were just getting skipped over.
  • simonlsimonl Posts: 866
    edited 2008-01-09 11:33
    Hi Steven,

    Just to let you know, I've been watching this thread - what you're doing looks really interesting; I'm sure others are watching too, in eager anticipation of the SD card integration. This appears to have HUGE possibilities for writing larger spin code, and could be something even _I_ could use (unlike the various LMMs which are PASM only).

    Keep up the good work - I'll be lurking on this thread from time-to-time.

    BTW: Can I make an early request for a step-by-step tutorial? I'd be happy to test-drive it / help write it; just let me know when you feel the time's right wink.gif

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

    Simon
    www.norfolkhelicopterclub.co.uk
    You'll always have as many take-offs as landings, the trick is to be sure you can take-off again ;-)
    BTW: I type as I'm thinking, so please don't take any offense at my writing style smile.gif
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2008-01-09 11:37
    What if you put a call to allocate directly after the call to create?
    Do you then get·a value other then 0? (you should)

    regards peter
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-09 11:37
    @simonl: If you have an SD card hooked up to your prop, some help soon would be greatly appreciated. I haven't got mine hooked up yet. Hopefully in another couple of nights I can get it to testing on SD card stage.

    Steven
  • simonlsimonl Posts: 866
    edited 2008-01-09 11:44
    @steven: Yup - all hooked-up and ready to go smile.gif

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

    Simon
    www.norfolkhelicopterclub.co.uk
    You'll always have as many take-offs as landings, the trick is to be sure you can take-off again ;-)
    BTW: I type as I'm thinking, so please don't take any offense at my writing style smile.gif
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-01-09 11:49
    @Peter, I don't know what I did but I just got it working. Code that was given me the wrong results an hour ago and hasn't been changed just started giving me the right result. Wouldn't have a clue what happened. Sorry for the trouble I caused you.

    Steven
Sign In or Register to comment.