Jump to content

RLNCF and RRNCF?


stryd_one
 Share

Recommended Posts

Hey you crazy coders. Great to see lots of buzz about user developed apps around here at the moment :)

I hope someone might know a trick for me.... if I use a bitshift in C with the >> or << operators, then the ASM generated is a RRCF or RLCF. These both use the Carry bit (statusbits.C aka STATUS.0).  The carry bit is cleared before the shift even if I don't specify it :(

Is there a way to have C generate a RRNCF or RLNCF instead? There are certain cases where I'd be better off without it...

Is there a way to NOT clear the carry bit before a bitshift?

While I'm on the subject of bitfields, I wonder if anyone has tried this and might be able to save me a few hours experimenting...Which is faster in a FOR loop:

Declare your bitfield in a union as normal

Test bit 'n' in the loop

or...

Declare the bitfield as a normal char, bitshift, and test the carry bit

Once upon a time I remember TK saying that bitfields could slow things down, but looking at the generated code, I suspect that the newer versions of SDCC may have fixed that problem. For example, 'statusbits.C = 0' becomes 'BCF STATUS.0'... And I think I remember AC saying that bitfields are limited to 8 bit?

Lootts of questions....

Link to comment
Share on other sites

LOL :) Yeh RTFM isn't necessarily the best thing around for plain english about it either :P Ahh it's like this...I'll just do right shift as an example.

The way it does a bitshift is really a bit rotation. Without the Carry bit, when you rotate right, the bottom bit doesn't just drop away, it gets pushed onto the top of the byte:

        v
0110 1001 >> 1 = 
1011 0100
^ 
That's an RRNCF - Rotate Right No Carry F However with the Carry Bit, there is one extra bit, and the bit that gets pushed off the end of the byte goes there:
C         v
0 0110 1001 >> 1 = 
1 0011 0100
^ 
If you continue to shift (OK rotate) after this without clearing the status bit, then it rolls back onto the byte:
C         v
1 0011 0100 >> 1 = 
0 1001 1010
^ 
That's an RRCF - Rotate Right through Carry F There are ways around it, but if you want one type of rotation, and are forced to use the other, it'll cost one instruction to get the same effect. Here's an example. scpbtemp is a long type (32b). I wrote this:
                STATUSbits.C = 0;        //Clear Carry Bit
                scpbtemp = scpbtemp >> 1;
And SDCC produced this:
;	.line	40; vxscpb.c	STATUSbits.C = 0;        //Clear Carry Bit
	BCF	_STATUSbits, 0

;	.line	41; vxscpb.c	scpbtemp = scpbtemp >> 1;
	BCF	STATUS, 0
	RRCF	r0x06, F
	RRCF	r0x05, F
	RRCF	r0x04, F
	RRCF	r0x03, F

Notice that it cleared the status bit twice - once when I told it to, and once all by itself.

This is a good demonstration of use for the carry bit... It gets pushed onto the top of each successive lower byte of the 32 bits. This is why the Carry bit needs to be cleared, atherwise some random value from another function might be pushed onto our variable, and may be why SDCC chose to use RRCF rather than RRNCF... Or it might just always use it.. I can find out, but I was hoping someone might have come across it.

But I don't like that it assumed I want that bit clear... Maybe I want the carry bit to be sent from another function? Then what? ??? Hmmmmmmm.....

Link to comment
Share on other sites

uglyla.gif

all right, you're definitely confusing me today

...no... just kidding, you explained this perfectly clear!

well, I think this would be a perfect case for an __asm / __endasm; statement, don't you think?

I'm not exactly sure, but I cannot remeber having seen something about a carry bit in C. When you shift a bit, it's gone. Though IIRC, there are some libraries that contain similar functions; but as these are not available in our case, it'll be best to do this in __asm.

Cheers ;D

Michael

Link to comment
Share on other sites

hehehe yeh I went on a mission to figure out a problem, and found three more while I was there :P

I could use naked ASM there but I'm trying to keep it portable where I can... I'll experiment today and see what it does with an unsigned char...

Link to comment
Share on other sites

Basically the compiler is doing what it needs to do to support the C shift operators, which have no concept of carry bits, i.e. they always shift zeros into the byte. Which makes sense, because 99.99% of the time you're doing a shifting of bits in a bitmask, i.e. to generate a bitmask with just bit 2 set you write "1 << 2".

So it's not just assuming you want that bit clear, it's meeting the specification of C, and there's nothing in C that does "rotate no carry", you have to code that explicitly.

If you're shifting through one or more bytes in PIC ASM you would have to set the carry bit to the first (or last) bit prior to doing the "rotate through carry" ops.... this is generally achieved by doing an RRCF or RLCF putting result into W (i.e. just shift the bit into the carry but don't do the rotate on the register).

A similar thing has to be done in C for every time you're bit shifting and want anything but zeros coming in... so for one byte you'd have to do something like this:


    /* rotate left no carry */
    x = ( x & 0x80 ? 0x01 : 0x00 ) | ( x << 1 );
    /* rotate right no carry */
    x = ( x & 0x01 ? 0x80 : 0x00 ) | ( x >> 1 );
[/code]

I don't know how efficient that compiles with SDCC, but it's going to be less efficient than just doing two RLCF or RRCF.

Link to comment
Share on other sites

Ahh that explains it. Damn standards. If I were Bill Gates I could ignore this. ;D

I had a look at it and was interested to find out that it always uses the carry bit when it rotates - but in a lot of cases for shifts of static magnitude it doesn't use R*CF at all - like for <<2, it does an ADDLW to double the number...

Where the magnitude of the shift is variable, it will use that variable as a counter, and uses a rotate (with carry) . Where the variable being shifted is > 8bit then it uses rotate with carry always.

Link to comment
Share on other sites

Yeah that makes sense... there's no C code that would translate to a rotate without carry. But I don't understand the ADDLW usage exactly, are you talking about a constant left-shifted? i.e. 4 << 2 becomes "movlw 4, addlw 4" ?

Link to comment
Share on other sites

are you talking about a constant left-shifted? i.e. 4 << 2 becomes "movlw 4, addlw 4" ?

Yeh exactly. It just finds the method that uses the least instructions to get the correct answer. I guess it makes sense but it wasn't what I expected to find.

;	.line	149; main.c	bstest = bstest << 5;
	SWAPF	_bstest, W, B
	ANDLW	0xf0
	MOVWF	_bstest, B
	ADDWF	_bstest, F, B

;	.line	149; main.c	bstest = bstest << 7;
	RRCF	_bstest, W, B
	CLRF	_bstest, B
	RRCF	_bstest, F, B

Weird, but good :)

Link to comment
Share on other sites

  • 10 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...