Multiple PASM Objects Into One PASM Cog
pjv
Posts: 1,903
Hi All;
I'm still learning Spin here, so I may be not on the best path...
What I'm trying to do is to load several PASM objects into a single PASM cog. The loading (Spin) cog will pull the objects in sequentially as they are listed. Inbetween the loaded objects appear the object header(s) which don't seem to cause much of a problem. What I am not finding an easy solution for is that each object gets compiled with an ORG of 0, and since they are located sequentially into the operating cog, the object's address references are messed up. I'm wanting to avoid placing special ORGs into each object as that would become a nightmare while developing code. Nor do I want to combine all the objects into a single super-object as that will ruin the flexibility I'm looking for.
What I can do, is load the objects via a PASM program and have it re-locate the addresses, but that is also a bit messy, and I was also wanting to keep all this rather Spin friendly........
Does anyone have any tricks or advice ?
Many thanks,
Peter (pjv)
I'm still learning Spin here, so I may be not on the best path...
What I'm trying to do is to load several PASM objects into a single PASM cog. The loading (Spin) cog will pull the objects in sequentially as they are listed. Inbetween the loaded objects appear the object header(s) which don't seem to cause much of a problem. What I am not finding an easy solution for is that each object gets compiled with an ORG of 0, and since they are located sequentially into the operating cog, the object's address references are messed up. I'm wanting to avoid placing special ORGs into each object as that would become a nightmare while developing code. Nor do I want to combine all the objects into a single super-object as that will ruin the flexibility I'm looking for.
What I can do, is load the objects via a PASM program and have it re-locate the addresses, but that is also a bit messy, and I was also wanting to keep all this rather Spin friendly........
Does anyone have any tricks or advice ?
Many thanks,
Peter (pjv)
Comments
-Phil
Marko, what you are describing is almost precisely what I do when I'm doing relocation in assembler, and it works great. Yours uses Spin to do the relocation, but the same principles apply. I had not considered doing that in Spin as it it is much slower (100x) than what I am looking for.... dynamically loading code into a cog while that cog is already running other code. In assembler the concept does operate quite well, loading and relocating small code segments in in the equivalent time of one, or a couple of, Spin instructions. So when Spin triggers driver code to be loaded, it's done by the time the next (few) Spin instructions are executed.
What I was hoping for was some technique in Spin that was unknown to me (newbie in this realm) that permitted over-riding the ORG directive or some other approach that would result in a contiguous address space among objects at compile time, eliminating the need for Spin-programmed relocation.
While my ultimate goal is much along the line of what my PASM approach is, I was wanting to mimic similar results in Spin.
Thank you both for your comments.
Cheers,
Peter (pjv)
After re-reading your original post, that would work against you wanting to avoid a single object. And IIRC spreading them over separate objects will force you to use specific (hard-wired) orgs anyway. Even if there was a way, the load order would be effectively hard-coded and you wouldn't be able to dynamically re-arrange them (e.g. don't need module A, load C instead) without relocation?! Or does it work like module A is always loaded at offset OA?
Thanks for your comments, and I believe I should be clearer in my post.
There are two things I am working on, the principal one being an assembler based scheduler encompassing a loader, all running in a single cog. The scheduler orchestrates an orderly distribution of cog compute cycles on an as-needed basis to numerous threads running simultaneously in the same cog. Meanwhile, the loader continuously monitors a hub mailbox looking for commands such as loading, dismissing or editing thread parameters in the cog. This is working well, but I still want to clean up some rough edges, and make the external mailbox interface a bit more "Spin friendly" so that numerous Spin programs accessing the programs (mostly drivers) in the cog will not trip over each other.
The second thing is, while working on this it occurred to me that, to a degree at least, a somewhat similar feature might be possible through loading the scheduler plus multiple assembler objects (like drivers) into a single cog with a COGNEW/COGINIT, but without the dynamic loader concept. And I would look to do that without messing with the internals of the objects.... just string one behind the other in the launcher's OBJ definition section. And here is where I ran into the ORG snag. Each canned object, being its own entity, and not wanting to mess with its internals, conflicts with the ORG of the following objects, and hence simple sequential loading does not appear possible. If Parallax could, or would, modify the compiler so that it does not automatically reset the ORG to zero at the start of each object, but rather lets the programmer explicitly change or keep the ORGs when he wants to. Better yet would be for the compiler to start ORG at zero for the first object, but not re-zero it if it encountered an "ORG $" at the start of any following objects.
Without that, I'm not sure if I can solve this one, or if it's worth a lot of effort, but I thank you both for your insight and comments.
Cheers,
Peter (pjv)
Okay, I think I understand what you want to do. You have a collection of PASM functions F1, F2, F3... and you want to dynamically choose a set of functions, then COGINIT them. Your challenge is PASM is statically addressed, which is a function of the ISA - not the ORG. Let me explain:
Normally PASM code starts with ORG 0 because the first instruction is always loaded into "register" 0. Now say, for example, you used ORG $100 instead. Then the code would be assembled to JMPRET NZ NC NR IF_ALWAYS $000 #$100, which would do the same thing if loaded into register $100, but if loaded into any other register would just jump to whatever instruction is stored in register $100. Other ISAs have relative addressing (particularly branch on condition), but PASM doesn't. So you'd need to code "helpers" at fixed locations.
The usual way to accomplish your task is via overlays where each function uses the same ORG and is always loaded into the same location. Or you could have multiple copies of each routine, each with a different ORG.
To have position independent code you'd need to first allocate your working variables at fixed registers. Then for jumps (and MOVisd, or other self-modifying code) you'd need a "helper" function at a fixed location, e.g.
Alternately you could implement a loader which would add an offset to the destination register and the source register if the immediate flag isn't set (except in the case of JMPRET).
Whatever you do, there will be significant latency on top of the COGINIT delay to create the DAT block, especially since each instruction will need to be copied between HUB RAM locations. It would be somewhat faster if the COG did the job itself.