simple CMP example not working
aempirei
Posts: 6
hello i have this simple CMP code and it does not seem to correctly work:
i assume that i should be caught in an infinite loop only if t1 != 69, but i get stuck in that loop as it is.
any help?
DAT
······· org 0
Toggle
······· cmp t1, #69 wz·
:fail
· if_ne jmp #:fail
······· mov dira, Pin·········· 'Set Pin to output
······· mov Time, cnt·········· 'Calculate delay time
······· add Time, #9··········· 'Set minimum delay here
:loop·· waitcnt Time, Delay···· 'Wait
······· xor outa, Pin·········· 'Toggle Pin
······· jmp #:loop············· 'Loop endlessly
Pin long |< 7·················· 'Pin number
Delay long 6_000_000··········· 'Clock cycles to delay
Time res 1····················· 'System Counter Workspace
t1 long 69
i assume that i should be caught in an infinite loop only if t1 != 69, but i get stuck in that loop as it is.
any help?
DAT
······· org 0
Toggle
······· cmp t1, #69 wz·
:fail
· if_ne jmp #:fail
······· mov dira, Pin·········· 'Set Pin to output
······· mov Time, cnt·········· 'Calculate delay time
······· add Time, #9··········· 'Set minimum delay here
:loop·· waitcnt Time, Delay···· 'Wait
······· xor outa, Pin·········· 'Toggle Pin
······· jmp #:loop············· 'Loop endlessly
Pin long |< 7·················· 'Pin number
Delay long 6_000_000··········· 'Clock cycles to delay
Time res 1····················· 'System Counter Workspace
t1 long 69
Comments
The RES stuff has to come last in the code to get loaded into the cog.
I would also increase the minimum delay time. 9 clock cycles is from
the time when the CNT register gets fetched until the WAITCNT starts
to wait which is more than 9 clock cycles. If you want to use a
minimum delay, you have to access CNT just before the WAITCNT.
I'd suggest:
it specifically the:
······· cmp t1, #69 wz·
:fail
· if_ne jmp #:fail
Point 5.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Help to build the Propeller wiki - propeller.wikispaces.com
Play Defender - Propeller version of the classic game
Prop Room Robotics - my web store for Roomba spare parts in the UK
Put the res last, like an end of cog marker.
If I may, what's the advantage of using res over just declaring a long, or a group of longs? If a given address, or group of addresses is gonna get labeled for working variable purposes, does it really matter?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Propeller Wiki: Share the coolness!
Both LONG and RES consume 1 long in Cog RAM. But only LONG consumes a long in Hub RAM. RES comes without cost to Hub RAM. So if you need an initialised variable or a constant >$1FF, use LONG, if it doesn't need to be initialised, then use RES to save a Hub long.
So long as you always place all RES lines after all LONG, WORD or BYTE lines in the assembler DAT block, there won't be a problem.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Help to build the Propeller wiki - propeller.wikispaces.com
Play Defender - Propeller version of the classic game
Prop Room Robotics - my web store for Roomba spare parts in the UK
It doesn't make any sense to my why longs have to be defined after res.
As a "newcog" blindly copies all the cog's memory, there is also no logical explanation.
Anyhow, it's the way it is. A long has to be decalred after all the res.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
Thanks!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Propeller Wiki: Share the coolness!
Try the new Wiki page and see if that makes some sense of the issue for you. There is a logical explanation, it's just a bit of a mind bender until suddenly you get it.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Help to build the Propeller wiki - propeller.wikispaces.com
Play Defender - Propeller version of the classic game
Prop Room Robotics - my web store for Roomba spare parts in the UK
reording the RES to last worked.
Gnaaa. Yes, it is.
> Try the new Wiki page and see if that makes some sense of the issue for you.
Yes, it does.
What doesn't make sense is, that there is no error-notice during compile.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
That boils down to the Propeller Tool accepting anything which is syntactically correct regardless of whether it's semantically correct, and in truth the compiler cannot easily judge what you may want to be doing, it can only impose restrictions on what can be done.
RES anywhere but at the end of Cog rarely makes sense, but that's not always the case, just like ORG ( except ORG 0 at the start ) doesn't usually make sense nor do what might be expected. Cog code longer than 496 longs is usually a mistake. However, there are some cases where all these make sense and are intended.
I think there ought to be a settable option on what level of checking there is during compiling as more often than not misplaced RES, incorrect use of ORG and Cog programs too long are mistakes or misunderstandings rather than deliberately done for some particular and properly handled reason.
Enhanced compiler to:
1) Support a new directive, ORGX, to allow user to stop COG address incrementing for large-model assembly programs.
2) Enhance arguments of ORG, RES, FIT, and ‘repeat’(in BYTE/WORD/LONG value[noparse][[/noparse]repeat]) so that they are allowed the same scope as instruction operands.
3) Support RES as _RET destinations.
4) Support TESTN instruction (which is an ANDN instruction, no result write... similar to how TEST is really an AND, no result write).
Ah well. I think I can arrange my registers the way that they do make sense by keeping things together that do belong together.
Also longs mixed in between res do make sense as sentinels, guards or flags that some table is not yet fillled/initialized or things like that.
> That boils down to the Propeller Tool accepting anything which is syntactically correct regardless of whether it's
> semantically correct,
If the syntax allows constructs that the compiler can't handle right, there is either a flaw in the language or the compiler.
And don't argue, that the Prop-Tool doesn't know where the pointer to COG-ram is, because he can complain about out-of-RAM.
It's simply a bug, but I have the impression that it has to be praised as a great feature.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
Post Edited (Nick Mueller) : 12/17/2007 3:01:57 PM GMT
The compiler is handling what was specified and handling it correctly so it cannot be called a bug.
Here's an entirely ( untested but ) valid piece of assembler which has RES before LONG ...
If the compiler called "error" on that it would be entirely wrong, and claiming any error was present would be a bug.
The code isn't even that artificially concocted because it's a trick I'm intending to use to populate a Cog which has code and variables in its bottom $000-$0FF and data in $100-$1EF while minimising the amount of hub memory to do that.
Post Edited (hippy) : 12/17/2007 3:43:08 PM GMT
Nick, it is a pity that you have not read through my "Machine Language Tutorial". Many things that you think are "difficult to understand" or "considered bugs", are explained there...
RES n
has a very specific meaning: It increments the COG memory reference counter by "n", without reserving any memory, thus desynchronizing COG memory allocation until the next ORG.
The reason also well explained here is Saving HUB memory.
It is generally a bad practice using features not well understood (RES, carry with SUBS, shadow registers,...)
It is easy to say: "But these features shouldn't exist in the first place!"
May be they shouldn't... But they are kind of useful to the master....
> But can he?
At least if I end the ASM with a FIT.
> Nick, it is a pity that you have not read through my "Machine Language Tutorial".
The pitty is, that you *asume* that.
> The reason also well explained here is Saving HUB memory.
I am in the situation to understand that. Believe it or not.
> It is generally a bad practice using features not well understood (RES, carry with SUBS, shadow registers,...)
It's generally a bad practice to introduce "features" -that don't even generate a warning- whose only side-effects are errors.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
I was thinking it was rather pointless...
I'm not sure I knew it had to come last either...
Why isn't this info in the Manual? The SPIN part of the manual seems more or less complete, but the Assembly portion seems very incomplete!
It took me a while to grasp its significance coming from an environment where whatever is in the user program has some corresponding allocation of space in an object image ( and in this case hub memory ). RES for more traditional architectures may not have any data defined with it but it still takes up space in an image on a one-to-one basis.
For the Propeller it's much more than, "give me a variable, and I don't care what's in it to start with", but I cannot recall seeing it explained in the official documentation. I worked it out when I started decompiling Spin bytecode but I'm not sure it's that well understandable or obvious to most people. They, like I did initially, probably more often than not use "RES 1" because that's what most example programs show, and when a variable needs a value use LONG.
The Propeller Manual describes the effect RES has on Cog memory but doesn't at all describe the effect it has with Hub memory or what the consequences are.
Likewise ORG. With most architectures, an arbitrary ORG will put subsequent code at the specified location onwards, on the Propeller it simply alters the symbol table addresses for the Cog program labels but doesn't pad out the image ( or hub memory ) so when the Cog code is loaded, things are not where they were expected to be.
The best way I've found to describe it to those familiar with image files ( .HEX, Motorola S-Record and Intel format etc ) is that RES and any gaps before ORG may not generate any records but that doesn't matter because when being loaded, the code is placed in memory at the location specified in each record. For the Propeller, the records are loaded and placed in memory sequentially regardless of what addresses are specified in each record.
But when reading through the posted version 1.20 I see the rational is quite hidden... I added many remarks in the meantime... I PROMISE to post it before the advent of the C compiler
Does #9 suffice?
Yes, in fact this is the case whithout any "wait" at all (5 ticks of WAITCNT only)!
I am sure aempirei ("nomen est omen") checked this out
Oh, dear! Now you opened Pandora's box even a little bit wider
Thanks for the diagram Hippy. That's a keeper for sure. (marked for the wiki)
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Propeller Wiki: Share the coolness!
Post Edited (potatohead) : 12/17/2007 8:07:31 PM GMT
From NewForth.spin. (with my comments)·Notice the hack-around +$10 to maintain the link field address integrity in the loaded program.
One would think that if the loader shoves a spin program into the hub at $10, then all the addresses in the compiled code would be adjust everywhere. But what this shows us is that the label addresses adjust·but the hand loaded word values using the labels do not get adjusted by the loader.
Other compilers surely handle this differently. I think the 9900 assembler didn't resolve any address at all until the program was loaded.
But note that the COG-LOADER is a hardware feature!!
Some LMM models can be considered kind of "virtual loader".
I played around with a "Secondary COG Loader" some months ago (it took 1/4 of the COG, but that area could be resused for variable space.)...
But as many have noticed already this needs another more intelligent cross assembler at the PC.
It's also necessary to consider there are two separate loaders ( and three separate processes in play here ).
One loader is the Bootloader which simply copies the I2C Eeprom ( or PC download ) to internal hub memory on a byte-by-byte basis, the other is the Cog Loader which takes an arbitrary 496 longs of Hub Memory and dumps them in a Cog for execution. Those account for two 'processes'.
The third process is Spin interpretation. The Spin interpreter runs largely with an offset system of addressing, where the base of what it references can be the start of hub memory, the start of an object, the start of an object's global variable space and the start of a subroutine's stack frame. The Spin interpreter adds base values to offsets as needed at runtime depending on bytecode context.
The 'main program' ( top level object ) is an object in its own right. This is usually offset +$10 from the start of hub memory following an information block which is used to get Cog 0 running the top level object after hub memory has been bootloaded.
In the Forth case cited, the Propeller Tool is building its image relative to the object base ( $0010 in hub memory as a top-level object ) and the explicit +$10 probably wouldn't be needed if the Forth kernel were adding the object base offset itself. That's of course slower than simply adjusting the pointer value offset itself.
What Forth is doing here is using Spin to build a linked list at absolute addresses in the hub memory, rather than building a linked list with pointers offset from the object base.
The downside though is that the Forth kernel object is locked into being a top-level object and couldn't be used as a sub-object of another application. The hard-wired +$10 would be wrong for a sub-object.
Also, if someone wrote a third-party Spin compiler and generated their '32KB application image' differently to how the propeller Tool does you could run into problems there.
That's not to say the Forth implementation is outright wrong. Adding the object base frequently at runtime would slow down the Forth interpreter ( hence hard-wiring is better ), but a better option might be to use an object base offset linked list, then go through and fixup relative, offset pointers to absolute hub addresses when the Forth interpreter is loaded. I have no idea how easy or hard that could be.
What ends up in the image ...
To process the list ...