Maker Pro
Maker Pro

Pic Program to update single bits from table

B

Bill B

Trying to figure out an easy way to update a single bit within a group
of 24 bits (3 bytes) using a lookup table that returns 8 bits. The
first 5 bits from the table will indicate the bit to be updated (1of
24) and the 6th bit will indicate a set or reset for that particular
bit.

Thought about using a counter and 3 other registers to shift the bit
through the 3 registers so the single bit appears in the correct
place, and then do an inclusive or to mask the bit into the existing
data. but it seems complicated.

Have any other ideas?

-Bill
 
J

Jon Slaughter

Bill B said:
Trying to figure out an easy way to update a single bit within a group
of 24 bits (3 bytes) using a lookup table that returns 8 bits. The
first 5 bits from the table will indicate the bit to be updated (1of
24) and the 6th bit will indicate a set or reset for that particular
bit.

It's called math:

call your first 5 bits the index, the 6th bit the value, the 8-bits a and
the 24-bits stream:

then it's

(stream & ~(1 << (a && 63))) | ((((a >> 6) & 1) << a && 63)

or broken down

value = (a >> 6) & 1;

This shifts the 6th bit to the first 1 and then ands it with 1 so that the
higher bits go to 0.

index = a && 011111b;

this gets teh index, which is just the first 5 bits. i.e., I set the top 3
bits to 0 and so I'm just left with the lower 5 having any effect.


but index represents the shifting amount. i.e., if index = 8 then I shift 8
bits...

i.e.,

value << index


This basically takes the value and puts it at the indexth bit location.


Now we just need to update the stream(the 24-bits) with our new value

(1 << (a && 63))

What this does is create create a mask where every bit is 0 except for the
bit at the index we want.

We invert it to create an and mask... so went we and it with stream we
"punch" out that bit location so we can or in the true value.

stream & (1 << (a && 63))

makes the indexth bit location 0, oring this with our new value put's in it.

(this assumes you have no routine to set bit's directly)


Thought about using a counter and 3 other registers to shift the bit
through the 3 registers so the single bit appears in the correct
place, and then do an inclusive or to mask the bit into the existing
data. but it seems complicated.

Have any other ideas?

Not sure what you are talking about here. Bit manipulation can almost always
be done using boolean logic. You just have to use the standard tricks and
know how the operators work.

heres a concrete example for what is above: (I'm using low bit first and
only a trimmed down version)

suppose stream = 0110101 (7bits, not 24)
value = 110x (lower 3 bits = index, 4th bit = value)

then

index = a & 111b = 110 = 3
value = a >> 3 = x

1 << index = 0001
~(1 << index) = 1110111

stream & 1110111 = 0110101 (Didn't change)


value << index = 000x

so

(stream & 1110111) | (value << index)
=
0110101 | 000x000 = 011x101

So I have moved the x to the proper location in the bit stream.
 
J

Jasen Betts

Trying to figure out an easy way to update a single bit within a group
of 24 bits (3 bytes) using a lookup table that returns 8 bits. The
first 5 bits from the table will indicate the bit to be updated (1of
24) and the 6th bit will indicate a set or reset for that particular
bit.

Thought about using a counter and 3 other registers to shift the bit
through the 3 registers so the single bit appears in the correct
place, and then do an inclusive or to mask the bit into the existing
data. but it seems complicated.

you have the number of bits you need to shift by in three of the bits
and an address offset in the other two bits and the action to perform
in the last bit.

Bye.
Jasen
 
P

petrus bitbyter

Bill B said:
Trying to figure out an easy way to update a single bit within a group
of 24 bits (3 bytes) using a lookup table that returns 8 bits. The
first 5 bits from the table will indicate the bit to be updated (1of
24) and the 6th bit will indicate a set or reset for that particular
bit.

Thought about using a counter and 3 other registers to shift the bit
through the 3 registers so the single bit appears in the correct
place, and then do an inclusive or to mask the bit into the existing
data. but it seems complicated.

Have any other ideas?

-Bill

Complicated? Seems straight forward to me, though not the most efficient in
speed as you need an average of 36 shift and jump operations. To improve
speed you can consider the following:
- pick up the update byte from the table and store ir somewhere
- use bit 3 and 4 (so the fourth and fifth bit) to point the indirect
register to the byte that needs to be updated
- use bit 0-3 to prepare the mask
- check bit 5 to see if you need to set or to reset
- if set is required, use an OR operation, if reset is required complement
mask and use an AND.

petrus bitbyter
 
J

Jon Slaughter

Anthony Fremont said:
tsk tsk, that wasn't very nice

It's true though... nice or not. Point I was trying to make is that you
don't need anything else.
I think the OP is talking about doing it with PIC assembly language.

um, yes, you have to translate it.. All cpu's have boolean logic to do such
things. (i.e. ALU)
 
B

Bill B

It's called math:

call your first 5 bits the index, the 6th bit the value, the 8-bits a and
the 24-bits stream:

then it's

(stream & ~(1 << (a && 63))) | ((((a >> 6) & 1) << a && 63)

or broken down

value = (a >> 6) & 1;

This shifts the 6th bit to the first 1 and then ands it with 1 so that the
higher bits go to 0.

index = a && 011111b;

this gets teh index, which is just the first 5 bits. i.e., I set the top 3
bits to 0 and so I'm just left with the lower 5 having any effect.

but index represents the shifting amount. i.e., if index = 8 then I shift 8
bits...

i.e.,

value << index

This basically takes the value and puts it at the indexth bit location.

Now we just need to update the stream(the 24-bits) with our new value

(1 << (a && 63))

What this does is create create a mask where every bit is 0 except for the
bit at the index we want.

We invert it to create an and mask... so went we and it with stream we
"punch" out that bit location so we can or in the true value.

stream & (1 << (a && 63))

makes the indexth bit location 0, oring this with our new value put's in it.

(this assumes you have no routine to set bit's directly)



Not sure what you are talking about here. Bit manipulation can almost always
be done using boolean logic. You just have to use the standard tricks and
know how the operators work.

heres a concrete example for what is above: (I'm using low bit first and
only a trimmed down version)

suppose stream = 0110101 (7bits, not 24)
value = 110x (lower 3 bits = index, 4th bit = value)

then

index = a & 111b = 110 = 3
value = a >> 3 = x

1 << index = 0001
~(1 << index) = 1110111

stream & 1110111 = 0110101 (Didn't change)

value << index = 000x

so

(stream & 1110111) | (value << index)
=
0110101 | 000x000 = 011x101

So I have moved the x to the proper location in the bit stream.

Yes, it's easy with high level languages, but I need a little more
speed and memory conservation, so assembly language is the preferred
method.

Thanks,

-Bill
 
B

Bill B

Assuming that you are using the typical 16Fxx type PIC, you really don't
have any easy way to do it. It might take a little less code if you divide
the 5 bit offset field into two fields. Two bits for the byte number (0,1,
or 2) and three bits for the bit position within the byte. Use the 2-bit
field to set up the FSR to point to the appropriate byte. Then you can just
use the three-bit field to index (by adding to the PCL) into a table that
looks something like this:
retlw 0b00000001
retlw 0b00000010
retlw 0b00000100
retlw 0b00001000
retlw 0b00010000
retlw 0b00100000
retlw 0b01000000
retlw 0b10000000
If necessary, negate the retrieved byte to AND off a bit, or use it as is to
OR one on in the byte pointed to by the FSR.

Yes, that's a good idea, I was using IORWF against say "00010000" to
set bit 4, but I hadn't thought of using the negative "11101111" with
the ANDWF to reset the bit. I'll give that a try.

Thanks,

-Bill
 
P

petrus bitbyter

James Waldby said:
"Bill B" ... schreef ...
Trying to figure out an easy way to update a single bit within a group
of 24 bits (3 bytes) using a lookup table that returns 8 bits. The
first 5 bits from the table will indicate the bit to be updated (1of
24) and the 6th bit will indicate a set or reset for that particular
bit.
[snip]
Complicated? Seems straight forward to me, though not the most efficient
in speed as you need an average of 36 shift and jump operations. To
improve speed you can consider the following: - pick up the update byte
from the table and store it somewhere - use bit 3 and 4 (so the fourth
and fifth bit) to point the indirect register to the byte that needs to
be updated - use bit 0-3 to prepare the mask
- check bit 5 to see if you need to set or to reset - if set is
required, use an OR operation, if reset is required complement mask and
use an AND.

The following might save an instruction or two --
0. Get byte in accumulator
1. OR accumulator with 1-bit mask M.
2. Go to 4 if bit is being set.
3. XOR accumulator with M
4. ...

That'll only set the mask. You also have to update a byte.

Suppose:

'updbyte' to be a copy picked from the update table
FSR pointing to the byte to be updated
'mask' to be the prepared mask, containing one 1

movf mask,w ; (Only if mask is not in w already)
btfsz updbyte, 5 ; check for set or reset
goto setupd ; set required go for it
xorlw 0xff ; reset required so complement mask
andwf IND,r ; reset bit
goto continue ; reset done, so continue
setupd iorwf IND,r ; set bit
continue nop

As there are only few instructions, I see no way to save one or two.

petrus bitbyter
 
F

Frank Buss

James said:
movf mask,w ; (Only if mask is not in w already)
iorwf IND,r ; set bit
btfss updbyte, 5 ; check for set or reset
xorwf IND,r ; reset bit
continue nop

This is dangerous, if an interrupt is generated after the iorwf.
 
M

Martin Brown

Depends if you have room to trade space for speed.
Yes, that's a good idea, I was using IORWF against say "00010000" to
set bit 4, but I hadn't thought of using the negative "11101111" with
the ANDWF to reset the bit. I'll give that a try.

Another way is to take the bitno in W and shift it left once then have
a computed jump table with 24 following 2 byte entries of the form:

BSF Reg0,0
RETURN
BSF Reg0,1
RETURN
...
BSF Reg0,7
RETURN
BSF Reg1,0 etc.
etc.

RETURN could be GOTO BSDONE

Obviously with long jump tables you have to take care not to have it
spanning a segment boundary or unexpected results will ensue. This is
about the simplest way, indivisible operation for bit change and
possibly the fastest.

Regards,
Martin Brown
 
P

petrus bitbyter

James Waldby said:
"James Waldby" ... schreef ...
schreef ...
Trying to figure out an easy way to update a single bit within a
group of 24 bits (3 bytes) using a lookup table that returns 8 bits.
The first 5 bits from the table will indicate the bit to be updated
(1of 24) and the 6th bit will indicate a set or reset for that
particular bit.
[snip]
Complicated? Seems straight forward to me, though not the most
efficient in speed as you need an average of 36 shift and jump
operations. To improve speed you can consider the following: - pick up
the update byte from the table and store it somewhere - use bit 3 and
4 (so the fourth and fifth bit) to point the indirect register to the
byte that needs to be updated - use bit 0-3 to prepare the mask -
check bit 5 to see if you need to set or to reset - if set is
required, use an OR operation, if reset is required complement mask
and use an AND.

The following might save an instruction or two --
0. Get byte in accumulator
1. OR accumulator with 1-bit mask M.
2. Go to 4 if bit is being set.
3. XOR accumulator with M
4. ...

That'll only set the mask. You also have to update a byte.

Suppose:

'updbyte' to be a copy picked from the update table FSR pointing to the
byte to be updated 'mask' to be the prepared mask, containing one 1

movf mask,w ; (Only if mask is not in w already)
btfsz updbyte, 5 ; check for set or reset
goto setupd ; set required go for it
xorlw 0xff ; reset required so complement mask
andwf IND,r ; reset bit
goto continue ; reset done, so continue
setupd iorwf IND,r ; set bit
continue nop

As there are only few instructions, I see no way to save one or two.

movf mask,w ; (Only if mask is not in w already)
iorwf IND,r ; set bit
btfss updbyte, 5 ; check for set or reset
xorwf IND,r ; reset bit
continue nop

You really save two instructions but I don't like the price. You set a bit
for some microseconds. Depending on the application it may not do any harm.
But suppose the bit switches a motor for instance when the byte is copied to
an output port by an interrupt routine? If things can go wrong they will
eventually go wrong and at that time you will have to pay an high interest
for the bytes saved now. I've seen this kind of things go wrong you know and
I learned to avoid chanches like that whenever I can. Nevertheless I once
more agree: You saved two instructions.

petrus bitbyter
 
B

Bill B

"James Waldby" ... schreef ...
schreef ...
Trying to figure out an easy way to update a single bit within a
group of 24 bits (3 bytes) using a lookup table that returns 8 bits.
The first 5 bits from the table will indicate the bit to be updated
(1of 24) and the 6th bit will indicate a set or reset for that
particular bit.
[snip]
Complicated? Seems straight forward to me, though not the most
efficient in speed as you need an average of 36 shift and jump
operations. To improve speed you can consider the following: - pick up
the update byte from the table and store it somewhere - use bit 3 and
4 (so the fourth and fifth bit) to point the indirect register to the
byte that needs to be updated - use bit 0-3 to prepare the mask -
check bit 5 to see if you need to set or to reset - if set is
required, use an OR operation, if reset is required complement mask
and use an AND.
The following might save an instruction or two --
0. Get byte in accumulator
1. OR accumulator with 1-bit mask M.
2. Go to 4 if bit is being set.
3. XOR accumulator with M
4. ...
That'll only set the mask. You also have to update a byte.

'updbyte' to be a copy picked from the update table FSR pointing to the
byte to be updated 'mask' to be the prepared mask, containing one 1
movf mask,w ; (Only if mask is not in w already)
btfsz updbyte, 5 ; check for set or reset
goto setupd ; set required go for it
xorlw 0xff ; reset required so complement mask
andwf IND,r ; reset bit
goto continue ; reset done, so continue
setupd iorwf IND,r ; set bit
continue nop
As there are only few instructions, I see no way to save one or two.

movf mask,w ; (Only if mask is not in w already)
iorwf IND,r ; set bit
btfss updbyte, 5 ; check for set or reset
xorwf IND,r ; reset bit
continue nop

Yes, that worked well. Thanks for the info.

-Bill
 
B

Bill B

Assuming that you are using the typical 16Fxx type PIC, you really don't
have any easy way to do it. It might take a little less code if you divide
the 5 bit offset field into two fields. Two bits for the byte number (0,1,
or 2) and three bits for the bit position within the byte. Use the 2-bit
field to set up the FSR to point to the appropriate byte. Then you can just
use the three-bit field to index (by adding to the PCL) into a table that
looks something like this:
retlw 0b00000001
retlw 0b00000010
retlw 0b00000100
retlw 0b00001000
retlw 0b00010000
retlw 0b00100000
retlw 0b01000000
retlw 0b10000000
If necessary, negate the retrieved byte to AND off a bit, or use it as is to
OR one on in the byte pointed to by the FSR.

Yes, I have the basic idea working as suggested, but one more question
if you have any ideas.

I have several data tables for various sequence generation, and I was
wondering if there is an easy way in assembly to call a table using a
variable indentifier. In other words, instead of calling table1,
table2, table3, etc. is there a methode of calling table(x) where x
represents the data table to be used?

I notice I can use a hard number such as <call d'175'> where 175 is
the program line number, and the program will branch to line 175 and
return the desired data. But I can't seem to figure out how to call
some variable location.

Any ideas?

-Bill
 
J

Jasen Betts

I notice I can use a hard number such as <call d'175'> where 175 is
the program line number, and the program will branch to line 175 and
return the desired data. But I can't seem to figure out how to call
some variable location.

push it on the stack and do a return?

can't use line numbers, but an array full of locations should work.

Bye.
Jasen
 
P

petrus bitbyter

Jasen Betts said:
push it on the stack and do a return?

can't use line numbers, but an array full of locations should work.

Bye.
Jasen


The small PICs don't have PUSH and POP instructions.

I see a possibility when you make one large table consisting all the small
ones and an extra table consisting the table addresses. Calling this lookup
routine requires two variables of course, one containing the number of the
table to be consulted and one containing the entry number in that table.
Suppose the entry number stored in the variable 'index' and the table number
stored in w, your code can go like:

call getit ; on return w should
; contain the required value
 
Top