I need to shift a 5 bit number in, through and out of a byte using bit0 to
bit4 and not affect bit5 - bit7.
The best way I can think of an example is if you had two 8 bit wide
registers next to each other like the following. The 5 bit value in byte 2
is shifted left throughout byte 1 and out.
byte1 byte2
XXX00000 xxx11111 start state
XXX00001 xxx11110
XXX00011 xxx11100
XXX00111 xxx11000
XXX01111 xxx10000
XXX11111 xxx00000
XXX11110 xxx00000
XXX11100 xxx00000
XXX11000 xxx00000
XXX10000 xxx00000
XXX00000 xxx00000 end state
Only byte 1 is important, byte 2 is just for my example.
X = can not be changed.
x = not used
Anyone have any ideas on how to do this? I think a couple of loops and
some bit testing & setting will do it but I just can't seem to crack the
algorithm needed.
> -----Original Message-----
> From: Jean-Michel Howland [SMTP:spam_OUTvegeTakeThisOuTVMAPA.COM]
> Sent: Wednesday, August 16, 2000 4:45 PM
> To: .....PICLISTKILLspam@spam@MITVMA.MIT.EDU
> Subject: [PIC]: Shifting a number through a byte
>
> Hi all,
>
> I need to shift a 5 bit number in, through and out of a byte using bit0 to
> bit4 and not affect bit5 - bit7.
>
> The best way I can think of an example is if you had two 8 bit wide
> registers next to each other like the following. The 5 bit value in byte
> 2
> is shifted left throughout byte 1 and out.
>
> byte1 byte2
>
> XXX00000 xxx11111 start state
> XXX00001 xxx11110
> XXX00011 xxx11100
> XXX00111 xxx11000
> XXX01111 xxx10000
> XXX11111 xxx00000
> XXX11110 xxx00000
> XXX11100 xxx00000
> XXX11000 xxx00000
> XXX10000 xxx00000
> XXX00000 xxx00000 end state
>
> Only byte 1 is important, byte 2 is just for my example.
>
> X = can not be changed.
> x = not used
>
> Anyone have any ideas on how to do this? I think a couple of loops and
> some bit testing & setting will do it but I just can't seem to crack the
> algorithm needed.
>
> Regards
> Jean-Michel.
>
I think I'd use a temporary variable and logically combine the shifted
result with byte1.
e.g.
CLRF temp ; ensure our temp variable is clear to begin
with
RLF byte2,F ; align incomming word to MSB's (assuming this is
ok??)
RLF byte2,F
RLF byte2,F
MOVLW 5
MOVWF count ; initialise loop counter
shift:
RLF byte2,F ; move the MSB of incomming word into CARRY
RLF temp,F ; and then move it into the LSB of temp
MOVF byte1,W ; get current state of byte one
ANDLW 0xE0 ; clear the 5 lsb's
IORWF temp,W ; set the 5 LSB's according to temp
MOVWF byte1 ; move the result back into byte1
; result in byte1 is correct
here
DECFSZ count
GOTO shift
I think this would work OK as long as the XXX bits in byte1 are not changed
(e.g. by an interrupt) during the middle four instructions of the shift
loop.
I don't even know why I attempted this, Scott or Dmitry will probably have
it whittled down to 3 instructions :o)
You are looking to rotate the lower five bits of a byte through the lower five
bits of a register without affecting the higher 3 bits.
The algorithm could be as follows, using two temp registers and assuming the
byte to be worked on is in W, the result goes in W. The original byte is in
TEMP1:
Copy W to temp1
Rotate W Left
Remove (clear) the top three bits or W (AND W with 0b0001.1111)
Copy W to temp2
Move temp1 to W
Remove the bottom 5 bits of W (AND W with 0b1110.0000)
Add temp2 to W
I know there are other ways to do this (shorter, faster, fewer registers, etc).
But this is a good way to do it. The example assembly is below:
MOVWF TEMP1
RLF W
ANDLW 0b0001.1111
MOVWF TEMP2
MOVF TEMP1, W
ANDLW 0b1110.0000
ADDWF TEMP2, W ;You can also use IORWF here.
>
> Hi all,
>
> I need to shift a 5 bit number in, through and out of a byte using bit0 to
> bit4 and not affect bit5 - bit7.
>
> The best way I can think of an example is if you had two 8 bit wide
> registers next to each other like the following. The 5 bit value in byte 2
> is shifted left throughout byte 1 and out.
>
> byte1 byte2
>
> XXX00000 xxx11111 start state
> XXX00001 xxx11110
> XXX00011 xxx11100
> XXX00111 xxx11000
> XXX01111 xxx10000
> XXX11111 xxx00000
> XXX11110 xxx00000
> XXX11100 xxx00000
> XXX11000 xxx00000
> XXX10000 xxx00000
> XXX00000 xxx00000 end state
>
> Only byte 1 is important, byte 2 is just for my example.
>
> X = can not be changed.
> x = not used
>
> Anyone have any ideas on how to do this? I think a couple of loops and
> some bit testing & setting will do it but I just can't seem to crack the
> algorithm needed.
>
> Regards
> Jean-Michel.
>
> --
> http://www.piclist.com hint: The PICList is archived three different
> ways. See http://www.piclist.com/#archives for details.
How about the brute force method: shift the whole byte, then put back the
upper three bits. No temporaries used and W untouched:
set carry appropriately, then
rlf byte1, F ; rotate carry into LSB
bcf byte1, 5 ; bit by bit move back the upper three bits
btfsc byte1, 6
bsf byte1, 5
bcf byte1, 6
btfsc byte1, 7
bsf byte1, 6
bcf byte1, 7
btfsc STATUS, C ; bit seven now in carry
bsf byte1, 7
If you need to keep the byte correct at all times I think you'll need a
temporary:
set carry appropiately
rlf byte1, W ; rotate but put result in W
andlw 0x1F ; clear the upper three bits
movwf temp ; store it
movlw 0xE0
andwf byte1, W ; move upper three bits to W
iorwf temp, W ; OR in the shifted lower 5 bits
movwf byte1 ; ... and put it back.
>Hi all,
>
>I need to shift a 5 bit number in, through and out of a byte using bit0 to
>bit4 and not affect bit5 - bit7.
>
>The best way I can think of an example is if you had two 8 bit wide
>registers next to each other like the following. The 5 bit value in byte 2
>is shifted left throughout byte 1 and out.
>
>byte1 byte2
>
>XXX00000 xxx11111 start state
>XXX00001 xxx11110
>XXX00011 xxx11100
>XXX00111 xxx11000
>XXX01111 xxx10000
>XXX11111 xxx00000
>XXX11110 xxx00000
>XXX11100 xxx00000
>XXX11000 xxx00000
>XXX10000 xxx00000
>XXX00000 xxx00000 end state
>
>Only byte 1 is important, byte 2 is just for my example.
>
>X = can not be changed.
>x = not used
>
>Anyone have any ideas on how to do this? I think a couple of loops and
>some bit testing & setting will do it but I just can't seem to crack the
>algorithm needed.
>
>Regards
>Jean-Michel.
>
>--
>http://www.piclist.com hint: The PICList is archived three different
>ways. See http://www.piclist.com/#archives for details.
This sounds interesting, so I thought I'd take a crack at it. The way I look
at it is to save your data to a temp register and another "working" register,
swap the high/low nibbles and shift out, then restore the temp register. Like
so:
movwf temp
movwf temp2
swapf temp2, 1 ;result would be 11111xxx
Here's a middle-of-the-road solution. No temporary but uses W and corrupts
temp1 for a few instructions:
set carry appropriately
movlw 0x1F
rlf byte1, F ; rotate in place, byte1 now corrupt
andwf byte1, F ; clear upper three bits
rrf byte1, W ; get the original back in W
andlw 0xE0 ; clear the lower 5 bits
iorwf byte1, F ; restore upper 3 bits, byte1 now OK
How about the brute force method: shift the whole byte, then put back the
upper three bits. No temporaries used and W untouched:
set carry appropriately, then
rlf byte1, F ; rotate carry into LSB
bcf byte1, 5 ; bit by bit move back the upper three bits
btfsc byte1, 6
bsf byte1, 5
bcf byte1, 6
btfsc byte1, 7
bsf byte1, 6
bcf byte1, 7
btfsc STATUS, C ; bit seven now in carry
bsf byte1, 7
If you need to keep the byte correct at all times I think you'll need a
temporary:
set carry appropriately
rlf byte1, W ; rotate but put result in W
andlw 0x1F ; clear the upper three bits
movwf temp ; store it
movlw 0xE0
andwf byte1, W ; move upper three bits to W
iorwf temp, W ; OR in the shifted lower 5 bits
movwf byte1 ; ... and put it back.
>Hi all,
>
>I need to shift a 5 bit number in, through and out of a byte using bit0 to
>bit4 and not affect bit5 - bit7.
>
>The best way I can think of an example is if you had two 8 bit wide
>registers next to each other like the following. The 5 bit value in byte 2
>is shifted left throughout byte 1 and out.
>
>byte1 byte2
>
>XXX00000 xxx11111 start state
>XXX00001 xxx11110
>XXX00011 xxx11100
>XXX00111 xxx11000
>XXX01111 xxx10000
>XXX11111 xxx00000
>XXX11110 xxx00000
>XXX11100 xxx00000
>XXX11000 xxx00000
>XXX10000 xxx00000
>XXX00000 xxx00000 end state
>
>Only byte 1 is important, byte 2 is just for my example.
>
>X = can not be changed.
>x = not used
>
>Anyone have any ideas on how to do this? I think a couple of loops and
>some bit testing & setting will do it but I just can't seem to crack the
>algorithm needed.
>
>Regards
>Jean-Michel.
>
>--
>http://www.piclist.com hint: The PICList is archived three different
>ways. See http://www.piclist.com/#archives for details.
Here is my crack at this. First a couple of assumptions that would affect
the solution. I assumed a 14-bit core part. I assumed that you wanted
both byte1 and byte2 to be correct as in your example after each bit shift.
A couple of things to watch for in some of the solutions posted previously.
I noticed an "RLF W" instruction that looks like it should rotate the WREG
left 1 bit
You can do this on the 16-bit core parts, but WREG is not an addressable
register on the 12 and 14-bit core parts.
In another solution byte2 was rotated left three bits to align it at the
MSB. Only thing to watch out for here is what value you are rotating into
byte2 in the carry. This depends on if you really need byte2 to turn out
as in your example.
I didn't show the looping control logic
clrf byte1
loop:
clrc ;clear carry into byte 2
rlf byte2,f ;rotate byte left once
movf byte1,w ;load byte1 into WREG
clrc ;clear carry
btfsc byte2,5 ;set or clear carry to be same as bit 5
setc ;note that clrc and setc translated by MPASM to bcf 3,0 and bsf 3,0
rlf byte1,w ;rotate bit into byte and leave in WREG
andlw B'00011111' ;clear bits 5..7
movwf temp1 ;save for second
movlw B'11100000' ;load mask to clear bits 0..4
andwf byte1,w ;get original high order bits from byte1
iorwf temp1,w ;combine the two
movwf byte1 ;and write back to byte1
>Hi all,
>
>I need to shift a 5 bit number in, through and out of a byte using bit0 to
>bit4 and not affect bit5 - bit7.
>
>The best way I can think of an example is if you had two 8 bit wide
>registers next to each other like the following. The 5 bit value in byte 2
>is shifted left throughout byte 1 and out.
>
>byte1 byte2
>
>XXX00000 xxx11111 start state
>XXX00001 xxx11110
>XXX00011 xxx11100
>XXX00111 xxx11000
>XXX01111 xxx10000
>XXX11111 xxx00000
>XXX11110 xxx00000
>XXX11100 xxx00000
>XXX11000 xxx00000
>XXX10000 xxx00000
>XXX00000 xxx00000 end state
>
>Only byte 1 is important, byte 2 is just for my example.
>
>X = can not be changed.
>x = not used
>
>Anyone have any ideas on how to do this? I think a couple of loops and
>some bit testing & setting will do it but I just can't seem to crack the
>algorithm needed.
>
>Regards
>Jean-Michel.
>
>--
>http://www.piclist.com hint: The PICList is archived three different
>ways. See http://www.piclist.com/#archives for details.
>
>
Here is a no-temporary, never leaves the value inconsistent, way to do it:
assume the current value of the byte is in the_byte, and is represented
by the bit pattern:
x y z a b c d e
where 'x y z' must be kept, and the new bit must be shifted in on the right
pushing 'b c d e' to the left one bit.
'a' of course drops out entirely.
then:
movf the_byte,W ; W = x y z a b c d e
andlw B'00001111' ; W = 0 0 0 0 b c d e
addwf the_byte,W ; W = x y z a b c d e + b c d e
btfsc the_byte,4 ; Was 'A' set?
addlw 0-B'00010000' ; Yes, take it out of the answer
W is now 'x y z a b c d e' + '0 0 0 0 b c d e' - '0 0 0 a 0 0 0 0'
This if of course equal to 'x y z b c d e 0' because we are adding two each
of 'b', 'c', 'd' and 'e', which will shift them up one position, and the two
'a's cancel each other.
Now we just have to insert the new bit into the LSBit of "W" before storing
the result.
Bob Ammerman
RAm Systems
(contract development of high performance, high function, low-level
sofftware)
Well, this doesn't work. I must be suffering from brain-fade. I added line
numbers below. Note that on line 04 I modify the contents of byte1, then on
line 05 I expect to get back the original contents. Good trick!
>Here's a middle-of-the-road solution. No temporary but uses W and corrupts
>temp1 for a few instructions:
>
>01 set carry appropriately
>02 movlw 0x1F
>03 rlf byte1, F ; rotate in place, byte1 now corrupt
>04 andwf byte1, F ; clear upper three bits
>05 rrf byte1, W ; get the original back in W
>06 andlw 0xE0 ; clear the lower 5 bits
>07 iorwf byte1, F ; restore upper 3 bits, byte1 now OK
Amazing clever as usual, but I'm confused. Wouldn't the final addlw
sometimes produce a carry into bit 5? Could you use an XOR rather than an
ADD to reverse the bit without the resulting carry?
>Here is a no-temporary, never leaves the value inconsistent, way to do it:
>
>assume the current value of the byte is in the_byte, and is represented
>by the bit pattern:
>
> x y z a b c d e
>
>where 'x y z' must be kept, and the new bit must be shifted in on the right
>pushing 'b c d e' to the left one bit.
>'a' of course drops out entirely.
>
>then:
>
> movf the_byte,W ; W = x y z a b c d e
> andlw B'00001111' ; W = 0 0 0 0 b c d e
> addwf the_byte,W ; W = x y z a b c d e + b c d e
> btfsc the_byte,4 ; Was 'A' set?
> addlw 0-B'00010000' ; Yes, take it out of the answer
>
>W is now 'x y z a b c d e' + '0 0 0 0 b c d e' - '0 0 0 a 0 0 0 0'
>
>This if of course equal to 'x y z b c d e 0' because we are adding two each
>of 'b', 'c', 'd' and 'e', which will shift them up one position, and the two
>'a's cancel each other.
>
>Now we just have to insert the new bit into the LSBit of "W" before storing
>the result.
>
>
>Bob Ammerman
>RAm Systems
>(contract development of high performance, high function, low-level
>sofftware)
>
>--
>http://www.piclist.com hint: The PICList is archived three different
>ways. See http://www.piclist.com/#archives for details.
> Here is a no-temporary, never leaves the value inconsistent, way to do it:
>
> assume the current value of the byte is in the_byte, and is represented
> by the bit pattern:
>
> x y z a b c d e
>
> where 'x y z' must be kept, and the new bit must be shifted in on the right
> pushing 'b c d e' to the left one bit.
> 'a' of course drops out entirely.
>
> then:
>
> movf the_byte,W ; W = x y z a b c d e
> andlw B'00001111' ; W = 0 0 0 0 b c d e
> addwf the_byte,W ; W = x y z a b c d e + b c d e
> btfsc the_byte,4 ; Was 'A' set?
> addlw 0-B'00010000' ; Yes, take it out of the answer
>
> W is now 'x y z a b c d e' + '0 0 0 0 b c d e' - '0 0 0 a 0 0 0 0'
>
> This if of course equal to 'x y z b c d e 0' because we are adding two each
> of 'b', 'c', 'd' and 'e', which will shift them up one position, and the two
> 'a's cancel each other.
>
> Now we just have to insert the new bit into the LSBit of "W" before storing
> the result.
>
> Bob Ammerman
> RAm Systems
> (contract development of high performance, high function, low-level
> sofftware)
>
> --
> http://www.piclist.com hint: The PICList is archived three different
> ways. See http://www.piclist.com/#archives for details.
As far as I understand you need I can see two ways to do it.
1. You only need to shift single one register.
rlf byte1,W ;get new bit from carry
xorwf byte1,W ;get difference
andlw B'00011111' ;0's will mask unchanged bits
xorwf byte1,F ;update only required bits
2. You need to shift in such way through many registers.
rlf byte1,W ;get new bit from carry
andlw B'00111111' ;mask msb's but last
addlw B'11100000' ;copy last to carry
xorwf byte1,W
andlw B'00011111' ;see explanation of
xorwf byte1,F ;this in example above
;then
;
rlf byte2,W
andlw B'00111111'
addlw B'11100000'
;
;and so on as many bytes as you need ;)
> I need to shift a 5 bit number in, through and out of a byte using bit0 to
> bit4 and not affect bit5 - bit7.
>
> The best way I can think of an example is if you had two 8 bit wide
> registers next to each other like the following. The 5 bit value in byte 2
> is shifted left throughout byte 1 and out.
>
> byte1 byte2
>
> XXX00000 xxx11111 start state
> XXX00001 xxx11110
> XXX00011 xxx11100
> XXX00111 xxx11000
> XXX01111 xxx10000
> XXX11111 xxx00000
> XXX11110 xxx00000
> XXX11100 xxx00000
> XXX11000 xxx00000
> XXX10000 xxx00000
> XXX00000 xxx00000 end state
>
> Only byte 1 is important, byte 2 is just for my example.
>
> X = can not be changed, x = not used
Actually the final ADDLW is actually _subtracting_ the value of A, only if
it was added in before. The add and subtract cancel each other, and thus
their affect on bits 5 through 7.
It isn't immediately clear from your question whether the upper three bits need
to be held constant all of the time OR only after every 5 bits are shifted
in. If it's the latter, then you could do this:
> Hello Jean-Michel.
>
> As far as I understand you need I can see two ways to do it.
>
> 1. You only need to shift single one register.
>
> rlf byte1,W ;get new bit from carry
>
> xorwf byte1,W ;get difference
> andlw B'00011111' ;0's will mask unchanged bits
> xorwf byte1,F ;update only required bits
>
> 2. You need to shift in such way through many registers.
>
> rlf byte1,W ;get new bit from carry
> andlw B'00111111' ;mask msb's but last
> addlw B'11100000' ;copy last to carry
>
> xorwf byte1,W
> andlw B'00011111' ;see explanation of
> xorwf byte1,F ;this in example above
> ;then
> ;
> rlf byte2,W
> andlw B'00111111'
> addlw B'11100000'
> ;
> ;and so on as many bytes as you need ;)
>
>
> WBR Dmitry.
>
>
>
> > I need to shift a 5 bit number in, through and out of a byte using bit0 to
> > bit4 and not affect bit5 - bit7.
> >
> > The best way I can think of an example is if you had two 8 bit wide
> > registers next to each other like the following. The 5 bit value in byte 2
> > is shifted left throughout byte 1 and out.
> >
> > byte1 byte2
> >
> > XXX00000 xxx11111 start state
> > XXX00001 xxx11110
> > XXX00011 xxx11100
> > XXX00111 xxx11000
> > XXX01111 xxx10000
> > XXX11111 xxx00000
> > XXX11110 xxx00000
> > XXX11100 xxx00000
> > XXX11000 xxx00000
> > XXX10000 xxx00000
> > XXX00000 xxx00000 end state
> >
> > Only byte 1 is important, byte 2 is just for my example.
> >
> > X = can not be changed, x = not used
>
> --
> http://www.piclist.com hint: The PICList is archived three different
> ways. See http://www.piclist.com/#archives for details.
>
At 03:56 PM 8/16/2000 , you wrote:
>Actually the final ADDLW is actually _subtracting_ the value of A, only if
>it was added in before. The add and subtract cancel each other, and thus
>their affect on bits 5 through 7.
>
>Carry is thus not an issue.
Hmmm....
start with the_byte = 0b0001 0000
> > > movf the_byte,W ; W = x y z a b c d e
W = 0b0001 0000
> > > andlw B'00001111' ; W = 0 0 0 0 b c d e
W = 0b0000 0000
> > > addwf the_byte,W ; W = x y z a b c d e + b c d e
W = 0b0001 0000
> > > btfsc the_byte,4 ; Was 'A' set?
yes
> > > addlw B'00010000' ; Yes, take it out of the answer
W = 0b0010 0000
To subtract wouldn't you have to add the 2's compliment?
addlw 0b1111 0000
for the result of:
W = 0b0000 0000
Am I missing something here? I normally don't try to keep up with the
"masters"!