Shop OBEX P1 Docs P2 Docs Learn Events
Passing multiple variables to asm - Page 2 — Parallax Forums

Passing multiple variables to asm

2

Comments

  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-22 22:11
    Well ... let's see what's wrong here ;o)

    [color=red]' This is a driver object, which will be used in some other SPIN, isn't it?
    ' So, you don't want the output_num variable to be in this file because then the other SPIN which uses the driver can not access the output
    ' Instead you have to do the same that you do with note and the cuelist - pass the adress.
    [/color][color=red]' PS: Now I recognized that you have changed LEDdrivercall to return the output value. So, it's some kind of mixed philosophy. For note ans cuelist you 
    [/color][color=red]' allow the other SPIN to maintain it, whereas you don't allow it to access output directly. I'd do it either this way or that way.
    [/color]VAR
      [color=orange]' somewhere in this thread we had the problem of passing mixed type parameters to PASM. There we had the problem, that PropTool is reordering
      ' the variables and we can not simply pass one adress to PASM and rely on the fact that all variables are in a row. That's why we had the idea
      ' to put several adresses in a single long named note_cuelisr_addr. Now we have an additional adress we need to pass. This does no longer fit
      ' into a long because HUB RAM adresses need 16 bit. That's why I switched to a word array now. 
      ' Please note: this is only needed, if note, output and cuelist have different types!
      ' If all have the same type we can rely on the fact that the order in memory is the same as the order of the definition. Then we only need to
      ' pass one adress. (To be honest I think the types are the same ... but OK, you'll learn more if we get it running this way)
      word  parameter_adr[noparse][[/noparse] 3 ] [s]note_cuelist_addr, output_num[/s][/color]
       
    
    PUB start([color=red]note_addr,output_addr[/color], cuelist_addr)
    
    [color=green]  word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse]0] := [b][color=red]@note[/color][/b]                  ' Pointer for note value
    [/color][color=green]  [color=orange]' again, THIS IS A NONO!!!!! Don't pass a adress that points to a variable on the stack, unless you know what it means[/color]
      word[noparse][[/noparse]note_cuelist_addr] [/color][color=green]:= @output_num               ' Pointer for value returned
    [/color][color=green]  [color=red]' ^ this will directly overwrite the value stored before becauese word[noparse][[/noparse] note_cuelist_addr ] is equal to word[noparse][[/noparse] note_cuelist_addr ][noparse][[/noparse] 0 ][/color]
      long[noparse][[/noparse]note_cuelist_addr][/color][color=green] := @cuelist_addr             ' Put the cutelist pointer in HUB ram
      [color=orange]' ^ this will overwrite everything stored in note_cuelist_addr before[/color]
    [/color][color=green]
      ' with the change of the variable the whole block looks a bit easier, as we simply can take the adresses passed to the function
      ' and store these in the parameter_adr array
      parameter_adr[noparse][[/noparse] 0 ]:=note_addr
    [/color][color=green]  parameter_adr[noparse][[/noparse] 1 ]:=output_addr
    [/color][color=green]  parameter_adr[noparse][[/noparse] 2 ]:=cuelist_addr
    [/color]  
      cognew(@entry, [color=green]@parameter_adr[/color])            
    
    { PUB LEDdrivercall                                         ' Used to get the value back from the operation
         
    return output_num }
    [color=red]' this no longer fits to the variables. The SPIN using this object has direct access to the output variable.
    [/color]
    DAT
                           org      0
    
                          ' When the cog starts par is initialized with the address passed in the coginit command
                          ' in this case it was passed @note_cuelist_addr.
    entry                   mov     ptr1,par                 ' load parameter pointer into ptr (points to global variables)
                                                             ' ptr is just a copy and keeps par unchanged for later.
                            [color=green]' up to here your PASM code looks good ;o)[/color]
                            mov     ptr2,par                 ' We need a second copy of the pointer for cuelist
                            [color=red]' but I don't know why you need an exact copy of par again
    [/color]                                      
    [color=orange]' having :start here only makes sense, if the pointer to note can change. But usually you would use the same buffer as long as the driver is running.[/color]
    [s]:start[/s]                  rdword  note_ptr,ptr1            ' Read the note pointer address from pointer1
                            [color=red][s]add     ptr1,note_ptr            ' move pointer1 to the note data[/s]
                            ' note_ptr IS pointing to the note data. What you did here was @note + @note_cueList_adr. Unpredictable to what this will point.
    [/color]
    [color=green]:start[/color]                  rdbyte  note_val,[color=green]note_[/color]ptr[s]1[/s]   wz  ' Read the note value
                            [color=purple]' it's a good idea to have a waitcnt here with an adequate waittime, because it saves energy. The waittime depends on
                            ' the needed responsiveness. If you have time critical stuff to do, don't wait, if not wait as long as possible.[/color]
                  if_z      jmp     #:start                  ' If the note value is zero start again                                                         
                            add     ptr2,#4                  ' Move pointer2 to the address of cuelist   
                            rdlong  list_ptr,ptr2            ' Read cuelist address
                            ' move getting list_ptr to where you get note_ptr
                            [s]add     ptr2,list_ptr            ' Move the pointer 2 to cuelist data[/s]
    
    :loop                   rdbyte  list,list_ptr[s]2[/s]                ' get the first byte of the byte array (cuelist)
                            cmp     list,note_val   wz       ' Compare a byte of cuelist with note_val
                  if_z      jmp     #:output_on              ' if zero go to a jump
                            add     count,#%0_0000_0001      ' Increment count
                            cmp     count,#%0_0111_1111 wz   ' compare count with 127
                  if_z      jmp     #:output_on              ' if count = 127 jump
                            add     ptr2,#1                  ' Move pointer2 to the next byte (of the array cuelist)
                            jmp     #:loop                   ' Jump back to the beginning of the loop
    
    :output_on              add     ptr1,#2                  ' Move ptr1 to the return value space
                            rdword  count_ptr,ptr1           ' Read the count pointer address
                            ' I would prepare a out_ptr at the same place you get the other pointers and use that. Then you don't need to calculate here.
                            [s]add     ptr1,count_ptr           ' move the pointer to the counter data space[/s]
                            wrlong  count, ptr1              ' Output the count value
                            mov     note_val,#0
                            [color=orange]wrlong  note_val, note_ptr       ' otherwise SPIN can not synchronize and :start will immediately run again
    [/color]                        
                            jmp     #:start [s]entry[/s]                   ' not sure about this jump, should it be to :start?
                        
    
                           ' These variables are in cog ram!
    
    ptr1                    long    0
    ptr2                    long    0 
    count                   long    0
    count_ptr               word    0
    [color=red]cue_ptr                 long    0
    [/color]' cue_ptr can not be used by PASM instructions because it does not point to a long-aligned-adress. You should have all words behind the longs
    ' and all bytes behind words. But still handling will be more difficult. Better to use long as long as you don't run out of COG RAM. 
    list_ptr                long    0
    list                    long    0
    note_val                long    0
    note_ptr                word    0
    test_num                long    0
    
                            fit 496
    

    I give it up for this night ;o) Maybe I should simply write the driver for you and explain what I did for what reason.
  • James LongJames Long Posts: 1,181
    edited 2009-04-22 22:25
    Just as a quick note.

    The code does have these in it, but it doesn't show for some reason:

    word[noparse][[/noparse]note_cuelist_addr](1) := @output_num
    long[noparse][[/noparse]note_cuelist_addr](1) := @cuelist_addr

    Had to use "(" to get them to show this time.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • James LongJames Long Posts: 1,181
    edited 2009-04-22 22:43
    I really want to figure this out, so you writing the driver really doesn't help.

    I'm still working on it.......have to digest what you wrote the last time.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • James LongJames Long Posts: 1,181
    edited 2009-04-22 23:36
    Blah, I'm sure everyone reading this thread is tired of my posting.

    another edition.

    Yea I have edited about 4 times on here already.

    VAR
    
      word  note_cuelist_addr
       
    
    PUB start(note_addr, output_addr, cuelist_addr)
    
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse]0] := @note_addr                ' Pointer for note value
      word[noparse][[/noparse]note_cuelist_addr](1) := @output_addr              ' Pointer for value returned
      word[noparse][[/noparse]note_cuelist_addr](2) := @cuelist_addr             ' Put the cutelist pointer in HUB ram
    
      "(" is only for the forums. the address is actually a "[noparse][[/noparse]"
      
      cognew(@entry, @note_cuelist_addr)            
    
    {{PUB LEDdrivercall                                       ' Commented out, but left for clarity
         
    return output_num}}
    DAT
                           org      0
                          ' When the cog starts par is initialized with the address passed in the coginit command
                          ' in this case it was passed @note_cuelist_addr.
    entry                   mov     ptr,par                  ' Set register ptr to equal Par
                   
    :start                  rdword  note_ptr,ptr             ' Read the note pointer address from pointer1
                            rdbyte  note_val,note_ptr     wz ' Read the note value from the address
                            waitcnt                          ' Not sure how long to wait.
                  if_z      jmp     #:start                  ' If the note value is zero start again                                                         
                            add     ptr,#2                   ' Move ptr to the return value space?? Is there a space?
                            rdword  output_ptr,ptr           ' Read the output pointer address
                            add     ptr,#2                   ' Move pointer to the address of cuelist   
                            rdword  list_ptr,ptr             ' Read cuelist address
    
    :loop                   rdbyte  list,list_ptr            ' get the first byte of the byte array (cuelist)
                            cmp     list,note_val         wz ' Compare a byte of cuelist with note_val
                  if_z      jmp     #:output_on              ' if zero go to a jump
                            add     count,#%0_0000_0001      ' Increment count
                            cmp     count,#%0_0111_1111   wz ' compare count with 127
                  if_z      jmp     #:output_on              ' if count = 127 jump
                            add     ptr,#1                   ' Move pointer to the next byte (of the array cuelist)
                            jmp     #:loop                   ' Jump back to the beginning of the loop
                                                             
    :output_on                                               ' The following I'm not sure if I understand.
                            wrbyte  count,output_ptr         ' Output the count value
                            mov     note_val,#0              ' Set note Value to zero
                            wrbyte  note_val,note_ptr        ' How does this work??
                            jmp     #:start                  ' Back to start
    
                           ' These variables are in cog ram!
    
    ptr                     long    0                      'not sure if any of these are right.
    note_ptr                word    0 
    output_ptr              word    0
    list_ptr                word    0
    count                   byte    0  
    note_val                byte    0 
    list                    byte    0
    
    
                            fit 496
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services

    Post Edited (James Long) : 4/23/2009 1:35:42 AM GMT
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-23 09:13
    That's bad! The forum offered the "Post reply" button, but when I was done with my post (which took ~30min) it told me that I have no rights to post. Obviously a timeout occurred. All changes were lost. freaked.gif

    Ok ... let's try again (with saving from time to time, so please be aware that this post might change while you read it until i write DONE at the end)

    James .. the goal comes closer ;o)

    VAR
    
      word  note_cuelist_addr
    [color=green]  ' I assume the [noparse][[/noparse] 3 ] has been swallowed by the forum software again?! You should have spaces between the square brackets and the number, otherwise[/color]
    [color=green]  ' forum software interprets it as 'set textsize'[/color]
       
    
    PUB start(note_addr, output_addr, cuelist_addr)
    
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse]0] := @note_addr                ' Pointer for note value
      word[noparse][[/noparse]note_cuelist_addr](1) := @output_addr              ' Pointer for value returned
      word[noparse][[/noparse]note_cuelist_addr](2) := @cuelist_addr             ' Put the cutelist pointer in HUB ram
    
      "(" is only for the forums. the address is actually a "[noparse][[/noparse]"
      
      cognew(@entry, @note_cuelist_addr)            
    
    {{PUB LEDdrivercall                                       ' Commented out, but left for clarity
         
    return output_num}}
    DAT
                           org      0
                          ' When the cog starts par is initialized with the address passed in the coginit command
                          ' in this case it was passed @note_cuelist_addr.
    entry                   mov     ptr,par                  ' Set register ptr to equal Par
                   
    
    [color=purple]                        ' I think we have a different understanding of how the driver should work. My understanding is that you pass the pointers to[/color]
    [color=purple]                        ' note, output and cuelist once. Your understanding seems to be that these pointers might change. For example your SPIN that uses[/color]
    [color=purple]                        ' the driver has several notes and several cuelists and can decide which to take for decoding.[/color]
    [color=purple]                        ' Ok, I'll adapt my understanding and we will first try to get this running like you want it. Later on we can optimize.[/color]
     
    :start                  rdword  note_ptr,ptr             ' Read the note pointer address from pointer1
    [color=red]                        ' first problem: this only works for the first iteration.[/color]
    [color=red]                        ' In entry you set ptr to par, so for the first run you get the right pointer. But later on in the code you change ptr.[/color]
    [color=red]                        ' You add 2 for getting output_ptr and again 2 for getting the list_ptr. This is OK as such. But when you come back to :start[/color]
    [color=red]                        ' ptr still points to the parameter which gives you the list_ptr. Either you have to subtract 4 after you read the last _ptr[/color]
    [color=red]                        ' or you do a jump to entry to get ptr reinitialized
    [/color]                        rdbyte  note_val,note_ptr     wz ' Read the note value from the address
                            [s]waitcnt[/s]                          ' Not sure how long to wait.
    [color=orange]                        ' waitcnt works a bit different than you think. You first have to calculate the cnt-value for which you want to wait.[/color]
    [color=orange]                        ' if_z mov  cnt_val, cnt[/color]
    [color=orange]                        ' if_z add  cnt_val, waittime[/color]
    [color=orange]                        ' if_z waitcnt cnt_val, #0[/color]
    [color=orange]                        ' as I said - first we get this running. Later on we can optimize this.[/color]
    [color=orange]                        ' You have to create the PASM variables cnt_val and waittime at the end of the code. The if_z simply skips the wait when we[/color]
    [color=orange]                        ' know that we want to do something.[/color]
    [color=orange]                        ' Again: waiting here is some kind of energy optimization - if you want it to be runtime optimized, then don't wait at all.
    [/color]              if_z      jmp     #:start                  ' If the note value is zero start again                                                         
                            add     ptr,#2                   ' Move ptr to the return value space?? Is there a space?
                            rdword  output_ptr,ptr           ' Read the output pointer address
                            add     ptr,#2                   ' Move pointer to the address of cuelist   
                            rdword  list_ptr,ptr             ' Read cuelist address
    
    :loop                   rdbyte  list,list_ptr            ' get the first byte of the byte array (cuelist)
                            cmp     list,note_val         wz ' Compare a byte of cuelist with note_val
                  if_z      jmp     #:output_on              ' if zero go to a jump
                            add     count,#%0_0000_0001      ' Increment count
    [color=red]                        ' Do you compile your code? I guess no, because this should produce a compile-error[/color]
    [color=red]                        ' The label count is not pointing to a long aligned adress. For the third time: please use long as PASM variables as long as[/color]
    [color=red]                        ' you don't have a better understanding. We can talk about that later.[/color]
    [color=red]                        ' And again: this will only work as desired in the first iteration, because count is never set to 0 again.[/color]
    [color=red]                        ' So, in the second conversion count will already be 127 - then you add 1. For the following compare it means it has to wait until[/color]
    [color=red]                        ' count wrapped around and got 127 again. Result you will reach memory-adresses which are outside of the cue-list and compare your[/color]
    [color=red]                        ' note_val with unpredictable data
    [/color]                        cmp     count,#%0_0111_1111   wz ' compare count with 127
                  if_z      jmp     #:output_on              ' if count = 127 jump
                            add     ptr,#1                   ' Move pointer to the next byte (of the array cuelist)
                            jmp     #:loop                   ' Jump back to the beginning of the loop
                                                             
    :output_on                                               ' The following I'm not sure if I understand.
                            wrbyte  count,output_ptr         ' Output the count value
                            mov     note_val,#0              ' Set note Value to zero
                            wrbyte  note_val,note_ptr        ' How does this work??
    [color=orange]                        ' In note_val you have a 0. So, you write the 0 to the memory location where you find the SPIN variable note.[/color]
    [color=orange]                        ' This has two effects. First thing is that your PASM driver will go back to :start. There you read note again. As nobody changed it[/color]
    [color=orange]                        ' the next conversion would start immediately. That's why you have to set note to 0 - then the driver waits until SPIN put a new[/color]
    [color=orange]                        ' value there. The other thing is that you now have the possibility to synchronize the SPIN code with the driver.[/color]
    [color=orange]                        ' note := "c"              -> this starts the lookdown[/color]
    [color=orange]                        ' repeat while note        -> this waits as long as lookdown is running
    [/color]                        jmp     #:start                  ' Back to start
    
                           ' These variables are in cog ram!
    
    ptr                     long    0                      'not sure if any of these are right.
    note_ptr                [s]word[/s]    0 
    output_ptr              [s]word[/s]    0
    list_ptr                [s]word[/s]    0
    count                   [s]byte[/s]    0  
    note_val                [s]byte[/s]    0 
    list                    [s]byte[/s]    0
    [color=red]' Use long instead.[/color] 
    
    
    ' cnt_val               long    0
    ' waittime              long    clkfeq/1000
    [color=orange]' Well, the waittime depends on how long you can wait for a decode. In this case the driver will check ~1000 times per second. This means that the[/color]
    [color=orange]' lookdown could need something between runtime and runtime + 1ms until we have the result in output. So, it very much depends on which responsiveness[/color]
    [color=orange]' you need in your application.
    [/color]                        fit 496
    
    

    Now some words for better understanding the problem with the words and bytes in PASM:

    The propeller has two different adress-busses with different adress ranges and different organisation.
    One adress-bus is the COG-RAM adress-bus. It's 9 bit wide, so it ranges from 0-512 ($000-$1FF / %0_0000_0000 - %1_1111_1111). As you can read in the propeller specs, each COG has 2kBytes of RAM. So not each byte has it's own adress! Each adress points to a LONG (4 byte) instead. 4Bytes x 512Adresses·= 2kBytes.
    PASM runs in COG-RAM and only knows LONG-adresses. Now let's have a look on the latest code from you and let's assume the variables would be placed at adress $100 (256 in decimal).

    $100 = ptr··········
    -> so, each PASM command using ptr will use adress $100 ( mov ptr, par will be translated to mov $100, $1f0 [noparse][[/noparse]I'm not sure if PAR really is at $1f0 and I am to
    lazy to search for it currently - so let's simply assume it's true]

    $101 = list_ptr, count and note_val
    -> as memory adress $101 is a long it can hold more data than just the list_ptr which is a word. But for PASM only the label list_ptr makes sense. Count would be at adress 256,5 and note_val would be at adress 256,75 ;o) But we don't have fractional adresses. So, when you want to access count in PASM you have to use the long which includes
    count. But then count is not at bit 0-7 but on bits 16-23. Adding 1 would change list_ptr and not count. To extract count needs some extra steps which increases runtime and
    memory usage. And that's why I said: You have to know what you do if you use different data types for you PASM variables.

    $102 = list and 3 undefined bytes

    And why does the compiler then allowes labels for words and bytes. Well ... because DAT is only data. Data can have different meanings, it could be image data ... or sound data ... whatever. In our dat section the data is a list of PASM opcodes and PASM variables. Please remember, the whole SPIN file first is placed in HUB-RAM. The HUB has it's own adress bus, which is 16 bits wide, ranging from 0 to 65535. With the first 32k-adresses you·can access RAM with the second 32k-adresses you can access the buildin ROM.
    And of course in SPIN you are allowed to read/write bytes, words and longwords from HUB-memory and there you can use those labels.

    DONE hop.gif

    Post Edited (MagIO2) : 4/23/2009 10:45:45 AM GMT
  • James LongJames Long Posts: 1,181
    edited 2009-04-23 18:42
    Wow, I understood all of that.

    Rather than posting code at the moment, I'll answer the few inaccuracies I may have created.

    Cuelist is always the same byte array. This information never changes. The notes on the other hand do change, but they should be placed in the same place (address) every time (my thinking).

    Your right, I will need to reset count and ptr.

    I knew waitcnt worked differently, but do not have a clue how long to wait.

    I now understand the long aligned problem. I greatly appreciate your explanation. For now, I'll use long values. I'm not sure if I am ready for any other alignment. It appear very difficult to deal with.

    When I get a chance I'll rewrite, and post the code.

    James

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • James LongJames Long Posts: 1,181
    edited 2009-04-23 19:14
    I just omitted waitcnt for now, but left a place for it.

    
    VAR
    
      word  note_cuelist_addr[noparse][[/noparse] 3 ]
       
    
    PUB start(note_addr, output_addr, cuelist_addr)
    
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 0 ] := @note_addr                ' Pointer for note value
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 1 ] := @output_addr              ' Pointer for value returned
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 2 ] := @cuelist_addr             ' Put the cutelist pointer in HUB ram
      
      cognew(@entry, @note_cuelist_addr)            
    
    DAT
                           org      0
                          ' When the cog starts par is initialized with the address passed in the coginit command
                          ' in this case it was passed @note_cuelist_addr.
    entry                   mov     ptr,par                  ' Set register ptr to equal Par
                   
    :start                  rdword  note_ptr,ptr             ' Read the note pointer address from pointer
                            rdbyte  note_val,note_ptr     wz ' Read the note value from note pointer address
                                                             ' Waitcnt goes here
                  if_z      jmp     #:start                  ' If the note value is zero start again                                                         
                            add     ptr,#2                   ' Move ptr to the output address
                            rdword  output_ptr,ptr           ' Read the output pointer address
                            add     ptr,#2                   ' Move pointer to the address of cuelist   
                            rdword  list_ptr,ptr             ' Read cuelist address
    
    :loop                   rdbyte  list,list_ptr            ' Read the first byte of the byte array from list_ptr address
                            cmp     list,note_val         wz ' Compare byte with note_val
                  if_z      jmp     #:output_on              ' if zero go to a jump
                            add     count,#%0_0000_0001      ' Increment count
                            cmp     count,#%0_0111_1111   wz ' compare count with 127
                  if_z      jmp     #:output_on              ' if count = 127 jump
                            add     list_ptr,#1              ' Move pointer to the next byte ( array cuelist)
                            jmp     #:loop                   ' Jump back to the beginning of the loop
    
    :output_on              wrlong  count,output_ptr         ' Output the count value to the output address
                            mov     note_val,#0              ' Set note Value to zero
                            wrlong  note_val,note_ptr        ' Setting note_ptr to 0 (synchronizes Spin)
                            mov     count,#0                 ' Reset Count to 0
                            sub     ptr,#4                   ' Back up the ptr to origin.
                            jmp     #:start                  ' Back to start
    
                           ' These variables are in cog ram!
    
    ptr                     long    0                      
    note_ptr                long    0 
    output_ptr              long    0
    list_ptr                long    0
    count                   long    0  
    note_val                long    0 
    list                    long    0
    
    
                            fit 496
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services

    Post Edited (James Long) : 4/23/2009 7:27:56 PM GMT
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-23 20:54
    Bingo!
    This seems to me like it could work. (I did not try it) Now we can start with some optimizations:
    Let's think about that: "... but they should be placed in the same place (address) every time" you talked about note and cuelist.
    So, why do you read the adresses with each iteration? When the adresses of note and cuelist never change, there is no need to read the adresses with each
    loop. Just do it in the initialisation phase of your PASM.
    Your version:                       org      0
    entry                   [s]mov     ptr,par[/s]                  ' Set register ptr to equal Par
                   
    [s]:start[/s] list_act:        rdword  note_ptr,par[s]ptr[/s]          ' Read the note pointer address from pointer
                            [s]rdbyte  note_val,note_ptr     wz ' Read the note value from note pointer address
    [/s]                                                         ' Waitcnt goes here
                 [s] if_z      jmp     #:start                  ' If the note value is zero start again[/s]                                                         
                            add     par[s]ptr[/s],#2                   ' Move ptr to the output address
                            rdword  output_ptr,par[s]ptr[/s]           ' Read the output pointer address
                            add     par[s]ptr[/s],#2                   ' Move pointer to the address of cuelist   
                            rdword  list_ptr,par[s]ptr[/s]             ' Read cuelist address
     
    [color=red]                        ' now you have the pointers to note, output and list in COG-RAM. No need to read it again and again, if these[/color]
    [color=red]                        ' don't change[/color]
     
    :start                  rdbyte  note_val, note_ptr   wz
                    if_z    jmp     #:start
    [color=orange]                        ' but now we should not change the list pointer, so we copy that and work with the copy in the :loop[/color]
                            mov     list_act, list_ptr
    [color=red]                        ' we never need the code above :start again, so we can overwrite with runtime variables. The time will come, when you need[/color]
    [color=red]                        ' each long for your PASM code to fit into the COG-RAM ;o) Note: you could even move the _ptr variables to the top. Then[/color]
    [color=red]                        ' you won't need a single long.[/color]
     
    :loop                   rdbyte  list,list_act[s]ptr[/s]            ' Read the first byte of the byte array from list_ptr address
                            cmp     list,note_val         wz ' Compare byte with note_val
                  if_z      jmp     #:output_on              ' if zero go to a jump
                            add     count,#%0_0000_0001      ' Increment count
                            cmp     count,#%0_0111_1111   wz ' compare count with 127
    [color=orange]                        ' a little exercise: if you count from 127 down (instead of up), you could have 2 instructions less in the loop[/color]
    [color=orange]                        ' so, in worst case you have 127 * 2 instructions less. Tip: DJNZ is your friend here. But you have to reorder stuff[/color]
    [color=orange]                        ' a little bit. And when you found the note in the list, you have to calculate the right count (=127-count) 
    [/color]              if_z      jmp     #:output_on              ' if count = 127 jump
                            add     list_act[s]ptr[/s],#1              ' Move pointer to the next byte ( array cuelist)
                            jmp     #:loop                   ' Jump back to the beginning of the loop
     
    :output_on              wrlong  count,output_ptr         ' Output the count value to the output address
                            [s]mov     note_val,#0[/s]              ' Set note Value to zero
    [color=red]                        ' there is no need to set note_val to zero, as we read a fresh value everytime[/color]
    [color=red]                        ' so, for clearing note_ptr you could use a different zero, after some reordering of the code
    [/color]                        wrlong  note_val,note_ptr        ' Setting note_ptr to 0 (synchronizes Spin)
                            mov     count,#0                 ' Reset Count to 0
                            [s]sub     ptr,#4[/s]                   ' Back up the ptr to origin.
                            jmp     #:start                  ' Back to start
    
    
    
     
    [s]ptr                     long    0[/s]                      
    note_ptr                long    0 
    output_ptr              long    0
    list_ptr                long    0
     
    

    PAR is nothing else than·a COG-RAM adress with the purpose of passing one parameter to the PASM. This is called a special register. As it's simply COG RAM you can
    change PAR and there is no need to copy PAR to PTR.

    Nice, isn't it? We reduced size by 6 longs, with potential of saving another 5 longs (if you follow my hints). And we reduced runtime of the loop.

    Happy digesting ... then the next optimizations will follow ;o)
    ·
  • James LongJames Long Posts: 1,181
    edited 2009-04-24 01:19
    I'm not sure how 6 longs were saved.

    I have reordered the code some to use djnz.

    As for moving them to the top, I'm not sure what you mean. Also, I'm not sure where to get another zero from the code. The count will not always come to zero.

    You may be thinking of an arrangement I can't not see at this point. Using spin for so long, I guess habits are hard to break.

    I've omitted everything above the DAT to save space.

    DAT
                           org      0
                          ' When the cog starts par is initialized with the address passed in the coginit command
                          ' in this case it was passed @note_cuelist_addr.
    entry       
                   
    : pointers               rdword  note_ptr,par             ' Read the note pointer address from pointer  (had to add a space between : and p)
                            add     par,#2                   ' Move ptr to the output address
                            rdword  output_ptr,par           ' Read the output pointer address 
                            add     par,#2                   ' Move pointer to the address of cuelist   
                            rdword  list_ptr,par             ' Read cuelist address
    
    :start                  rdbyte  note_val,note_ptr     wz ' Read the note value from note pointer address
                                                             ' Waitcnt goes here
                  if_z      jmp     #:start                  ' If the note value is zero start again
                            mov     list_loc,list_ptr        ' Copy the list pointer to list location
                                                             '   copied to prevent needing to reset list_ptr on
                                                             '   each iteration
                            mov     count,#127               ' set Count to 127
    
                            
    :loop                   rdbyte  list,list_loc            ' Read the byte (moves with loop) of the byte array
                                                             '    from list_loc address                        
                            cmp     list,note_val         wz ' Compare byte with note_val
                  if_z      jmp     #:output_on              ' If the values match jump to output on
                            add     list_loc,#1              ' Move pointer to the next byte(array cuelist)
                            cmp     count,#0              wz ' compare Count with 0
                            djnz    count,#:loop             ' If the values do not match decrement count and jump to loop                             
    
    :output_on              wrlong  count,output_ptr         ' Output the count value to the output address
                            mov     note_val,#0              ' not sure where to get another 0??
                            wrlong  note_val,note_ptr        ' Setting note_ptr to 0 (synchronizes Spin)                        
                            jmp     #:start                  ' Back to start
    
                           ' These variables are in cog ram!
    
    list_loc                long    0     
    note_ptr                long    0 
    output_ptr              long    0
    list_ptr                long    0
    count                   long    0  
    note_val                long    0 
    list                    long    0
    
    
                            fit 496
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services

    Post Edited (James Long) : 4/24/2009 2:17:07 AM GMT
  • James LongJames Long Posts: 1,181
    edited 2009-04-24 02:26
    I really hope some other soul out there is also getting something from all of this. I put off learning Pasm for a long time, and the threshold had been reached.

    If you are out there, and have hit that point, some public airing of the laundry may be needed. I hate to show how hard it is for me to learn something like Pasm, but I feel the end justifies the means.

    If you are following, I hope your light went on before mine did.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-24 06:53
    Hi James!

    It seems like we're alone in this thread.

    If I count the lines which have been striked out I count 6 lines. This means we saved 6 longs in comparision to the version before.
    You are right with what you say about the zero. I forgot about the other tip to use DJNZ. That of course means that counter is no longer initialized with zero.

    ······················· ' we never need the code above :start again, so we can overwrite with runtime variables. The time will come, when you need
    ························' each long for your PASM code to fit into the COG-RAM ;o) Note: you could even move the _ptr variables to the top. Then
    ······················· ' you won't need a single long.

    What I mean is: From label entry up to label :start we have some code which is only needed on the first call of our driver. When calling cognew( @entry, @note_cuelist_addr ). All the jump we have in the code don't go back to the very beginning. So, here we have 5 longs that we can use in our loops. By doing so, we can save some memory at the end.

    entry note_ptr                rdword  note_ptr,par             ' Read the note pointer address from pointer  (had to add a space between : and p)
    output_ptr              add     par,#2                   ' Move ptr to the output address
    list_ptr                rdword  output_ptr,par           ' Read the output pointer address 
    list_loc                add     par,#2                   ' Move pointer to the address of cuelist   
    count                   rdword  list_ptr,par             ' Read cuelist address
    
    ...
    
    [s]list_loc                long    0[/s]     
    [s]note_ptr                long    0[/s] 
    [s]output_ptr              long    0[/s]
    [s]list_ptr                long    0[/s]
    [s]count                   long    0[/s]  
    note_val                res     1 
    list                    res     1
    
    


    See what I mean? We reuse the memory. First it is filled with our code, but when the code ran we can use it as any other memory adress. So we saved another 5 longs. I know we don't need to save for this little driver, but if you learn to save memory you get familiar with it and you don't have to twist your brain when you really need it.
    Please be aware this not only saves memory in COG-RAM, it also saves memory in HUB-RAM as each long defined has a real memory adress and data in HUB-RAM.
    Of course you can only use this trick for variables which need not to be initialized.

    What does RES mean? Well, it's doing the same with the difference that it uses memory behind our code and long, word, byte definitions. That's very important! The RES·has to be used after all code AND variable declarations of the PASM snipped for one COG! Otherwise you have different labels point to the same memory adress. In opposite to long, RES does not put data to HUB-RAM, but you need some COG-RAM for it. So, if you used all 496 longs for code and data it's not possible to add a RES. Overwriting no longer needed memory is then the only way to have some extra room for variables.

    Hope this was understandable for you! Again in short form:
    long (and of course word and byte) needs memory in HUB-RAM and in COG-RAM and·they are·initialized it with a value.
    res points to an adress in COG-RAM and needs no memory in HUB-RAM - that's why you can only use it for variables which need not to be initialized by default.
    IMPORTANT: RES has to be defined AFTER code and long/word/byte of the PASM for one COG.

    In your code you still have one little obstacle:
    :loop                   rdbyte  list,list_loc            ' Read the byte (moves with loop) of the byte array
                                                             '    from list_loc address                        
                            cmp     list,note_val         wz ' Compare byte with note_val
                  if_z      jmp     #:output_on              ' If the values match jump to output on
                            add     list_loc,#1              ' Move pointer to the next byte(array cuelist)
                            [s]cmp     count,#0              wz ' compare Count with 0[/s]
                            [color=red]' you don't need to compare. DJNZ is doing the whole job ([color=green][b]D[/b][/color]ecrement and [color=green][b]J[/b][/color]ump if [b][color=green]N[/color][/b]ot [b][color=green]Z[/color][/b]ero). The cmp can not see if the decrement will[/color]
    [color=#ff0000]                        ' be zero or not.[/color]
                            djnz    count,#:loop             ' If the values do not match decrement count and jump to loop                             
    
    

    Ok ... now the code looks pretty good. Maybe I'll give it a try this evening/night. But we're not done with optimizing. Guess this thread will be a nice tutorial when we're done.
    What's to come next? I suggest that you now write the code which uses our driver. Based on that we can do more improvements.

    Post Edited (MagIO2) : 4/24/2009 11:07:14 AM GMT
  • James LongJames Long Posts: 1,181
    edited 2009-04-24 19:31
    Mag,

    Hmmmm.....I didn't even know that was legal. I do not think I have ever seen what you did here.
    entry
    note_ptr                rdword  note_ptr,par             ' Read the note pointer address from pointer  (had to add a space between : and p)
    output_ptr              add     par,#2                   ' Move ptr to the output address
    list_ptr                rdword  output_ptr,par           ' Read the output pointer address 
    list_loc                add     par,#2                   ' Move pointer to the address of cuelist   
    count                   rdword  list_ptr,par             ' Read cuelist address
    
    



    That is interesting. I didn't know that could be done. It is a totally new concept to me. I haven't paid a lot of attention to PASM in the past, so I may have missed this done before.

    As for the djnz, I missed that concept.

    The nice thing about this driver we built as it could be tested with nothing but hyperterminal. Doesn't really need any additional hardware. I am using a SD card to read data into the byte array, but there are ways around that.

    I actually have code I was writing this for, but it is a mess, and huge. I'm not sure that would be good to test with.

    I'll think about writing something to test with.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-24 22:05
    Did you already find the bugs?
    PUB start(note_addr, output_addr, cuelist_addr)
    
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 0 ] := [s][color=red]@[/color][/s]note_addr                ' Pointer for note value
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 1 ] := [s][color=orange]@[/color][/s]output_addr              ' Pointer for value returned
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 2 ] := [s][color=red]@[/color][/s]cuelist_addr             ' Put the cutelist pointer in HUB ram
    

    This is the bug in the SPIN-part. We don't want to pass the adresses of the start function parameters. We want the variable adresses which are passed to start when we call it:

    start( @note, @output, @cue_list )

    Already talked about that (never pass an adress of a function parameter) and still I did not see it this time ;o)

    [color=orange]' THIS was missing! I'm baffled a bit by myself ... have to think about that![/color]
    [color=orange]ptr                     rdlong  ptr,par[/color]
    note_ptr                rdword  note_ptr, ptr
    output_ptr              add     ptr, #2
    list_ptr                rdword  output_ptr, ptr
    list_loc                add     ptr, #2
    count                   rdword  list_ptr, ptr
                            [color=red]add     list_ptr, #127[/color]
    [color=#ff0000]                        ' that's not a bug, it only makes things easier. Count starts from 127 and counts down to 0. So, to look at the[/color]
    [color=#ff0000]                        ' place which matches with this count, we simply start at the end of the list[/color] 
     
    :start                  rdbyte  note_val,note_ptr     wz ' Read the note value from note pointer address
                                                             ' Waitcnt goes here
                  if_z      jmp     #:start                  ' If the note value is zero start again
                            mov     list_loc,list_ptr        ' Copy the list pointer to list location
                                                             '   copied to prevent needing to reset list_ptr on
                                                             '   each iteration
                            mov     count,#127               ' set Count to 127
                            
    :loop                   rdbyte  list,list_loc            ' Read the byte (moves with loop) of the byte array
                                                             '    from list_loc address                        
                            cmp     list,note_val         wz ' Compare byte with note_val
                  if_z      jmp     #:output_on              ' If the values match jump to output on
                            [color=orange]sub     list_loc,#1              ' Move pointer to the next byte(array cuelist)[/color]
    [color=orange]                        ' list location has to decrease then
    [/color]                        djnz    count,#:loop             ' If the values do not match decrement count and jump to loop                             
    :output_on
                            [color=red]wrbyte  count,output_ptr         ' Output the count value to the output address[/color]
    [color=red]                        ' here we had a wrlong. That's wrong when we deal with byte variables
    [/color]                        mov     note_val,#0              ' not sure where to get another 0??
                            [color=orange]wrbyte  note_val,note_ptr        ' Setting note_ptr to 0 (synchronizes Spin)[/color]                        
                            jmp     #:start                  ' Back to start
                           ' These variables are in cog ram!
    note_val                res     1 
    list                    res     1
    
                            fit 496
    

    But now it works.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-24 22:29
    Ah ... the dark clouds of dumbness dissappear.

    As you might know some bugs don't show up immediately! So, what was wrong with the part that baffled me?
    PUB start(note_addr, output_addr, cuelist_addr)
    
      [s]word[noparse][[/noparse][/s]note_cuelist_addr[s]][/s][noparse][[/noparse] 0 ] := note_addr                ' Pointer for note value
      [s]word[noparse][[/noparse][/s]note_cuelist_addr[s]][/s][noparse][[/noparse] 1 ] := output_addr              ' Pointer for value returned
      [s]word[noparse][[/noparse][/s]note_cuelist_addr[s]][/s][noparse][[/noparse] 2 ] := cuelist_addr             ' Put the cutelist pointer in HUB ram
    

    See the difference? Maybe you learned enough, so that you can explain it to me? And what makes this bug dangerous.
    Of course the code which reads the adresses has to be changed back now that we corrected this bug:
    [color=orange][s]ptr                     rdlong  ptr,par[/s][/color]
    note_ptr                rdword  note_ptr, par [s]ptr[/s]
    output_ptr              add     par [s]ptr[/s], #2
    list_ptr                rdword  output_ptr, par [s]ptr[/s]
    list_loc                add     par [s]ptr[/s], #2
    count                   rdword  list_ptr, par [s]ptr[/s]
    
    
    


    ·
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 00:05
    MagIO2 said...
    Ah ... the dark clouds of dumbness dissappear.


    As you might know some bugs don't show up immediately! So, what was wrong with the part that baffled me?



    PUB start(note_addr, output_addr, cuelist_addr)
    
      [s]word[noparse][[/noparse][/s]note_cuelist_addr[s]][/s][noparse][[/noparse] 0 ] := note_addr                ' Pointer for note value
      [s]word[noparse][[/noparse][/s]note_cuelist_addr[s]][/s][noparse][[/noparse] 1 ] := output_addr              ' Pointer for value returned
      [s]word[noparse][[/noparse][/s]note_cuelist_addr[s]][/s][noparse][[/noparse] 2 ] := cuelist_addr             ' Put the cutelist pointer in HUB ram 
    
    


    See the difference? Maybe you learned enough, so that you can explain it to me? And what makes this bug dangerous.
    Of course the code which reads the adresses has to be changed back now that we corrected this bug:



    
    [color=orange]ptr                    ][/color] 
    
    note_ptr                rdword  note_ptr, par <STRIKE>ptr
    output_ptr              add     par [s]ptr[/s], #2
    list_ptr                rdword  output_ptr, par [s]ptr[/s]
    list_loc                add     par [s]ptr[/s], #2
    count                   rdword  list_ptr, par [s]ptr[/s]
     
    
    
    


    Yep, you are right, I didn't see that either. Using the address of the address would be of little use.

    I would assume, because the way the items are declared, all of those are longs.

    But if that in fact the case, wouldn't the "add par, #2" need to be "add par, #4".

    Just my take on the subject.

    I know it didn't work with the last iteration with all of the variables declared at the bottom.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-25 00:28
    James Long said...
    But if that in fact the case, wouldn't the "add par, #2" need to be "add par, #4".
    Further up you declare note_cuelist_addr as

    word  note_cuelist_addr[noparse][[/noparse] 3 ]
    


    So +2 should be fine. What I have trouble with is the actual instruction

    add     par, #2
    


    PAR is a read-only register and can't be used as a destination (without unwanted side effects). Therefore you'll usually find stuff like this at the beginning if more than one parameter is to be passed into the PASM section.

    mov     rw_ptr, par
    rdword  value1, rw_ptr
    add     rw_ptr, #2
    rdword  value2, rw_ptr
    


    HTH
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 00:59
    HTH,

    If you scroll back up, you will see Mag suggest to initialize some of the data at the beginning of the PASM. Using the following:

    note_ptr                rdword  note_ptr, par
    output_ptr              add     ptr, #2
    list_ptr                rdword  output_ptr, par
    list_loc                add     ptr, #2
    count                   rdword  list_ptr, par
    
    


    If you notice par is not copied at all.

    What I don't understand is why the following will not work:
     word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 0 ] := note_addr                ' Pointer for note value
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 1 ] := output_addr             ' Pointer for value returned
      word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 2 ] := cuelist_addr            ' Put the cutelist pointer in HUB ram
    
    



    I'm not sure at this point why.

    I haven't done any deep thinking about it, so I may be missing the target.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-25 01:16
    James Long said...
    If you scroll back up, you will see Mag suggest to initialize some of the data at the beginning of the PASM. Using the following:

    note_ptr                rdword  note_ptr, par
    output_ptr              add     ptr, #2
    list_ptr                rdword  output_ptr, par
    list_loc                add     ptr, #2
    count                   rdword  list_ptr, par
    
    


    If you notice par is not copied at all.
    If you run this, then note_ptr, output_ptr and list_ptr are all the same as they are loaded from PAR. Unless that's a typo and should read ptr.

    Anyway I was referring to MagIOs last posting (starting with Ah ... the dark clouds of dumbness dissappear.) which I thought was up-to-date.
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 01:22
    Yes,

    You are right, it is a typo.

    the code should be:
    note_ptr                rdword  note_ptr, par
    output_ptr              add     par, #2
    list_ptr                rdword  output_ptr, par
    list_loc                add     par, #2
    count                   rdword  list_ptr, par
    
    



    Might be a typo on my part.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-25 01:24
    And that's exactly what doesn't work. ADD par, ??? doesn't do what you expect it to do.
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 01:26
    I have found what I believe to be the issue, but I'm not sure why it is an issue.

    Both are legal in Spin:
    word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 0 ] := note_addr                ' Pointer for note value
    word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 1 ] := output_addr             ' Pointer for value returned
    word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 2 ] := cuelist_addr            ' Put the cutelist pointer in HUB ram
    
    



    This is also legal, with the declarations in the previous post:
    note_cuelist_addr[noparse][[/noparse] 0 ] := note_addr                ' Pointer for note value
    note_cuelist_addr[noparse][[/noparse] 1 ] := output_addr             ' Pointer for value returned
    note_cuelist_addr[noparse][[/noparse] 2 ] := cuelist_addr            ' Put the cutelist pointer in HUB ram
    
    



    I have no idea why, but spin will let you do this.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 01:35
    I can't say one way or another. I believe Mag has written a top object to test with, and I have not.

    He may be doing something illegal with PAR, but I can not say. I'm just trying to learn.

    I know you can write to PAR, for Mike Green does it. I'm not sure what he is writing to PAR, but I have his exact code which does. I know it works. I'm using it.

    As for adding or subtracting, I have no idea.

    I have to take what I am taught at face value and assume the instructor has done these procedures before. Mag appears to know what can and can not be done, so I believe what he says is true.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-25 01:36
    when you write "word[noparse][[/noparse] note_cuelist_addr ]" you mean "the word whose address is contained in the value note_cuelist_addr". Does that mean what you think it means?
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 01:43
    Mike Green said...
    when you write "word[noparse][[/noparse] note_cuelist_addr ]" you mean "the word whose address is contained in the value note_cuelist_addr". Does that mean what you think it means?

    Mike,

    Just for comparison, for my use:

    When you do not use "word", what does it mean?

    I'm trying to learn this, and it is important for me to understand the significance of each.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-25 02:08
    James Long said...
    I have to take what I am taught at face value and assume the instructor has done these procedures before. Mag appears to know what can and can not be done, so I believe what he says is true.
    Yes, you can write to PAR but that write goes to the shadow copy. Using it as the source register (afterwards) will give you (again) the value passed into coginit/cognew. Just try it, pass a two value array (initialised with two different values) to cognew and try to get to the 2nd value by adding the relevant offset to PAR.

    Example for Hydra (adjust LED(6) pin for your setup):

    VAR
      long  array[noparse][[/noparse] 2]
        
    PUB init
      array[noparse][[/noparse] 0] := 42
      array[noparse][[/noparse] 1] := 24
      
      cognew(@entry, @array)
    
    DAT
    entry           mov dira, #1 << 6
    
                    rdlong  one, par
                    add     par, #4
                    rdlong  two, par
    
                    cmp     two, #24 wz
            if_z    or      outa, #1 << 6
    
    loop            waitcnt loop, #0
                    jmp     #loop
    
    one             long    0
    two             long    0
    


    If the LED stays dark, change the cmp instruction to cmp two, #42 wz.
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-25 02:22
    As for arrays, note_cuelist_addr[noparse][[/noparse]idx] is equivalent to word[noparse][[/noparse]@note_cuelist_addr][noparse][[/noparse]idx]. Just writing word[noparse][[/noparse]note_cuelist_addr] will give you a word array which starts at address note_cuelist_addr[noparse][[/noparse]0] (i.e. with whatever is in the first element).
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 02:22
    kuroneko said...
    James Long said...
    I have to take what I am taught at face value and assume the instructor has done these procedures before. Mag appears to know what can and can not be done, so I believe what he says is true.
    Yes, you can write to PAR but that write goes to the shadow copy. Using it as the source register (afterwards) will give you (again) the value passed into coginit/cognew. Just try it, pass a two value array (initialised with two different values) to cognew and try to get to the 2nd value by adding the relevant offset to PAR.

    Example for Hydra (adjust LED(6) pin for your setup):

    VAR
      long  array[noparse][[/noparse] 2]
        
    PUB init
      array[noparse][[/noparse] 0] := 42
      array[noparse][[/noparse] 1] := 24
      
      cognew(@entry, @array)
    
    DAT
    entry           mov dira, #1 << 6
    
                    rdlong  one, par
                    add     par, #4
                    rdlong  two, par
    
                    cmp     two, #24 wz
            if_z    or      outa, #1 << 6
    
    loop            waitcnt loop, #0
                    jmp     #loop
    
    one             long    0
    two             long    0
    


    If the LED stays dark, change the cmp instruction to cmp two, #42 wz.

    I'm not doubting what you are saying, but you are not initializing the variables like Mag did.

    At no time did he do like you have done above.

    He is just using variables to simulate a situation. This is what I understand to be happening.

    I understand what he is doing to be the following:
    note_ptr                rdword  note_ptr, par    <---- this is a variable equal to a word read from par
    output_ptr              add     par, #2             <---- this is a variable equal to par +2
    list_ptr                rdword  output_ptr, par   <-----this is a variable equal to word read from par + 2
    list_loc                add     par, #2               <-----this is a variable equal to par + 4
    count                   rdword  list_ptr, par      <-----this is a variable equal to word read from par + 4
    
    



    Like I said. I have not tested the code. We were using a copy of par before he changed the variables to the top of the PASM. Then he implemented the above code.

    To get into a deep discussion, you would really need to discuss it with Mag.

    as a side note, the # of list_loc may be wrong, but I believe this would work.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services

    Post Edited (James Long) : 4/25/2009 2:32:14 AM GMT
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 02:49
    Mag has spent a lot of time working with me to understand all of this, and we both have made a few errors. Well I have made more than a "few". I do not dare look back. I skip the whole lot, and get to the end. This is to prevent learning back bad information.

    thinking back on the whole topic, he may have meant the following:
    note_ptr                 rdword  note_ptr, par    <---- this is a variable equal to a word read from par
    count                  add     par, #2             <---- this is a variable equal to par +2
    output_ptr               rdword  output_ptr, count   <-----this is a variable equal to word read from par + 2
    list_loc                add     par, #4               <-----this is a variable equal to par + 4
    list_ptr                   rdword  list_ptr, list_loc      <-----this is a variable equal to word read from par + 4
    
    



    This would make more sense if using the variables for multi-purpose. I know he has to cope with a large amount of frustration dealing with me, which is bound to cause errors.

    Their use like I have above makes much more sense to me, but then again, it all doesn't make much sense at all.

    I'm still trying to get the "@" symbol right.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services

    Post Edited (James Long) : 4/25/2009 2:54:28 AM GMT
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-25 10:06
    It's already been mentioned, but as I asked I want to explain the thing in my own words now.

    word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 0 ] := note_addr                ' Pointer for note value
    word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 1 ] := output_addr             ' Pointer for value returned
    word[noparse][[/noparse]note_cuelist_addr][noparse][[/noparse] 2 ] := cuelist_addr            ' Put the cutelist pointer in HUB ram
    
    

    note_cuelist_addr is our word array. Variables are initialized with zero. SPIN is not typesafe. This means that you can use not_cuelist_addr as normal variable instead of as an array. My guess here is, that note_cuelist_addr is the same as note_cuelist_addr[noparse][[/noparse]0]. Maybe I'll check that out somewhen.
    So, what word[noparse][[/noparse] note_cuelist_addr ][noparse][[/noparse]0] will do is use content of note_cuelist_addr in the first dimension.
    word[noparse][[/noparse] 0 ][noparse][[/noparse] 0 ] simply points to $0000 in HUB-RAM.
    word[noparse][[/noparse] 0 ][noparse][[/noparse] 1 ] points to $0002 in HUB-RAM.
    word[noparse][[/noparse] 0 ][noparse][[/noparse] 2 ] points to $0004
    That means we overwrite a part in HUB-RAM with some special meaning. The first long in RAM for example is reserved for the SPIN internal variable clkfreq. And that's the dangerous part of this bug. If we later on have some code which reads clkfreq for calculating some timing it gets a wrong result and the timing will not be as expected. Now find that bug when your driver has been written·a half year ago·;o)

    As the note_cuelist_ptr is defined in the drivers var section we can simply write
    note_cuelist[noparse][[/noparse] 0 ] :=
    ...

    or alternativels

    word[noparse][[/noparse] @note_cuelist_addr ][noparse][[/noparse] 0 ] :=
    ...


    Why did it work with rdlong ptr, par? Because this added another level of indirection. First we got the content of note_cuelist_addr, which is zero. Then we read the content of $0000 into note_par which really contained the adress of note. So, I used a workaround for the bug, but did not fix it.

    Ok, the par is used in a wrong way. I really thought I saw my code working like that. I leaned my lesson!
    entry
    ptr                     mov     ptr,par             
    note_ptr                rdword  note_ptr, ptr
    output_ptr              add     ptr, #2
    list_ptr                rdword  output_ptr, ptr
    list_loc                add     ptr, #2
    count                   rdword  list_ptr, ptr
    
    


    So, this will work definitely.
    I attached my test-code to the post, so you can see that par as well. Guess this thread is long enough, so I don't put it in the post directly. We have to discuss enough other topics now ;o)
    The test needs the FullDuplexSerial and pleas adjust the clock-settings as I use a 10MHz crystal. Open the terminal and press any key and it will start after a second.

    @james:
    I'm not frustrated, I'm learning by explaining things. I just started with the prop a few weeks ago (or maybe one or two months - time is passing so fast when you do interesting things).
  • James LongJames Long Posts: 1,181
    edited 2009-04-25 19:10
    Mag,

    Well if nothing else, you are getting a chance to learn how to explain things in different ways. This is the secret of teaching someone.

    Now the main question, is this faster than a Spin lookdown statement?

    The reason I ask, the byte array I'm working with may be up to 128 words long. Yea, right now I'm working with byte, but the array may need to change to accommodate words.

    Putting this into lookdown is a problem. Because of the syntax of Spin, that line gets really long, and I haven't experienced a "wrap around" yet. I do not know of a way to cause a line to wrap around, so using a PASM lookdown seems to be the way to go.

    As for my inaccuracies with the word[noparse][[/noparse] 0 ][noparse][[/noparse] 0 ], that explains the problem I've been having. Before when i tried the code, my propeller would lock up. I was killing the reserved variables the prop needed to run.

    Now that the driver is written, I'm going to try it with my existing code that will do away with the regular lookdown.

    James L

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    James L
    Partner/Designer

    Lil Brother SMT Assembly Services
Sign In or Register to comment.