Shop OBEX P1 Docs P2 Docs Learn Events
How to address 2 bits in same byte — Parallax Forums

How to address 2 bits in same byte

PUB GetByte2Bits(plByteAddr, pbB1Pos, pbB2Pos)
     '
    >| pbB1Pos
    >| pbB2Pos
    _Mask := (pbB1Pos | pbB2Pos)
    '
    Return ((Byte[plByteAddr] & _Mask) == _Mask)
    '
'END PUB

If I ran the above method,
Would I receive return values of 0, 1, 2 or 3 back?
Is the logic correct/wrong?

If wrong, where did I go wrong?
If correct, is there a more better/standardised way of doing this?






Comments

  • I think there is a way to access bits in spin2, do not sure about remembering the syntax correct but it is something like

    Byte[plByteAddr].[bitnumber]

    Enjoy!

    Mike
  • JonnyMacJonnyMac Posts: 8,927
    edited 2020-12-08 03:24
    Since you're returning a 2-bit value, do you really need to pass the address of the modified variable? You could write your code like this
    pub get_2bits(value, b1pos, b0pos)
    
      result := ((value >> (b1pos-1)) & 1) | ((value >> b0pos) & 1)
    

    Then you could use it like this:
      myVar := get_2bits(myVar, b1, b0)
    

    Or am I missing something and you just want to isolate two bits in the same byte without moving their position. If so...
    pub isolate2(value, b1pos, b0pos)
    
      result := value & ((1 << b1pos) | (1 << b0pos))
    
  • I might be worrying about this unjustifiably but I always avoid doing bit operations on any variable other than a long.

    I've run into trouble tying to do bit operations on bytes using the Propeller 1 so I also perform the bit operations on a long and then save the value back to the byte.

    Am I imagining things or is this concern justified?
  • JonnyMacJonnyMac Posts: 8,927
    edited 2020-12-08 04:11
    No need to worry -- in the end, every variable simply resolves to a hub address. If you wanted to isolate the lower two bits of the second byte of a word, you could do this:
      myWord.byte[1] &= %0000_0011
    
  • msrobots wrote: »
    I think there is a way to access bits in spin2, do not sure about remembering the syntax correct but it is something like

    Byte[plByteAddr].[bitnumber]

    Enjoy!

    Mike


    Hiya msrobots,

    Thank you, I look forward to using Spin2 with the new P2 microcontroller,
    Currently I'm delving into P1.

  • JonnyMac wrote: »
    Since you're returning a 2-bit value, do you really need to pass the address of the modified variable? You could write your code like this
    pub get_2bits(value, b1pos, b0pos)
    
      result := ((value >> (b1pos-1)) & 1) | ((value >> b0pos) & 1)
    

    Then you could use it like this:
      myVar := get_2bits(myVar, b1, b0)
    

    Or am I missing something and you just want to isolate two bits in the same byte without moving their position. If so...
    pub isolate2(value, b1pos, b0pos)
    
      result := value & ((1 << b1pos) | (1 << b0pos))
    


    Thank You JonnyMac,

    I think your way is better since its only one statement (cycle?)
    and mine is more unfortunately...

    I'm kind of having a foray into designing a framework for the P1
    Similar to this... an013-gui-graphics-series-menus-and-messaging-with-the-propeller-window-manager-framework

    And so I have some settings which I need to access and modify at run time.
    Kind of like this...
       Byte _bCoreFlags1                '* Primary window flags                            (CoreFlags1 structure)
       '  Layer          bit0           'Window layer (up 4 layers supported)              (00=layer1/01=layer2)
       '  Layer          bit1           '(use with above)                                  (10=layer3/11=layer4)
       '  BorderStyle    bit2           'Window borderstyle (upto 4 styles supported)      (00=none/01=single)
       '  BorderStyle    bit3           '                                                  (10=double/11=user defined)
       '  Reserved       bit4
       '  Reserved       bit5
       '  Reserved       bit6
       '  Reserved       bit7
    
    

    And I wanted to be able to read-in the settings, and then change & save them back to the settings.
    So hence I wrote the function above, which, since I lack enough knowledge was unsure if the function would return what I expected.
    I expected to be returned the value 0, 1, 2, 3 and since no one has pointed out any mistakes, I will assume the function will work, but I will change it to how you advised as that seems much better because its less cycles.

    Now taking it for granted that the function at the top of this thread returns 0, 1, 2, 3 how would I then write back new values to the byte?
    Currently I'm using the function below, which although not optimal, would still work...
    I'm sure it could be optimised with better code than mine below...
    PUB SetByte2Bits(plByteAddr, pbB1Pos, pbB2Pos, pbNewValue)
       '
       If (pbNewValue == 3)
          SetByteBit(plByteAddr, pbB1Pos)
          SetByteBit(plByteAddr, pbB2Pos)
       ElseIf (pbNewValue == 2) 
          ClrByteBit(plByteAddr, pbB1Pos)
          SetByteBit(plByteAddr, pbB2Pos)
       ElseIf (pbNewValue == 1) 
          SetByteBit(plByteAddr, pbB1Pos)
          ClrByteBit(plByteAddr, pbB2Pos)
       Else
          ClrByteBit(plByteAddr, pbB1Pos)
          ClrByteBit(plByteAddr, pbB2Pos)
       'End If 
       '
    'End PUB
    

    Also to answer your question, I think I don't need to pass the address of the byte, its just there because originally I had that code in a separate object, hence I passed the address of the byte so it could be modified directly, If I pass the value of the byte (byval as opposed to byref) then I wouldn't be able to change the value in that specific byte directly I guess..... So having said that then maybe yes I do need to pass the address?

    Does that sound right? you will have to excuse my lack of understanding/knowledge.



  • For your specific application:
    PUB getLayer
      return _bCoreFlags1 & %11		' return 2 lowest bits
    
    PUB setLayer(layer)
      _bCoreFlags1 &= !%11			' clear 2 lowest bits
      _bCoreFlags1 |= (layer & %11)		' write new bits
    
    PUB getBorder
      return _bCoreFlags1 >> 2 & %11
    	
    PUB setBorder(border)
      _bCoreFlags1 &= !%1100
      _bCoreFlags1 |= (layer & %11) << 2
    
    Alternately, you can take advantage of the Prop's unused B registers - while the Prop1 only has 32 I/O pins, it still has dirB and outB registers that you can use.
      dirb := _bCoreFlags1
      layer := dirb[1..0] 		' read layer
      border := dirb[3..2]		' read border
      
      dirb[1..0] := new_layer	' set layer
      dirb[3..2] := new_border	' set border
      _bCoreFlags1 := dirb
    
  • How constrained on memory is your application? All of this would be much simpler if you stored each value in a byte rather than in 2 bits, and generally it's best to start with the simple solution and only move to the more complicated one if you have to. At the moment you only have 2 values (layer and border) so using bytes will only cost you one additional byte, which you'll almost certainly get back in smaller code size.
  • ChrisGadd wrote: »
    For your specific application:
    PUB getLayer
      return _bCoreFlags1 & %11		' return 2 lowest bits
    
    PUB setLayer(layer)
      _bCoreFlags1 &= !%11			' clear 2 lowest bits
      _bCoreFlags1 |= (layer & %11)		' write new bits
    
    PUB getBorder
      return _bCoreFlags1 >> 2 & %11
    	
    PUB setBorder(border)
      _bCoreFlags1 &= !%1100
      _bCoreFlags1 |= (layer & %11) << 2
    
    Alternately, you can take advantage of the Prop's unused B registers - while the Prop1 only has 32 I/O pins, it still has dirB and outB registers that you can use.
      dirb := _bCoreFlags1
      layer := dirb[1..0] 		' read layer
      border := dirb[3..2]		' read border
      
      dirb[1..0] := new_layer	' set layer
      dirb[3..2] := new_border	' set border
      _bCoreFlags1 := dirb
    


    Thank you Chris,
    I've saved your example in a notepad file, my intention is to complete the various modules then replace the calls to the SetByte2Bits() function with inline statements like the ones in your example and hopefully on recompile it will reduce the filesize of the final program.

    I tried to avoid using the PortB registers since I'm sure I read in the forums somewhere that PortB won't be supported on P2

  • ersmith wrote: »
    How constrained on memory is your application? All of this would be much simpler if you stored each value in a byte rather than in 2 bits, and generally it's best to start with the simple solution and only move to the more complicated one if you have to. At the moment you only have 2 values (layer and border) so using bytes will only cost you one additional byte, which you'll almost certainly get back in smaller code size.

    Hi ersmith,
    I would hazard a guess my program (when its finished) will be very constrained for space.

    I had started with individual bytes, words, longs for everything and sized the field according to value length.
    And in order to save space in the compiled code and also final space when I save objects to ram I've used bits where there is a simple Y/N, T/F or 1/0 as a value.

    There are a lot more modules, the one in the code sample above is just a simplified version from one module.

  • JaanDoh wrote: »
    And in order to save space in the compiled code and also final space when I save objects to ram I've used bits where there is a simple Y/N, T/F or 1/0 as a value.
    Here's the thing, though -- accessing bit fields is going to create a *lot* more code than accessing a byte. So in fact you may not be saving any space at all. The small savings you get in the size of data may well be more than offset by larger code.

    Keep it simple. Start out with the most straightforward solution first, and don't worry about optimizing (for either time or space) until you find out that you need to optimize. Donald Knuth once wrote that "premature optimization is the root of all evil", and he is a very wise man.
Sign In or Register to comment.