#1535 Shift error

closed-fixed
nobody
5
2013-05-25
2009-05-21
No

I started to add a really basic little monitor module to let me poke around while my system is running and I ran into this interesting behaviour.

compiler command: sdcc -mpic16 -p18f65j50 --model-small -I. --obanksel=2 --optimize-cmp -D_DEBUG --calltree -c monitor.c -o monitor.o

I get an erroneous result when shifting by an amount in a variable and storing to that same variable, but only if I don't do it to another variable first. That is best explained by some code. Here is snippet where the error occurs:

union {
uint8_t *ptr;
struct {
uint16_t val;
uint8_t thing;
} ival;
} work_addr;

uint8_t monitor_wait(uint8_t c)
{
uint8_t wb,w2;
rs232_puts("\r\nSet bit> ");
work_addr.ival.val = get_ptr();
work_addr.ival.thing = 0x80; // I don't understand but this is necessary. Why isn't it 0;
rs232_puts(" B: ");
wb = get_val();
if (wb > 7) {
rs232_puts(" oops\r\n");
return c;
}
rs232_putchar(' ');
rs232_puthex_byte(wb);
// w2 = (0x01<<wb);
wb = (0x01<<wb);
rs232_puthex_byte(wb);
// rs232_puthex_byte(w2);
*work_addr.ptr = *work_addr.ptr|wb;
rs232_puts(" (");
rs232_puthex_byte(*work_addr.ptr);
rs232_putchar(')');
break;

Notice I have the w2 = (0x01<<wb); line commented out

I get this output:

R> 0f1f 0F1F = 00 (Just to make sure it's 0)
Set bit> 0f1f B: 01 01 02 (02 )
Set bit> 0f1f B: 03 03 02 (02 )
Set bit> 0f1f B: 00 00 02 (02 )
Set bit> 0f1f B: 07 07 02 (02 )

But, if I remove the commented out lines (thereby doing the shift twice, right?) I get this output:

R> 0f1f 0F1F = 00 (Just to make sure it's 0)
Set bit> 0f1f B: 01 01 02 02 (02 )
Set bit> 0f1f B: 03 03 08 08 (0A )
Set bit> 0f1f B: 00 00 01 01 (0B )
Set bit> 0f1f B: 07 07 80 80 (8B )

Which is the correct result!

So there is a third case. I'll try, shift 0x01 by wb and store in w2.

It works correctly. Here's the code:

rs232_puts("\r\nSet bit> ");
work_addr.ival.val = get_ptr();
work_addr.ival.thing = 0x80; // I don't understand but this is necessary. Why isn't it 0;
rs232_puts(" B: ");
wb = get_val();
if (wb > 7) {
rs232_puts(" oops\r\n");
return c;
}
rs232_putchar(' ');
rs232_puthex_byte(wb);
w2 = (0x01<<wb);
rs232_puthex_byte(wb);
rs232_puthex_byte(w2);
*work_addr.ptr = *work_addr.ptr|w2;
rs232_puts(" (");
rs232_puthex_byte(*work_addr.ptr);
rs232_putchar(')');

So it seems wb = (0x01<<wb) only works if I do w2 = (0x01<<wb) first (and just discard w2).

I've attached the whole monitor file with a broken 'B' command and a working 'b' command (kind of a mess with all the extra puts's and whatnot)

Robert

Discussion

  • Robert Wuest

    Robert Wuest - 2009-05-21
     
  • Raphael Neider

    Raphael Neider - 2009-05-22

    The error can be reproduced with just

    unsigned char val;
    void foo(void) {
    val = (1 << val);
    }

    The problem is that the shiftcount (which happens to be in the same register as the result) is initialized with the left shift operand (1), thus causing all such shifts to yield 1<<1 == 2.

    Fixed in SDCC 2.9.1, r5459.

    Thanks for the report,
    Raphael

     
  • Raphael Neider

    Raphael Neider - 2009-05-22
    • milestone: --> fixed
    • status: open --> closed-fixed
     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks