Shop OBEX P1 Docs P2 Docs Learn Events
simple CMP example not working — Parallax Forums

simple CMP example not working

aempireiaempirei Posts: 6
edited 2007-12-18 15:32 in Propeller 1
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
«1

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-16 22:33
    For one, the t1 declaration has to come before any RES declarations.
    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:
            mov  Time,#9
            add   Time,CNT
    :loop waitcnt Time,Delay
    
  • aempireiaempirei Posts: 6
    edited 2007-12-16 22:36
    thats not the part of the code im having a problem with.



    it specifically the:



    ······· cmp t1, #69 wz·
    :fail
    · if_ne jmp #:fail
  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-16 22:38
    Please reread the first part of my reply.
  • CardboardGuruCardboardGuru Posts: 443
    edited 2007-12-16 22:52
    propeller.wikispaces.com/Common+Assembler+Bugs

    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
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-16 22:59
    I was stumped too. (don't normally use res, which is the trouble here) After reading Mike's reply, the problem is t1 is not getting actually loaded (and thus initialized) in the COG. So, you really don't know what you are comparing to! That's why you get the loop no matter what.

    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!
  • CardboardGuruCardboardGuru Posts: 443
    edited 2007-12-16 23:05
    potatohead said...
    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?

    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
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-16 23:21
    > 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.


    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
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-16 23:22
    Got it. That makes perfect sense.

    Thanks!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
  • CardboardGuruCardboardGuru Posts: 443
    edited 2007-12-17 03:39
    Nick Mueller said...
    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.
    It's the other way around. RES must be AFTER all LONGS (and everything else).

    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
  • aempireiaempirei Posts: 6
    edited 2007-12-17 06:40
    SWEET THANKS FOR THE HELP!

    reording the RES to last worked.
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2007-12-17 09:07
    two cents: the wiki page ought not hide the word 'reserve' until nearly the final sentence. Most of the mystery is based upon that slight of hand.
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-17 09:58
    > It's the other way around. RES must be AFTER all LONGS (and everything else).

    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
  • hippyhippy Posts: 1,981
    edited 2007-12-17 13:17
    Nick Mueller said...
    What doesn't make sense is, that there is no error-notice during compile.

    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.
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2007-12-17 14:46
    While we're wishing, how about a single stop shop that explains this stuff:
    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).
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-17 14:51
    > RES anywhere but at the end of Cog rarely makes sense, [noparse][[/noparse]snip]

    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. smile.gif


    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
  • hippyhippy Posts: 1,981
    edited 2007-12-17 15:37
    Nick Mueller said...
    > 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. smile.gif

    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 ...

            org    0
    
            mov    count,#10
    Reloc   mov    $100,from
            add    Reloc,k_0201
            decjnz count,#Reloc
    
    Loop
            :
            jmp    #Loop
    
    count   long   0
    k_0201  long   $0000_0201
    
    from
    
    var1    res    1
    array   res    10
    var2    res    1
    
            long   1
            long   2
            :
            long   10
    
    
    



    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
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-17 15:59
    Nick Mueller said...
    ... because he can complain about out-of-RAM.
    But can he?

    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....
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-17 16:46
    >>... because he can complain about out-of-RAM.

    > 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
  • RaymanRayman Posts: 14,162
    edited 2007-12-17 16:54
    I didn't know about RES saving HUB RAM! (Maybe because I never made it to the end of deSilva's tutorial [noparse]:)[/noparse]
    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!
  • hippyhippy Posts: 1,981
    edited 2007-12-17 17:36
    Rayman said...
    I didn't know about RES saving HUB RAM! (Maybe because I never made it to the end of deSilva's tutorial [noparse]:)[/noparse]
    I was thinking it was rather pointless...

    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.
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-17 17:43
    ... the end of deSilva's Tutorial... well, the main thing is at the end of page 7 smile.gif

    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
  • hippyhippy Posts: 1,981
    edited 2007-12-17 17:55
    A picture's worth a thousand words apparently ...
                What one wants                          What one gets
            .--------------------.                   .------------------.
            |       org  0       |___________________|  org  0          |
    000     | Loop  mov  a,b     |                   |  mov  $003,$004  |    000
    001     |       call #MySub  |                   |  call #$100      |    001
    002     |       jmp  #Loop   |___________________|  jmp  #$000      |    002
    003     | a     res  1       |      |   _________|  long $123       |    003
    004     | b     res  1       |______|  |         |  nop             |    004
    005     | c     long $123    |_________|    _____|  ret             |    005
            |--------------------|         |   |     |                  |
            :                    :         |   |     :                  :
            |--------------------|         |   |     |                  |
            |       org $100     |_________|   |     |                  |    100
    100     | MySub nop          |             |     |                  |
    101     |       ret          |_____________|     |                  |
            |--------------------|                   |                  |
            :                    :                   :                  :
    1EF     |                    |                   |                  |    1EF
            `--------------------'                   `------------------'
    
    
    
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-17 18:11
    This is something Mike addressed:
            mov Time, CNT           'Calculate delay time
            add Time, #9            'Set minimum delay here
            waitcnt Time, Delay     'Wait
            xor   OUTA, Pin
    


    Does #9 suffice?
    Yes, in fact this is the case whithout any "wait" at all (5 ticks of WAITCNT only)!
    Tick   GetInstr  empty  GetDest  GetSrc  Operate   StoreBack
    -3     MOV
    -2                ---
    -1                      Time
    0                                CNT
    +1     ADD                                ---
    +2                ---                              Time
    +3                      Time
    +4                               #9
    +5     WAITCNT                            add
    +6                ---                              Time
    +7                      Time
    +8                               Delay
    +9                                        Wait     Time
    +10    XOR
    +11               ---
    +12                     OUTA
    +13                             Pin
    +14                                       xor
    +15                                               OUTA   -> Strope detectable
    


    I am sure aempirei ("nomen est omen") checked this out smile.gif
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-17 18:16
    @hippy: Very nice diagram!
    MySub  NOP
    


    Oh, dear! Now you opened Pandora's box even a little bit wider smile.gif
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-17 20:01
    Hehe... you guys are great. I absolutely love the learning environment here. I read each day, letting it all soak in, one entertaining thread at a time. It's not always pretty, but it's just a kick seeing it all play out. Thanks all for that. Know it's totally appreciated by this guy, slowly coming back to micros + electronics. Should have never left in the first place. Had there been venues like this, I wouldn't have. When I do approach the prop and begin, I can hear the words ringing in my head... saved me a ton of time --will save more, count on it.

    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
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2007-12-18 02:27
    ForthDictStart
     
                            word    0                   'lfa grounded, no more words in dictionary to search.
    mswHereNFA              byte    $87,"mswHere"
    mswHerePFA              word    (@a_dovarw - @a_base)/4
                            word    $46F4
     
                            word    @mswHereNFA + $10   'lfa to next word.
    

    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.
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-18 07:48
    Right, Fred. It is rarely understood that an essential part of a system is the LOADER and the LINKER. The most simplistic LOADER is something copying a binary image. This is far away from what a decent system does.

    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.
  • hippyhippy Posts: 1,981
    edited 2007-12-18 10:24
    Fred Hawkins said...
    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

    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.
  • hippyhippy Posts: 1,981
    edited 2007-12-18 10:54
    Another picture. This shows the source code for a Spin-built linked list which is built by the Propeller Tool relative to the start of an object rather than than relative to the start of hub memory ...

    aa      word "A"
            word @bb
    
    bb      word "B"
            word @cc
    
    cc      word "C"
            word 0
    
    
    



    What ends up in the image ...

    Hub Adr    Obj Adr    Contents
                                     Object Base Ptr
                        .------.        .------.
     0124       0000    |  "A" | <------| 0124 |
     0126       0002    | 0004 |        `------'
                        |------|
     0128       0004    |  "B" |
     012A       0006    | 0006 |
                        |------|
     012C       0008    |  "C" |
     012E       000A    | 0000 |
                        `------'
    
    



    To process the list ...

    PUB Main
      PrintLinkedListOffsetFromObjectBase( $0124 )
    
    PRI PrintLinkedListOffsetFromObjectBase( objBase ) | objAdr, lstDat
      objAdr := $0000
      repeat
        lstDat := word [noparse][[/noparse] objAdr + 0 + objBase ]
        objAdr := word [noparse][[/noparse] objAdr + 2 + objBase ]
      loop until objAdr == 0
    
    
    
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2007-12-18 13:52
    hippy said...


    The 'main program' ( top level object ) 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.
    When isn't it offset by 16?
Sign In or Register to comment.