PDA

View Full Version : Move seperate bytes into a word



tazntex
- 11th November 2008, 19:09
How can I combine these bytes into a word size variable? I am using only four bits of the bytes "0-3" and would like to place them into a word in such a way that "Z" holds A= 0-3, B= 4-7, C=8-11,and D=12-15.
Example:

A=%00000001
B=%00000010
C=%00000011
D=%00000100

Z=0100001100100001

I was thinking of using Aliases in the manual but not sure if that was a way to do it.

I really didn't want to do this:
z.0=a.0
z.1=a.1
etc.
Thanks

Ioannis
- 11th November 2008, 20:39
Something like this?

z=a+b<<4+c<<8+d<<12

Ioannis

tazntex
- 11th November 2008, 21:04
Thank you very much, never thought of that. I will try it out.

mister_e
- 11th November 2008, 21:23
"Z" holds
A= 0-3,
B= 4-7,
C=8-11,and
D=12-15.

First thing is to isolate each 4LSB of each variable. Easy way, using boolean AND (&)


A = A & $0F
B = B & $0F
C = C & $0F
D = D & $0F

Now, you need to shift some bits of your Bytes variables. This is done using left shift (<<). Check your manual about that. Knowing that, we could modify the above like


A = A & $0F
B = B << 4
C = C & $0F
D = D << 4

Now you need to combine A & B, and C & D, then the whole thing together. Boolean OR do the trick


A = (A & $0F) | (B <<4) ' a hold A & B
C = (C & $0F) | (D <<4) ' C hold C & D


Then you need to send A and C where they're suppose to go in Z


Z.LowByte = A
Z.HighByte = C

A is now LSB of Z(0-7), C is now MSB of Z(8-15).

This could be shorten like


Z.LowByte = (A & $0F) | (B <<4)
Z.HighByte = (C & $0F) | (D <<4)


If you're REALLY SURE you NEVER EVER mess with bits <7:4> of your variables, then yes, this could reduce to


Z.HighByte = (D<<4) | C
Z.LowByte = (B<<4) | A

OR


Z = (D<<12) | (C<<8) | (B<<4) | A


I see other ways, but this should be more than enough to start ;)

mister_e
- 11th November 2008, 21:44
One step further..


Z VAR WORD
A VAR Z.LOWBYTE
B VAR BYTE
C VAR Z.HIGHBYTE
D VAR BYTE

'
' Some other code where you set A, B, C & D BYTE variables
'

Z.HIGHBYTE = Z.HIGHBYTE | (D<<4)
Z.LOWBYTE = Z.LOWBYTE | (B<<4)
' Now you have everything in Z... easy huh?

or.. yet another


Z = Z | (B<<4) | (D<<12)
Enjoy :D

tazntex
- 11th November 2008, 22:06
I've tried Ioannis suggestion and it seems to work fine, I'll will try the others to. I do not plan to ever use bits 7-4 so I will give these a try. I am just playing around trying to see what does and does not work. I learned something new and appreciate all the help.

Again, Many Thanks

Ioannis
- 11th November 2008, 22:23
Steve's solutions cover the case that high nibble could hold some bits at 1 and masks to zero. Mine is based on the assumption that high nibbles will always be 0.

It would also be interesting to know which way is less memory hungry.

Ioannis

mister_e
- 11th November 2008, 22:31
this one


Z VAR WORD
A VAR Z.LOWBYTE
B VAR BYTE
C VAR Z.HIGHBYTE
D VAR BYTE

'
' Some other code where you set A, B, C & D BYTE variables
'

Z.HIGHBYTE = Z.HIGHBYTE | (D<<4)
Z.LOWBYTE = Z.LOWBYTE | (B<<4)

ought to be the the less memory hungry.

while changing the last two line by

Z = Z | (B<<4) | (D<<12)
should use more code space.

In the above A & C are Aliases, so shouldn't need any extra RAM.

this


z=a+b<<4+c<<8+d<<12

ought to use load of RAM and time to execute... BUT this said, I'm rusty and my memory/capacity fade since few months...

Darrel Taylor
- 12th November 2008, 00:17
Here's one that won't get used.
But since the questions of how big and how fast came up, you won't find anything smaller or faster. (unless Bruce shows up) :)


