This is a bug in the program code, I think. The variable x is declared as:
x res 1
which does not initialize it, just reserves some space for it (in COG memory... "res" does nothing to HUB memory!). It'll have as an initial value whatever happens to be in HUB memory after the label; in this case it'll be the first instruction of the PropCam_Acq function.
But in the actual code x appears to be used without being explicitly set, so that initial value will determine the behavior of the program. The first use of x I see is in this loop:
doVga
rdfast #0,##$1000-$400 'load .bmp palette into lut
rep @.end,#$100
rflong y
shl y,#8
wrlut y,x
add x,#1
.end
x is used as the index into LUT for writing, but since it is not set first the results will depend on the contents of HUB memory.
This explains why everything works if the first instruction after PropCam_Acq is "nop"; in that case x happens to be initialized to the bit pattern of the nop instruction, which is all 0. It also works if you change the "x res 1" to "x long 0", for a similar reason (now x is initialized to 0), or if there's an "orgh" before PropCam_Acq (orgh pads with 0). Another fix would be to insert "mov x, #0" before the rep loop.
I think ORGH needs to bump the adress to at least $400 to get around these ambiguities.
This particular example didn't have anyting to do with ORGH, except accidentally -- it was just use of an uninitialized variable.
I'm changing PNut.exe to separate the ORGH address from the actual object code address.
What exactly do you mean by that, Chip? Do you mean that labels will now have 3 values, their default value, notional hub value as set by ORGH, and actual location in HUB memory? This seems like it could get very confusing. I think one of the things people didn't like in P1 was that "@label" had different meanings in Spin and PASM; in Spin it gave you the actual HUB location, but in PASM it just gave you an offset of sorts. It would be nice to fix that in P2.
BTW: "RES" is nothing but trouble. It's too easy to get caught putting variables after a RES and messing up your code.
And here, we see how it can really mess you up if you don't realize it's not initiated...
I'm trying to think if RES serves any use that justifies itself..
In fastspin at least "orgh 0" will only work if it's the very first thing in the program. Otherwise you'd be asking the assembler to go backwards, which would be impossible.
I think the way it works now (but could be wrong) is that
ORGH X
tries to start code at X in HUB memory with X being made to be at least $400.
This seems to be working just fine for me...
In fastspin (and I'm pretty sure the other assemblers) "ORGH X" will try to insert padding to make sure the code/data will start at location X in hub memory. If there is already more than X bytes of things in HUB then it will report an error. There's no special case for $400.
Note that unlike ORG, just plain ORGH on its own is *not* the same as "ORGH 0". Just "ORGH" with no number says "labels defined after this point are in HUB memory", but it doesn't change the hub memory location. So in:
ORGH 0 ' first thing
ORG 0 ' COG labels
x nop
y nop
ORGH ' HUB labels
z nop
"x" has the value 0, "y" as the value 1 (it's a COG address), but "z" has the value 8 (it's a HUB address). If the ORGH wasn't there, "z" would have the value 2.
Hmm... In that case, I'm surprised I didn't have an issue with "ORGH" yet...
I thought there were some things that don't work if address is below $400.
What was it? I think it was something about a relative vs. hub address...
Or, maybe it is hubexec code doesn't work if below $400 ?...
BTW: "RES" is nothing but trouble. It's too easy to get caught putting variables after a RES and messing up your code.
And here, we see how it can really mess you up if you don't realize it's not initiated...
I'm trying to think if RES serves any use that justifies itself..
You have to use RES carefully, but it does have uses. The main one is that it allows you to declare variables that you know will be initialized from elsewhere (e.g. data read from pins or SD card) without requiring that space be allocated in the binary. That can save a lot on load time, and also lets you fit more things into HUB RAM. For example:
x res 100
reserves space for 400 longs at runtime, but since it's not initialized you don't have to download that to the P2, and if it's in an ORG section it consumes no extra HUB RAM; whereas
x long 100[0]
makes your .binary file 400 bytes larger. In some cases this could be the difference between having code that fits in memory and not.
I also ran into the issue with x not being initialized. I posted a thread about this called Minor issue with VGA_640_x_480_8bpp.spin2 and VGA_640_x_480_16bpp.spin2. It worked OK in the original programs because the ORGH caused the memory to be padded out with zeros. However, if you put code immediately after x and y the memory will be nonzero.
The RES instruction should be used with care. If a variable is required to be initialize to zero it is better to use "long 0" instead of using res, and then depend on the assembler to pad with zeros.
For assembler mode, like PNut.exe works in right now, nothing will change.
For Spin2 mode, though, there isn't going to be controllable absolute addresses because of how objects build. So, in the case if Spin2 mode, ORGH will only affect the assembler-aware origin, and will default to $400, and not allow addresses below $400.
I would argue that you could just use FIT to achieve the same purpose with less risk...
But, I do use RES, I'm just very careful with it after having been burned more than once.
I think there is room for both, but they need to be very clear about what they actually do, and where they are doing it !!
As P2 is totally RAM based, there are code-gains to be had, by declaring a VAR and initialising it at the same time.
Flash based MCUs have to load any initialized RAM vars, which costs time and code space.
Some MCUs sweep RAM to clear to 0x00, as part of their init code. That approach does reduce code size and helps avoid 'oops' bugs.
Arrays that are declared maybe should have an option to load a known value ?
As mentioned above, large arrays could have a download cost, if their value is really don't care.
Why can’t res vars be relocated to after declared registers?
The assembler would have to group them up under each ORG and arrange them before the end of the DAT block or before the next ORG or ORGH. It's a lot simpler to just place them manually and understand what they do.
The RES directive is not a new directive for P2.
It's has been used extensively in P1 code.
The P1 manual explains it's use and even includes this statement.
For assembler mode, like PNut.exe works in right now, nothing will change.
For Spin2 mode, though, there isn't going to be controllable absolute addresses because of how objects build. So, in the case if Spin2 mode, ORGH will only affect the assembler-aware origin, and will default to $400, and not allow addresses below $400.
I would urge you to think about this again. Addresses were one of the problem points in Spin 1; I think people often tripped over the difference between @ in Spin and PASM. I know that making @ working as expected in mixed PASM and Spin is difficult. But it is possible -- homespun and bstc did it, for example (although they had to invent a new syntax, @ @ @, to maintain Spin compatibility).
Correct, code in a method can use (at)image to get the absolute hub address of a DAT symbol "image". (Code in a DAT section would have to use a more complicated method involving a run-time fixup, unless you're using bstc or fastspin, in which case triple (at) will do the trick.)
Seems the triple is only for PASM sections?
But, I think the tools right now already give us the absolute address of things when inside a PASM section.
Correct, code in a method can use (at)image to get the absolute hub address of a DAT symbol "image". (Code in a DAT section would have to use a more complicated method involving a run-time fixup, unless you're using bstc or fastspin, in which case triple (at) will do the trick.)
Seems the triple is only for PASM sections?
But, I think the tools right now already give us the absolute address of things when inside a PASM section.
Not in Spin 1. On the Propeller 1, @ inside a DAT section always meant an address relative to the start of the DAT section. Right now in P2 code this is different and @ means absolute address, but I think Chip was talking about making Spin 2 act like Spin 1. I think this could end up being very confusing.
In Spin2, hub-exec PASM code can be ORGH'd at any address >= $400, but it will never wind up there after compilation. With relative addressing modes within PASM blocks, though, all you'd need to know is the entry address, which is absolute and easy to determine at runtime, but not as ORGH'd. As objects are stacked together, there's no telling where some block of PASM code is going to wind up.
Am I missing something?
We'd have to have some kind of linker step to afford absolute addressing between uncommonly ORGH'd blocks of PASM code, right? It seems way more trouble than it's worth if we can determine an entry-point at run time and just use that, instead.
Ok, that's mostly what I do now, except for the VGA bitmap, etc.
There we currently rely on the orgh value, I think, so that would have to change somehow...
Couldn't there be two types of DAT sections with one type connected to a Spin object, and the other independent of an object? The independent one would look like what we have now with absolute addresses. The other type would look like the Spin1 DAT sections, where the addresses are relative to the start of the object.
EDIT: Maybe the independent DAT section could contain global symbols that any object could directly address. That's a feature that would have been useful in Spin1.
Comments
But in the actual code x appears to be used without being explicitly set, so that initial value will determine the behavior of the program. The first use of x I see is in this loop: x is used as the index into LUT for writing, but since it is not set first the results will depend on the contents of HUB memory.
This explains why everything works if the first instruction after PropCam_Acq is "nop"; in that case x happens to be initialized to the bit pattern of the nop instruction, which is all 0. It also works if you change the "x res 1" to "x long 0", for a similar reason (now x is initialized to 0), or if there's an "orgh" before PropCam_Acq (orgh pads with 0). Another fix would be to insert "mov x, #0" before the rep loop.
I'm changing PNut.exe to separate the ORGH address from the actual object code address.
What exactly do you mean by that, Chip? Do you mean that labels will now have 3 values, their default value, notional hub value as set by ORGH, and actual location in HUB memory? This seems like it could get very confusing. I think one of the things people didn't like in P1 was that "@label" had different meanings in Spin and PASM; in Spin it gave you the actual HUB location, but in PASM it just gave you an offset of sorts. It would be nice to fix that in P2.
I think it pushes to at least $400.
I think the way it works now (but could be wrong) is that tries to start code at X in HUB memory with X being made to be at least $400.
This seems to be working just fine for me...
And here, we see how it can really mess you up if you don't realize it's not initiated...
I'm trying to think if RES serves any use that justifies itself..
In fastspin (and I'm pretty sure the other assemblers) "ORGH X" will try to insert padding to make sure the code/data will start at location X in hub memory. If there is already more than X bytes of things in HUB then it will report an error. There's no special case for $400.
Note that unlike ORG, just plain ORGH on its own is *not* the same as "ORGH 0". Just "ORGH" with no number says "labels defined after this point are in HUB memory", but it doesn't change the hub memory location. So in: "x" has the value 0, "y" as the value 1 (it's a COG address), but "z" has the value 8 (it's a HUB address). If the ORGH wasn't there, "z" would have the value 2.
I thought there were some things that don't work if address is below $400.
What was it? I think it was something about a relative vs. hub address...
Or, maybe it is hubexec code doesn't work if below $400 ?...
Thank you! I never checked for that. I've tested it and it works just by adding a MOV x,#0.
You have to use RES carefully, but it does have uses. The main one is that it allows you to declare variables that you know will be initialized from elsewhere (e.g. data read from pins or SD card) without requiring that space be allocated in the binary. That can save a lot on load time, and also lets you fit more things into HUB RAM. For example: reserves space for 400 longs at runtime, but since it's not initialized you don't have to download that to the P2, and if it's in an ORG section it consumes no extra HUB RAM; whereas makes your .binary file 400 bytes larger. In some cases this could be the difference between having code that fits in memory and not.
But, I do use RES, I'm just very careful with it after having been burned more than once.
I've had bad experience too but, at this stage, it doesn't look to be the fault of the tools.
The RES instruction should be used with care. If a variable is required to be initialize to zero it is better to use "long 0" instead of using res, and then depend on the assembler to pad with zeros.
For Spin2 mode, though, there isn't going to be controllable absolute addresses because of how objects build. So, in the case if Spin2 mode, ORGH will only affect the assembler-aware origin, and will default to $400, and not allow addresses below $400.
I think there is room for both, but they need to be very clear about what they actually do, and where they are doing it !!
As P2 is totally RAM based, there are code-gains to be had, by declaring a VAR and initialising it at the same time.
Flash based MCUs have to load any initialized RAM vars, which costs time and code space.
Some MCUs sweep RAM to clear to 0x00, as part of their init code. That approach does reduce code size and helps avoid 'oops' bugs.
Arrays that are declared maybe should have an option to load a known value ?
As mentioned above, large arrays could have a download cost, if their value is really don't care.
The assembler would have to group them up under each ORG and arrange them before the end of the DAT block or before the next ORG or ORGH. It's a lot simpler to just place them manually and understand what they do.
I like warnings
Ignore them all the time
It's has been used extensively in P1 code.
The P1 manual explains it's use and even includes this statement.
I would urge you to think about this again. Addresses were one of the problem points in Spin 1; I think people often tripped over the difference between @ in Spin and PASM. I know that making @ working as expected in mixed PASM and Spin is difficult. But it is possible -- homespun and bstc did it, for example (although they had to invent a new syntax, @ @ @, to maintain Spin compatibility).
I found this quote from ersmith:
Seems the triple is only for PASM sections?
But, I think the tools right now already give us the absolute address of things when inside a PASM section.
Not in Spin 1. On the Propeller 1, @ inside a DAT section always meant an address relative to the start of the DAT section. Right now in P2 code this is different and @ means absolute address, but I think Chip was talking about making Spin 2 act like Spin 1. I think this could end up being very confusing.
Am I missing something?
We'd have to have some kind of linker step to afford absolute addressing between uncommonly ORGH'd blocks of PASM code, right? It seems way more trouble than it's worth if we can determine an entry-point at run time and just use that, instead.
There we currently rely on the orgh value, I think, so that would have to change somehow...
EDIT: Maybe the independent DAT section could contain global symbols that any object could directly address. That's a feature that would have been useful in Spin1.