Shop OBEX P1 Docs P2 Docs Learn Events
Assembly confusion — Parallax Forums

Assembly confusion

Graham StablerGraham Stabler Posts: 2,507
edited 2007-07-10 23:47 in Propeller 1
I think I saw this mentioned elsewhere but what the heck is going on here:

 :IPos           add     0, Diff                         'Add to encoder position value
                    wrlong  0, MPosAddr                     'Write new position to main memory




I understand add and wrlong but not the use as 0 as a destination, I assume it relates to the label :IPos but I'm not sure how.

I'd also like to know if this is good programming practise or just being fancy [noparse]:)[/noparse]

Graham
«1

Comments

  • nutsonnutson Posts: 242
    edited 2006-10-07 13:24
    Lacking an indexed adressing mechanism, propeller assembly makes use of "instruction modification" or "self modifying code" for routines that store / fetch data in tables, stepping through the table by incrementing / decrementing the destination / source address in the instruction that handles them. The instructions MOVS and MOVI are meant to insert a starting address in these instructions. The instruction to be modified is often written as having a source / destination of "0", as it will be modified later anayway.

    Nico Hattink
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2006-10-07 15:28
    two things... The first argument in the WRLONG instruction is the Value, not the Destination. Second, the Value can not be a literal, it needs to point to a register containing the value you want to pass.
    Refer to page 415 of the Propeller manual.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-10-07 19:31
    Phil (PhiPi) uses a convention for self modifying place holders that I particularly like, and that is the value 0_0. This evaluates to 0, however it is clear to somone reading the code this is only a place-holder to be modified by a MOVS/MOVD instruction at a later point.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-07 19:34
    Another similar convention is to use 0-0, but really anything that stands out and is understood by others is useful.
  • Graham StablerGraham Stabler Posts: 2,507
    edited 2006-10-08 10:21
    Beau, I just got it the wrong way around.

    Could someone explain this specific example rather than the generalities, I don't actually know what an indexed addressing mechanism is and so it is hard to understand what this is trying to achieve and why.

    Sorry to act like such a dunce.

    Graham
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-08 13:16
    Graham,
    Indexed addressing usually is used for array access. Essentially, a computed value is used for an address. This works already on the Propeller for HUB memory access in that the HUB address is taken from a COG memory location and can be computed in any fashion (for RDxxxx and WRxxxx instructions). Similarly, jump addresses are taken from a COG memory location and can be computed, so you can have a table of instructions (like jumps) and a memory location "addr" that has the address of a table entry in it, then do a "JMP addr". What you don't have is the ability to fetch and set data values (like in an array) using a computed address. For that, you have to actually change the instruction to be executed, particularly the source address or destination address field. There are MOVS and MOVD instructions that make this easier. A simple example:
    '' To do "repeat j from 9 to 0"
    '' "  table[noparse][[/noparse]j] := j"
          mov   m,#10
    xx  mov   zz,#table-1
          add    zz,m
          movd yy,zz  ' note there's a 1 instruction delay
          movd ww,zz  ' because the Propeller fetches instructions
    yy   mov   0-0,m  ' ahead of time.  The "j" value is kept
    ww  sub   0-0,#1  ' here in "m" and offset by one partly
           djnz  m,#xx ' because of the djnz instruction and just
    '                           to demonstrate that it can be done.
    '
    i      res   1
    table res  10
    
    

    Post Edited (Mike Green) : 10/8/2006 1:20:18 PM GMT
  • parskoparsko Posts: 501
    edited 2006-10-08 20:19
    xx  mov   zz,#table-1
    
    



    Mike, this is legal??? One can subtract in a mov command?
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-08 20:27
    This is a simple move of a literal (immediate) value to a cog memory location. It just happens that the literal value is a constant expression "table - 1" which happens to be the address of the location called "table" minus one (to compensate for using a counter starting at one). Any instruction source or destination field including immediate values can be a constant expression of any complexity because the compiler is computing the value at "compile time". After the program is compiled, this is just a binary number like the rest of the instruction.
  • Graham StablerGraham Stabler Posts: 2,507
    edited 2006-10-09 00:06
    OK I think I now get it, you have 10 longs reserved for your array but you can't just write table like you might in spin.

    So you take the address of the table which is its name, add an offset to access the element you are interested in and by using the command movd write that into the destination part of the command with label yy, replacing the 0-0 that acted as a place holder. When that command is run it has the correct address of the element of the array.

    The main thing I wasn't understanding was the self modifying code remarks made earlier, I now understand that movd acts only on the destination and likewise Movs acts on the source. Looking at your code at first I wondered why you didn't just write mov zz,m and then I realized it would just overwrite zz and not use the address it holds.

    Graham

    p.s. Now I get it Nico's explanation makes perfect sense.
  • Jim CJim C Posts: 76
    edited 2006-10-10 19:43
    I have come across another little twist about indirect addressing and arrays when using assembly. If there are more than one parameter to pass to or from a new cog they would be passed via an array, with the address of first element being passed as a parameter to the cog. See example below, drawn from the fullduplex object:

    VAR
    long rx_head
    long rx_tail
    long tx_head
    long tx_tail
    long rx_pin


    cognew(@entry,@rx_head)' 'pass address of rx_head: first element of array
    entry mov t1,par 'mov address of rx_head to t1
    add t1,#4 << 2 'shifting 4 two bits to left yields 16. T1 now holds address of rx_pin: 5th element of array
    rdlong t2,t1 'read rx_pin value from that 5th address, into t2

    The trick that was not clear to me at first was that to get to the next array element, the cog has to add 4. This is because the hub keeps track of things as bytes, so to get to the next long, you need to advance 4.

    Jim C
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2006-10-10 20:09
    Jim C,

    VAR
    long rx_head 
    long rx_tail
    long tx_head
    long tx_tail
    long rx_pin
    
    cognew(@entry,@rx_head)' 'pass address of rx_head: first element of array
    
    entry  mov    t1,par
           rdlong t2,t1     't2 receives rx_head
           add    t1,#4     '<--Add offset of 4 for next LONG
           rdlong t2,t1     't2 receives rx_tail
           add    t1,#4     '<--Add offset of 4 for next LONG
           rdlong t2,t1     't2 receives tx_head
           add    t1,#4     '<--Add offset of 4 for next LONG  
           rdlong t2,t1     't2 receives tx_tail
           add    t1,#4     '<--Add offset of 4 for next LONG 
           rdlong t2,t1     't2 receives rx_pin
     
     
    {
    Note:
    typically for t2 you would have individual varaibles... something more like...
    
    

    VAR
    long rx_head 
    long rx_tail
    long tx_head
    long tx_tail
    long rx_pin
    
    cognew(@entry,@rx_head)' 'pass address of rx_head: first element of array
    
    entry  mov    t1,   par
           rdlong Arg0, t1     'Arg0 receives rx_head
           add    t1,   #4     '<--Add offset of 4 for next LONG
           rdlong Arg1, t1     'Arg1 receives rx_tail
           add    t1,   #4     '<--Add offset of 4 for next LONG
           rdlong Arg2, t1     'Arg2 receives tx_head
           add    t1,   #4     '<--Add offset of 4 for next LONG  
           rdlong Arg3, t1     'Arg3 receives tx_tail
           add    t1,   #4     '<--Add offset of 4 for next LONG 
           rdlong Arg4, t1     'Arg4 receives rx_pin
    




    unless you define your variables you want to pass as Bytes..


    VAR
    byte rx_head 
    byte rx_tail
    byte tx_head
    byte tx_tail
    byte rx_pin
    
    cognew(@entry,@rx_head)' 'pass address of rx_head: first element of array
    
    entry  mov    t1,   par
           rdbyte Arg0, t1     'Arg0 receives rx_head
           add    t1,   #1     '<--Add offset of 1 for next BYTE
           rdbyte Arg1, t1     'Arg1 receives rx_tail
           add    t1,   #1     '<--Add offset of 1 for next BYTE
           rdbyte Arg2, t1     'Arg2 receives tx_head
           add    t1,   #1     '<--Add offset of 1 for next BYTE  
           rdbyte Arg3, t1     'Arg3 receives tx_tail
           add    t1,   #1     '<--Add offset of 1 for next BYTE 
           rdbyte Arg4, t1     'Arg4 receives rx_pin
    





    consequently if you assigned a word variable you would add 2 for every subsequent entry and use 'rdword' instead.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 10/10/2006 8:43:13 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-10 20:12
    Beau,
    That a good segue into a question about the behavior of rdxxxx and wrxxxx instructions with unaligned values.

    What does the Propeller do with a RDLONG or WRLONG instruction with a HUB address that's not a multiple of 4?

    Similarly, what does it do with a RDWORD or WRWORD instruction with a HUB address that's not a multiple of 2?

    Mike
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2006-10-10 20:29
    Good question Mike,

    I know that in the Assembly Dispatch program, that I have found very useful for calling Assembly functions from Spin, the following section...

    jumps                   byte    0                       '0
                            byte    Command1_               '1
                            byte    Command2_               '2
                            byte    NotUsed_
                            byte    NotUsed_                '&#61626;&#9472;&#9488;                                                               
                            byte    NotUsed_                '  &#9474;                                                               
                            byte    NotUsed_                '  &#9507;&#9472;&#61610; Additional functions MUST be in groups of 4-bytes (1 long)  
                            byte    NotUsed_                '&#61626;&#9472;&#9496;   With this setup, there is a limit of 256 possible functions.
    NotUsed_
                            jmp     #mainloop
    
    



    ...will not compile if the number of "byte" references do not equate to a multiple of one long. So the IDE might be smart enough to figure out the
    relative byte offset if you create a problem. Now, that said, if you call a routine that is positioned within an odd byte offset, then all bets are off.
    I'm not sure what you would run into.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • Jim CJim C Posts: 76
    edited 2006-10-10 20:36
    Beau:

    Thanks for the more complete explanation. I had not seen the rdword and wrword commands before, but seeing now how they work, as well as the byte commands, the whole addressing scheme starts to get clear.

    Jim C.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-10 20:49
    Beau,
    It would be nice to have this behavior publically documented. It's clearly something that people are not supposed to do and may not be done the same way in future versions of the Propeller, but it would be nice to know to be able to explain why a program misbehaves in a particular way with this mistake.
    Mike
  • WurlitzerWurlitzer Posts: 237
    edited 2007-07-04 14:47
    Beau Schwabe (Parallax) said...
    Jim C,

    VAR
    long rx_head 
    long rx_tail
    long tx_head
    long tx_tail
    long rx_pin
    
    cognew(@entry,@rx_head)' 'pass address of rx_head: first element of array
    
    entry  mov    t1,par
           rdlong t2,t1     't2 receives rx_head
           add    t1,#4     '<--Add offset of 4 for next LONG
           rdlong t2,t1     't2 receives rx_tail
           add    t1,#4     '<--Add offset of 4 for next LONG
           rdlong t2,t1     't2 receives tx_head
           add    t1,#4     '<--Add offset of 4 for next LONG  
           rdlong t2,t1     't2 receives tx_tail
           add    t1,#4     '<--Add offset of 4 for next LONG 
           rdlong t2,t1     't2 receives rx_pin
     
     
    {
    Note:
    typically for t2 you would have individual varaibles... something more like...
    
    

    Ok! I am stuck completely. I have a series of Arrays some Byte arrays and some Longs. If I pass the address of my byte array and attempt to locate the value for array index [noparse][[/noparse]0] I find I have to add #2 to the address passed to the assembly program.
    VAR
    · byte· KBArray[noparse][[/noparse]64]
    · Long· CurStopWord1[noparse][[/noparse]16]'
    · Long· CurStopWord2[noparse][[/noparse]16]
    · Word· OutputWord'
    · long· ProcessStop'
    · long· cog·························· '· long· StRam
    ·· long LC
    PUB start : okay·
    lc:=1
    · repeat 16· 'load some logical values into array to find in assembly·routine
    ··· kbarray[noparse][[/noparse]lc] :=lc
    ··· lc:=lc+1


    · kbarray[noparse][[/noparse]0]:=222' a unique value to locate in assembly routine·
    okay := cog := cognew(@entry, @kbarray) + 1
    DAT
    ············· org
    entry···················
    ····················
    ············· mov VarStartAddr,par
    ············· or dira,pinmask
    ············· shl pinmask,#1
    ············· or dira,pinmask
    ············· shl pinmask,#2
    ············· or dira,pinmask
    ············· shl pinmask,#3
    ············· or dira,pinmask
    ·································
    ············· add VarStartAddr,#2 'It seems I have·increment by 2 to find the first element of KBArray
    ············· rdbyte tmp,VarStartAddr· wz············
    ············· cmp tmp,#222· wz'Z flag set if equal·································
    ············· if_z· or outa,#1 '···The Z flag is set with these values
    ·
    ············
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-04 15:27
    Because KBArray is declared as a byte array, it can be placed at any address in the hub memory. Unfortunately, the address that's passed to the assembly routine can only be a long word address. The lower two bits are always forced to zero. The compiler allocates space for the long word values first, then the word values, then the byte values. You have a single word value so the byte values start at a word boundary that's not a long word boundary (+2). The +2 offset gets truncated by the cognew().

    One solution is to define KBArray as long[noparse][[/noparse] 16 ] and to refer to its elements in your Spin code as KBArray.byte[noparse][[/noparse] lc ]. Another solution is to pass the address of a long word that you set to the actual address of KBArray like:
    VAR long kbaddress
    kbaddress := @KBArray
    cognew(@entry,@kbaddress)
    DAT
    entry mov VarStartAddr,par
             rdlong VarStartAddr,VarStartAddr
    
    
  • WurlitzerWurlitzer Posts: 237
    edited 2007-07-04 15:48
    Thank you very much Mike! That makes perfect sense!
    Craig
  • WurlitzerWurlitzer Posts: 237
    edited 2007-07-06 20:36
    Well thanks to Mike G. and others, I have my 1st assembly routine running perfectly. It screams! It is writing and reading bunches of data from HUB RAM and processing all that data properly.

    Now what I need to do is to launch 3 other pure assembly routines. I attempted to do the following to call the 2nd assembly program which was simply created, right or wrong, as a 2nd DAT statement in the same file as the 1st assembly routine. While there was no error generated, it is obvious that the 2nd routine is not running. (for this test I simply flash a unique LED in each routine)

    From my spin program:
    okay := cog := cognew(@entry, @MasterArray) + 1 'This called routine runs fine as evident by a LED flash routine.

    okay := cog := cognew(@OutputDriverCog, @MasterArray) + 1 '** NOTE: the same LED flash routine (with different PIN) does not run

    Obviously this is not the correct way to do this so my question is 2 fold.
    1) Can a single Spin program call multiple assembly programs? How?
    2) Can or should the 2nd assembly routine be located in the original spin file or as a seperate file and what is the best configuration.

    NOTE: I am not trying to create multiple instances of an object as all the assembly routines will be doing completely different tasks.

    Thanks in advance, Craig
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-06 20:49
    You need to have an "ORG 0" statement before OutputDriverCog since each cog program needs to be assembled starting at the first long word of the cog. The first address in the COGNEW is the address of the long word to be copied to location zero of the new cog. You don't need two DAT statements although you can certainly have them. Basically you have
    DAT
          ORG   0
    entry ' stuff for 1st cog
    
    ' more stuff for 1st cog
    
         ORG    0
    OutputDriverCog ' stuff for 2nd cog
    
    ' more stuff for 2nd cog
    
    
  • WurlitzerWurlitzer Posts: 237
    edited 2007-07-06 20:56
    Boy Mike you are good and fast. Thanks for your help!

    Craig
  • WurlitzerWurlitzer Posts: 237
    edited 2007-07-06 21:24
    Mike, I have the ORG in the locations you described but the 2nd routine still does not run. What are the requirements of local variables in the 2 assembly routines as if I try to use the same name local variable the compiler complains of the duplicate name. By requirements I mean are they simply placed at the end of the 2nd routine?

    I have remarked out all the other code in both assembly routines with just the following remaining

    DAT
    org
    entry
    mov VarStartAddr,par 'Retrieves RAM starting location for HUB variables



    {========= SET PINS TO OUTPUT MODE =======================}
    mov tmp,#1
    shl tmp,#18
    mov pinmask,#1
    :PinDirLoop 'set pins to output mode
    cmp tmp,pinmask wz, nr 'tmp=loop counter. Set Z flag if values are the same
    or dira,pinmask 'Set this pin to output mode
    shl pinmask,#1 'Shift bit left one position
    if_nz jmp #:PinDirLoop 'If all pins required not set, continue to loop
    {
    }


    :TestLoop
    waitcnt time,_off_time ' wait for delay to pass
    xor outa ,#2 ' toggle the pin
    waitcnt time,_on_time ' wait for delay to pass
    xor outa,#2 ' toggle
    jmp #:TestLoop

    In the 2nd assembly routine I simply added a 2 to the loop labels "TestLoop2" and used xor outa, #1

    Just to verify the outputs I swapped the outa, #pin numbers and yes the 1st routine still works.
  • WurlitzerWurlitzer Posts: 237
    edited 2007-07-06 21:44
    Hold the presses. Mike, it does work. The problem was my very first statement in the 2nd assembly routine used a variable name from the first routine yet the compiler did not, nor does it seem to ever complain about using a variable declared in the first routine.

    The compiler only seems to complain about a duplicate decaration.

    Anyway, thanks again.
  • deSilvadeSilva Posts: 2,967
    edited 2007-07-08 02:33
    @Wurlitzer:
    (1) How should the compiler know which part of code is assumed to be put into which COG?
    (2) Do you preset TIME correcly for the first WAITCNT ? There is a general misunderstanding of how WAITCNT works. It does NOT wait until TIME + DELTA smile.gif

    @Mike, Beau
    (4) Mike asked yesterday what will happen when RDLONG A, B finds an "odd" value in B. IMO Beau did not answer that question; I think however the answer is: It ignores the LSBs
    (5) As padding does happen in the DAT section (it has to, as there is no re-allocation as in the VAR section), I think when mixing COG code with BYTE or WORD definitions, there will be no problems
  • WurlitzerWurlitzer Posts: 237
    edited 2007-07-08 18:09
    deSilva:
    1) Other than 2 or more ORGs I don't know how the compiler determines which part of the code is placed in a given COG. I had assumed a 2nd DAT statement would be the indicator for the compiler. In any event I had used 2 DAT and 2 ORG statements but the problem was I did not use a unique name for the variable which received the PAR from the SPIN routine. I thought the compiler would complain if I had used a variable in both DAT routines but it did not. It only complained when I used the same name in the xxxx RES 1 variable declarations.

    2) Both of the assembly routines do have a long delay befor the LEDs start to flash at the start but I knew what caused that but I was not concerned as at this point. I wanted to determine the best way to call multiple assembly routines. The actual routines work fine.

    That brings up a point where I am still confused. I can now create and run multiple assembly routines in multiple COGs but only if included in a single SPIN file. While this will work fine, I would like, if possible, to have separate files with Assembly ONLY code and call those routines from a single SPIN program. As of yet my little mind has not seen the light.

    It would be much easier to write and edit if each assembly routine were in its own file. I understand how to use Objects in Spin but again, I only wanted a single Spin routine to launch 1 or more pure assembly routines.

    I also want to understand the indexing through a table described earlier in this thread. My current application would work slick running a table of 96 longs. It needs to take an index received via a serial port and based on that index value, retrieve the proper bit pattern from a table in as efficient manner as possible.
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2007-07-08 20:50
    deSilva,

    "...Mike asked yesterday what will happen when RDLONG A, B finds an "odd" value in B. IMO Beau did not answer that question..."

    Actually the question was asked on October 10th 2006, and I did reply on that same day... "...if you call a routine that is positioned within an odd byte offset, then all bets are off.
    I'm not sure what you would run into."

    In answer to your question.....assume you are referring to two LONGs (8 total BYTES)
    
    If you increment the BYTE pointer every 4 Bytes, then the allignment is correct
    bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb   bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb
    &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;   &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;
      {All of this is the first LONG}       {All of this is the second LONG}
    
    Here if you increment the BYTE pointer every 3 Bytes, then your data is corrupted
    bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb   bbbbbbbb bbbbbbbb bbbbbbbb
    &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;   &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;
      {All of this is the first LONG}     &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;
                               &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;   &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600; &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;
                                 {All of this is the second LONG}
                               &#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;&#61600;
                          Data overlaps here
    


    Now if you define two variables as a long, and then you look past the end of the long declaration, you start dipping into other variables (words or bytes) or actual
    program space. This program space actually defines the END of the Propeller program and variable space, but it is NOT blank... If you look at the HEX view after
    pressing F8, the terminating double long looks like this.... FF FF F9 FF FF FF F9 FF

    example:

    [b]VAR[/b]
       [b]long[/b]  Temp1
       [b]long[/b]  Temp2
       [b]word[/b]  Temp3
       [b]byte[/b]  Temp4
       [b]byte[/b]  Temp5
    
    [b]PUB[/b] start
    [b]cognew[/b](@entry,@Temp1)' 'pass address of Temp1: first element of array
    
    [b]DAT[/b]
    entry  [b]mov[/b]    t1,[b]par[/b]
           [b]rdlong[/b] t2,t1     't2 receives Temp1
           [b]add[/b]    t1,#4     '<--Add offset of 4 for next LONG
           [b]rdlong[/b] t2,t1     't2 receives Temp2
           [b]add[/b]    t1,#4     '<--Add offset of 4 for next LONG
           [b]rdlong[/b] t2,t1     't2 receives Temp3,Temp4, and Temp5
    
    t1     [b]res[/b]    1
    t2     [b]res[/b]    1
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 7/9/2007 3:53:56 AM GMT
  • ericballericball Posts: 774
    edited 2007-07-09 17:19
    deSilva said...
    (1) How should the compiler know which part of code is assumed to be put into which COG?
    COGINIT / COGNEW simply copies Address.long[noparse][[/noparse]0] through Address.long[noparse][[/noparse]495] to COGRAM and then starts executing at COGRAM[noparse][[/noparse]0].· (Yes, even if your PASM routine is only 10 instructions, 496 longs are copied.)· The ORG allows the compiler to translate any labels in the code to COGRAM addresses.
    ·
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2007-07-10 04:47
    I don't understand the line at napshr. Can someone explain generally, and specifically the #18/16/13?

    ' Nap
    '
    nap                     rdlong  t,#0                    'get clkfreq
    napshr                  shr     t,#18/16/13             'shr scales time
    



    (fragment from end of Keyboard.spin -- lines 432 - 435)
  • mirrormirror Posts: 322
    edited 2007-07-10 05:51
    Fred Hawkins said...
    I don't understand the line at napshr. Can someone explain generally, and specifically the #18/16/13?

    ' Nap
    '
    nap                     rdlong  t,#0                    'get clkfreq
    napshr                  shr     t,#18/16/13             'shr scales time
    



    (fragment from end of Keyboard.spin -- lines 432 - 435)
    This is a little bit of the wonder of Propeller. The #18/16/13 is essentially a
    comment, which warns you that this line of code is modified elsewhere in the
    assembly code. Look for the other references to napshr, they're the ones that
    are actually modifying this line of code.



    ·
  • deSilvadeSilva Posts: 2,967
    edited 2007-07-10 12:20
    ... and every author invents his own idioms. You can be sure, that when something "senseless" is stated in an address field it is a hint that it will be patched.

    Ex.:
    0 highly improbably address value, as the first instruction is located here
    0-0 absolutely redundant because 0-0 == 0
    #18/16/13 makes no sense, as yields 0; wants to say: "Will be patched with 18 or 16 or 13 respectively"

    Edit:
    RDLONG .., #0
    might also be confusing, though is well commented smile.gif

    Ref. to the manual "....There are two values stored in the initialization area that might be of interest to your program:
    a long at $0000 contains the initial master clock frequency, in Hertz, and a byte following it
    at $0004 contains the initial value written into the CLK register. These two values can be
    read/written using their physical addresses (LONG[noparse][[/noparse]$0] and BYTE[noparse][[/noparse]$4])"


    Post Edited (deSilva) : 7/10/2007 12:29:34 PM GMT
Sign In or Register to comment.