Proposal: indexed addressing
I'm probably not the first who suggests somethig like this... How about adding an indexed addressing mode? There's no need to change anything in the hardware, a simple extension to the assembler/compiler would do.
So MOV dst,src[i]
could be translated to
ALTS i,#src MOV dst,src
...just like MOV dst,##long_const
is translated to an AUGS
/MOV
instruction pair. It would make the code much more readable and avoids errors like accidentally inserting instructions after ALTS/ALTD or branching to the second instruction.
Indexing is useful when processsing multiple instances of data in cog ram or multiple coordinates of a vector. However, I've found out that if there are more than say 4 to 5 accesses that need indexing it's probably easier to swap in and out the whole data structure from/to hub ram using SETQ+RD/WRLONG and then use fixed addressing inside the loop or subroutine.
Comments
It's not the typical indexed addressing - register indirect main memory to register - rather it's prefixed register indirect register to register.
Yep, been suggested before. I've not seen Chip acknowledge the suggestion but I suspected he's likely already mulled it over many years ago during first Pnut development.
It makes skipping a bit more tricky as what appears to be one instruction is actually two. Not an issue if you are not one of the skipperati.
On the subject of assembler changes, how about aliases for
inc
anddec
?That's the same "problem" as in mov dst,##src. We have it already, so nothing new there. Extending the syntax like this
and also writable, as this syntax is used "everywhere"
Skip can be very useful but only in interpreter or simulator like code where the data flow is always the same but different operations need to be performed on the data. The skip mask can then be used to slightly tweak the behaviour of the code to use the same function for different actions. I've used it only once, though. Excessive use of skip creates confusing and messy code and is difficult to debug.
It needs some reading and a lot of practice to get it right but the P2 instruction set has an awful lot of cool features. I've just used the xorc option for the first time
to detect a change in direction. The best thing is that the two sign bits are stored in completely different locations so a normal XOR instruction wouldn't work.
I do like the conditional execution flexibility. It allows a just little more execution complexity before reverting to branches or something more formal.
Check out compiler output from flexspin. At some point I improved the branch conversion pass to be able to stack multiple condition sequences into and onto eachother and now you can sometimes find a beautiful mountain of if conditions.
Speaking of, introducing special syntax for ALTx would be convenient, but might make some of the neater tricks less discoverable.
The new syntax is just an alias. It doesn't force anybody to use it. If you please you can still continue to use the old more verbose syntax.
Yes, and real programmers don't document. If it was hard to write it should be hard to read!
Nice. That could be written as
MOV dst,src[i++]
. But the increment step could be more than just 1.MOV dst,src[i+=5]
is misleading as it's a post-increment and the C-like syntax would presume a pre-increment.If you ever want to jump if bit 31 of a register is not the same as C, then
TJV D,{#}S
does that in one instruction and without changing C. TJV means "test and jump if overflow" but it is not limited to signed arithmetic and C could be derived from anything. (TJNV does not exist because it would be a waste of a valuable instruction slot.)Ah, interesting. But in the case above it wouldn't help. First, the "..." stands for some lines of code that do different things. The wcz after abs is "for free" but only if the sequence stays the same, i.e. bit #31 of newVel must be tested before bit [axis] of oldDir. Second, I need to jump if both sign flags are equal OR newVel is zero. (newVel==0 is treated as "neutral" instead of being positive, it doesn't trigger a direction change regardless of the old sign). That's not possible with TJV. But good to know.
Maybe add some explicit syntax to make it clearer that there are two instructions involved, something like:
where the
@@
acts as a visual marker like##
? This shouldn't conflict with the use of@@
in Spin code, since@@
isn't really useful in PASM.Brackets for indexing could be added.
I have thought about this a few times, but it always seems to get complicated as I work out the details.
Nice! Can't say I've been inspecting any compiled C logic of late though.
Great!
Of course, there are some trapdoors that need attention like instruction counts for REP and SKIP. But I think those are no different from the already existing ##->AUGS/D mechanism.
BTW, there are roumors that Parallax won't invest much time into compiler development in the future. I hope that affects only Propeller Tool? So the preferred/supported toolset will be VSC + PNut?
Post-increment and other modifications aren't very practical to write with this notation though, because they require bits 9 and above (i.e. cannot be accessed with regular immediates). Does AUGS work on ALTS/ALTD? If so I suppose the assembler could emit 3 instructions for
mov r, a[i++]
, but that's starting to get cumbersome.No, causes bug where AUGS stays latched and affects some other instruction down the line.
Just an idea: Might some macro preprocessor give similar (and more) possibibilities as the proposed modification of the assembler?
alts seems to have auto increment builtin, so if i is a register, 2 instructions are enough
But the
i
is the destination inalts i, #a
, and the immediate has only 9 bits (so Source[17:9] will always be 0).Using auto increment only really makes sense in the context of a loop, preferably using the same index increment for each step.
With the example of
mov r, a[i++]
, the way to handle it elegantly is to set up the base pointer prior to entry into the loop:Then inside the loop:
This gives a simple two instruction auto increment per instance with a two instruction setup, but that complicates the state tracking. It is certainly beyond what you could ask of an assembler without macro capabilities.
If you want to auto increment by different amounts within the loop that will require a
setd
for every change. It would make more sense to directly manipulate the index in those circumstances (as ugly as that looks.)Bringing this back to the original suggestion, how’s this for a compromise between function and simplicity?
mov dst, src[i]
becomesand the programmer retains responsibility for presetting the content of src with a base pointer and any auto increment value,
while
mov dst, #src[i]
becomesI continue to work on the compiler. It's the IDE that we are hoping VSC can replace. Or, the expectation of editor quality exceeds what we can keep up with, so we think VSC may become the center of the tool system.
Ok, thanks. There are some minor features that the VSC+PNut combination doesn't provide at the moment such as displaying the cog ram address of labels in DAT sections for use with the PASM debugger. But I think this should be no big problem to be sorted out.