Shop OBEX P1 Docs P2 Docs Learn Events
Replace bits from one long with bits of another — Parallax Forums

Replace bits from one long with bits of another

Bobb FwedBobb Fwed Posts: 1,119
edited 2011-08-22 08:52 in Propeller 1
I need to replace an arbitrary number of bits in one long with the same number of bits from another long at a (possibly) different arbitrary position...for example:

v1 := %1001_1010_1011
v2 := %1111_0000_0101
replace 5 bits of v2 starting at bit 3 with bits of v1 starting at bit 1
result is: v2 == %1111_1010_1101

While the example is only a byte and a half, I need it to work with all 32 bits.

Here is a first stab at this, it works, but I'm looking for a faster way to do it.
v1 := %1001_1010_1011
  v2 := %1111_0000_0101

  bits := 5                                             ' number of bits to replace
  start1 := 1                                           ' get bits from variable 1 starting at bit 1
  start2 := 3                                           ' put bits from variable 1 into variable 2 starting at bit 3

  v1 >>= start1                                         ' get to starting bit
  v1 &= (-1 >> (32 - bits))                             ' remove all other bits
  v1 <<= start2                                         ' shift to correct position

  v2 &= !((-1 >> (32 - bits)) << start2)                ' remove bits that are being replaced
  v2 |= v1                                              ' put bits from first variable into this one
' result v2 == %1111_[I][B]1010_1[/B][/I]101

Comments

  • MagIO2MagIO2 Posts: 2,243
    edited 2011-08-18 12:08
    mask := |<start2 - |<start1
    result:= v1 & mask | v2 & !mask

    not tested, but in my theory it worked ;o) (of course start1,start2 and v1,v2 have the same values as in your code)


    PS: Oh ... now I understand the full question .. ;o) ... cut out anywhere and put in somewhere else ... so forget about the solution given here
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-18 12:08
    This will work:
      v1 := %1001_1010_1011
      v2 := %1111_0000_0101
    
      bits := 5                                             ' number of bits to replace
      start1 := 3                                           ' get bits from variable 1 starting at bit 1
      start2 := 1                                           ' put bits from variable 1 into variable 2 starting at bit 3
    
      v1 := (v1 & (|< bits - 1) << start1) <- (start2 - start1)
      v2 := v2 & !((|< bits - 1) << start2) | v1
    

    Better yet, since it doesn't alter v1:
      v2 := v2 & !((|< bits - 1) << start2) | ((v1 & (|< bits - 1) << start1) <- (start2 - start1))
    


    -Phil
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-08-18 12:27
    mask := |<(start1+bits) - |<start1
    result := (v1 & mask)<<start2 | v2 & !(mask<<start2)

    How's that?
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-08-18 12:51
    MagIO2 wrote: »
    mask := |<(start1+bits) - |<start1
    result := (v1 & mask)<<start2 | v2 & !(mask<<start2)

    How's that?
    I had to fix it to this:
    mask := |<(start1+bits) - |<start1
      v2 := (v1 & mask)<<(start2 - start1) | v2 & !(mask<<(start2 - start1))
    

    But that makes it slower than Phil's second solution, which is that fastest.
    Thanks guys!
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-08-18 13:32
    I found a faster way, and it doesn't modify v1:
    There was a bug in the first version I just posted, here is the corrected one:
    v2 := (v2 & !((|< bits - 1) << start2)) | (((|< bits - 1) & (v1 >> start1)) << start2)
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-18 13:36
    I wonder if it would be faster yet to define the mask once, instead of computing it twice:
    mask := |< bits - 1
    v2 := (v2 & !(mask << start2)) | ((mask & (v1 >> start1)) << start2)
    

    -Phil
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-08-18 13:53
    I wonder if it would be faster yet to define the mask once, instead of computing it twice:
    mask := |< bits - 1
    v2 := (v2 & !(mask << start2)) | ((mask & (v1 >> start1)) << start2)
    

    -Phil
    So it is. 176 cycles faster.

    But even faster yet is to assign it in-line (another 96 cycles faster):
    v2 := (v2 & !((mask := |< bits - 1) << start2)) | ((mask & (v1 >> start1)) << start2)
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-18 14:09
    Excellent! Spin is starting to look like Perl! Pretty soon your whole program will be on one line. :)

    -Phil
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-08-18 14:14
    Excellent! Spin is starting to look like Perl! Pretty soon your whole program will be on one line. :)

    -Phil
    lol
  • kuronekokuroneko Posts: 3,623
    edited 2011-08-19 17:50
    Bobb Fwed wrote: »
    But even faster yet is to assign it in-line (another 96 cycles faster):
    v2 := (v2 & !((mask := |< bits - 1) << start2)) | ((mask & (v1 >> start1)) << start2)
    
    The above line clocks in with $1000 cycles (t := -cnt/.../t += cnt). These three only need $0CF0:
    outb := v2
      outb[start2+bits-1..start2] := v1 >> start1
      v2 := outb
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-19 22:02
    SFR abuse wins again! :)

    -Phil
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2011-08-22 08:52
    kuroneko wrote: »
    The above line clocks in with $1000 cycles (t := -cnt/.../t += cnt). These three only need $0CF0:
    outb := v2
      outb[start2+bits-1..start2] := v1 >> start1
      v2 := outb
    
    Thanks!
    Optimized a little by modifying bits:
    outb := v2
      outb[(start2 + --bits)..start2] := v1 >> start1
      v2 := outb
    
Sign In or Register to comment.