Shop OBEX P1 Docs P2 Docs Learn Events
Unaligned memory access — Parallax Forums

Unaligned memory access

Harrison.Harrison. Posts: 484
edited 2007-11-20 09:11 in Propeller 1
What would be the best way to perform unaligned HUB memory access? I have a 1518 byte array that I would like to be able to access via LONG[noparse]/noparse, WORD[noparse]/noparse, and BYTE[noparse]/noparse at even or odd addresses. I am currently doing shifts and independent BYTE[noparse]/noparse accesses, but that is messy and probably slow.

One last question, would the addition (+) or the bitwise OR (|) operator be faster for joining bytes into a long? I am assuming the bitwise OR would be, but I have no idea how SPIN handles this internally.

For example:
VAR
   byte buffer[noparse][[/noparse]1518]

PUB main | i
   i := LONG[noparse][[/noparse]@buffer + 3]                  ' may work if aligned?
   i := WORD[noparse][[/noparse]@buffer + 3]                 ' another maybe?
   i := BYTE[noparse][[/noparse]@buffer + 6] << 24 + BYTE[noparse][[/noparse]@buffer + 5] << 16 + BYTE[noparse][[/noparse]@buffer + 4] << 8 + BYTE[noparse][[/noparse]@buffer + 3]         ' this is what I have to do now




EDIT: I found some information here about unaligned access: http://forums.parallax.com/forums/default.aspx?f=25&p=1&m=148004 . I wasn't able to discern any real answers though, other than the fact that there will be corruption if I had longs, words, and bytes I wanted to access all in one long. My issue is I am accessing an ethernet packet that has longs, words, and bytes inside of byte aligned packets.

Harrison

Post Edited (Harrison.) : 11/18/2007 9:30:45 AM GMT

Comments

  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2007-11-18 15:50
    You can make use of the bytemove command to shift the Actual data into a temporary data location to read from...
    VAR
        long dummyData
        long ActualData[noparse][[/noparse]100]
        long ShiftedData[noparse][[/noparse]10]
    
     
    
    

        
    'PUB Block
     
        ActualData[noparse][[/noparse]0] := $FF_00_00_00
        ActualData[noparse][[/noparse]1] := $CC_00_00_BB
        ActualData[noparse][[/noparse]2] := $AA_00_DD_00
     
        Offset := 4                'range is -4 to 4 ; A negative value shifts data down ; A positive value shifts data up 
        NumberOfLongsToMove := 10
        StartLocation := @ActualData
        bytemove (@ShiftedData, StartLocation+Offset,4* NumberOfLongsToMove)
     
        {
          Read data from ShiftedData[noparse][[/noparse]0],ShiftedData[noparse][[/noparse]1],ShiftedData[noparse][[/noparse]3]....etc. 
        }
    
    
    

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

    IC Layout Engineer
    Parallax, Inc.
  • deSilvadeSilva Posts: 2,967
    edited 2007-11-18 17:07
    @Harrison
    You have to understand that the MEMORY (not only COG, but HUB also) consists of 32 bit elements.
    Accessing something from one part and something from the other is simply not possible.

    You can of course write very fancy routines to just do that, i.e. reading here and there and putting it together.
    I think there is not much difference with respect to timing how you do that.... All will be VERY SLOW smile.gif

    When you have a larger misaligned array, use Beau's trick (BYTEMOVE).
  • hippyhippy Posts: 1,981
    edited 2007-11-18 20:06
    If you have a spare cog you can create a parameter block ...
      long hubAddress
      long byteValue
      long wordValue
      long longValue
    



    ... and have the Cog run an assembler program which monitors hubAddress and when not negative fills in the return parameters as required.
    Set hubAddress, wait for it to go negative and read whichever xxxxValue you want. You can wrap that all up in Spin functions if you like ...

    PRI ReadWord( adr )
      hubAddress := adr
      repeat until hubAddress < 0
      return wordValue
    
    


    That would probably make for a nice introductory program for venturing into assembler code.
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2007-11-20 05:41
    This is just a neat FYI on my previous post.· You can also do this to simplify the code even further....

    VAR
     
    long dummyDataTop
    long ActualData[noparse][[/noparse]100]
    long dummyDataBottom
     
    PUB DEMO
     
        ActualData[noparse][[/noparse]0] := $FF_00_00_00
        ActualData[noparse][[/noparse]1] := $CC_00_00_BB
        ActualData[noparse][[/noparse]2] := $AA_00_DD_00
        ActualData[noparse][[/noparse]3] := $11_22_33_44
        
        Offset := 4                'range is -4 to 4 ; A negative value shifts data down ; A positive value shifts data up 
     
        bytemove (@ActualData, @ActualData+Offset,4* 100{<--Data Length})
    
    




    Now, my original thought with the above method was that at least in one direction that the data would be overwritten and corrupted.· I sent an E-mail to Jeff Martin regarding this potential issue, and below is how he replied....
    Jeff's E-mail Reply ...
    Hi Beau,
    ·
    Chip and I had discussed this potential problem back when he was writing the xxxxmove commands, and he wrote it to intelligently start at whichever end of the data block that faces the direction of movement, so that overlapping source and destination locations wouldn’t be a problem.· Of course, this means that, during the operation, the block will sometimes be copied in the order from start to end, and sometimes from end to start, but the end result is the same regardless of overlap.
    ·
    I actually hadn’t tried that myself, but your question solidifies it to me that he actually did make it work the way we discussed.

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

    IC Layout Engineer
    Parallax, Inc.
  • deSilvadeSilva Posts: 2,967
    edited 2007-11-20 08:45
    Be careful with little endian effects smile.gif
  • Harrison.Harrison. Posts: 484
    edited 2007-11-20 09:11
    Thanks for all the help. I ended up using independent byte reads and shifting / adding the bytes together. The main reason why I resorted to this was because ethernet packets use big endian while the Propeller is little endian. Beau's bytemove stuff proved to be quite useful for copying data between partial buffers (I had repeat loops, which were obviously slow and code space hogging).

    Looks like I'll have to analyze the clock cycles taken for each type of operation to find out the best method. But for now, it seems to work well and I should have my new ethernet code ready for release soon.

    Harrison
Sign In or Register to comment.