GroupVars VAR BYTE[6]
A VAR GroupVars(0)
B VAR GroupVars(1)
C VAR GroupVars(2)
D VAR GroupVars(3)
ZW VAR WORD EXT : @ZW = _GroupVars + 4

ASM
CHK?RP _GroupVars
swapf _D, W ; swap nibbles in D
iorwf _C, W ; or with C
movwf ZW + 1 ; move to Highbyte of word
swapf _B, W ; swap nibbles in B
iorwf _A, W ; or with A
movwf ZW ; move to LowByte of word
ENDASM

mister_e
- 12th November 2008, 00:50
yeah, no complaint at all, ASM route is easy & fast, but the only minor problem it use a bit more of RAM?

Who cares anyway :D

Darrel Taylor
- 12th November 2008, 01:17
Technically, it uses less RAM.

A statement like z=a+b<<4+c<<8+d<<12

Will create 3 T variables to hold the intermediate results.
Each T var is a Word (Long for PBPL), so it uses at least 6 more bytes of RAM.
Of course, if the program already had T vars from other statements, it won't make any difference.

For Flash, it uses 6-8 words depending on variable locations.
z=a+b<<4+c<<8+d<<12, uses ~60 depending on library routines already used.

And Time wise, it takes about 6-8 uS @ 4Mhz
z=a+b<<4+c<<8+d<<12, uses several hundred.
<br>

Ioannis
- 12th November 2008, 07:00
OK, that was not fair Darrel!

Cannot beat ASM code of course.

If I wanted to do that way, how can one find what this CHK?RP does? Where does this come from? I suppose there is no RTFM on this. Maybe digging deep inside PBP's librarys?

Ioannis

Bruce
- 12th November 2008, 08:51
OK - here's a little smaller verion...;o}


Z VAR WORD BANK0 ; use BANKA for 18F part
A VAR Z.LowByte
B VAR BYTE BANK0
C VAR Z.HighByte
D VAR BYTE BANK0

A=%00000001
B=%00000010
C=%00000011
D=%00000100

ASM
CHK?RP _Z
swapf _B, W ; swap nibbles in B, result in W
iorwf _A, F ; or with A, result in A (low byte is done)
swapf _D, W ; swap nibbles in D, result in W
iorwf _C, F ; or with C, result in C (HighByte is done)
ENDASM
Z = %0100 0011 0010 0001

Jerson
- 12th November 2008, 11:53
Wow! What compact and fast code! Both Bruce and DT must have been coding in Assembler for ages to have such skill ;) I might have coded it like Steve(mister_e) here and just got the job done. But, I guess, this is how compiler writers optimize their code generation capabilities. I would like to hazard a thought that this kind of optimisations would help PBP generate tighter code.

Darrel Taylor
- 12th November 2008, 13:50
That's why we don't have optimization contests for money around here...

Bruce would always win. :)

SWEET!<hr>

Ioannis,

The CHK?RP macro just changes the bank to where the specified variable is located. That way you don't have to keep track of where everything is. You can let PBP handle the banking, even though it's ASM.

And yup, wading through the library is about the only RTFM.
It's in the PBPPIC14.lib file for the 12F and 16F's.

Ioannis
- 13th November 2008, 07:47
Thanks Darrel. But if the macro had to change the page, how will it restore backe the original page? It isn't called again. Is this done automatically?

Ioannis

mister_e
- 13th November 2008, 20:25
PBP will handle it for you on the next PBP command.

Ioannis
- 13th November 2008, 20:35
Oh, I see. OK, Thanks Steve.

Ioannis

Darrel Taylor
- 14th November 2008, 01:13
There is another macro that resets it to bank0 ...
RST?RP ' Reset to Bank0

The ASM statement uses that macro to set the bank to 0.
So when you enter an ASM block, you always know you're starting off in bank0.

The ENDASM does not reset to bank0, but as long as you use PBP's banking system and don't change it manually, then after you exit the ASM block, PBP knows what bank you changed to, and will be able to continue on.

If you do GOTO's or BRA's in the ASM block, you have to be more careful, because PBP's banking system can't follow the jumps. It's up to you to make sure the banks are correct before jumping.

If the banks are changed manually without PBP's assistance, then you have to reset the bank manually before exiting the ASM block.
banksel 0
PREVBANK = 0
ENDASM

hth,