From: Peter V. E. <va...@sf...> - 2011-09-23 05:27:19
|
Can anyone shed light on this problem? with a relatively recent (within the last few weeks) snap of SDCC the following code misbehaves (at least as far as printing goes): // start of running stack (in DATA memory) __data uint8 * __data sys_rstack; ... // get the start of the stack __asm mov a,#__start__stack mov _sys_rstack,a __endasm; as expected (dumping memory with a debugger) sys_rstack contains the hex value of the intitial stack (0x45 in this case). In the main routine a printf gets the wrong value: extern __data uint8 * __data sys_rstack; // string for LCD output #define STR_LEN 80 __xdata uint8 str[STR_LEN]; ... main() { ... sprintf (str,"%x", (uint8) *sys_rstack); lcd_print(2, str); generates: 707 ; main.c:107: sprintf (str,"%x", (uint8) * sys_rstack); 01B4 A9 10 708 mov r1,_sys_rstack 01B6 87 07 709 mov ar7,@r1 01B8 C0 07 710 push ar7 01BA 74 53 711 mov a,#__str_3 01BC C0 E0 712 push acc 01BE 74 7E 713 mov a,#(__str_3 >> 8) 01C0 C0 E0 714 push acc 01C2 74 80 715 mov a,#0x80 01C4 C0 E0 716 push acc 01C6 74 DC 717 mov a,#_str 01C8 C0 E0 718 push acc 01CA 74 01 719 mov a,#(_str >> 8) 01CC C0 E0 720 push acc 01CE E4 721 clr a 01CF C0 E0 722 push acc 01D1 12 7D 15 723 lcall _sprintf 01D4 E5 81 724 mov a,sp 01D6 24 F9 725 add a,#0xf9 01D8 F5 81 726 mov sp,a 727 ; main.c:108: lcd_print(2, str); but displays on the LCD 6100 rather than the expected (because thats whats in data location 10H) 45. The code above appears to be loading the contents of sys_rstack (at 0x10 in data) in to r7 but something undesirable happens after that (which may well be operator error on my part). debug cmd> d D:0000 24 0000: 00 00 02 03 00 40 1E 00 C1 0F 15 00 6F 03 18 18 0010: 45 2F 01 05 5D 02 00 00 DE 10 00 02 04 08 00 00 0020: 51 0A 04 01 Peter Van Epp |
From: Maarten B. <sou...@ds...> - 2011-09-23 06:06:57
|
Hello Peter, > In the main routine a printf gets the wrong value: > > extern __data uint8 * __data sys_rstack; > > // string for LCD output > #define STR_LEN 80 > __xdata uint8 str[STR_LEN]; > > main() > { > sprintf (str,"%x", (uint8) *sys_rstack); > lcd_print(2, str); > > generates: > 707 ; main.c:107: sprintf (str,"%x", > (uint8) * > sys_rstack); > 01B4 A9 10 708 mov r1,_sys_rstack > 01B6 87 07 709 mov ar7,@r1 > 01B8 C0 07 710 push ar7 > 01BA 74 53 711 mov a,#__str_3 > 01BC C0 E0 712 push acc > 01BE 74 7E 713 mov a,#(__str_3 >> 8) > 01C0 C0 E0 714 push acc > 01C2 74 80 715 mov a,#0x80 > 01C4 C0 E0 716 push acc > 01C6 74 DC 717 mov a,#_str > 01C8 C0 E0 718 push acc > 01CA 74 01 719 mov a,#(_str >> 8) > 01CC C0 E0 720 push acc > 01CE E4 721 clr a > 01CF C0 E0 722 push acc > 01D1 12 7D 15 723 lcall _sprintf > 01D4 E5 81 724 mov a,sp > 01D6 24 F9 725 add a,#0xf9 > 01D8 F5 81 726 mov sp,a > 727 ; main.c:108: lcd_print(2, str); > > The code above appears to be loading the contents of > sys_rstack (at 0x10 in data) in to r7 but something undesirable happens > after that (which may well be operator error on my part). Since you use an explicit cast to char on the parameter passed to a varargs function (sprintf) the value is not passed as an int as normal. This is an extension to save memory. But then your formatter must also tell it to expect a char instead of an int as %x does. Maybe it's better to just remove the inline cast. HTH, Maarten |
From: Paul F. <pg...@la...> - 2011-09-23 12:35:19
|
maarten wrote: > Hello Peter, > > > In the main routine a printf gets the wrong value: > > > > extern __data uint8 * __data sys_rstack; > > > > // string for LCD output > > #define STR_LEN 80 > > __xdata uint8 str[STR_LEN]; > > > > main() > > { > > sprintf (str,"%x", (uint8) *sys_rstack); > > lcd_print(2, str); > > > > generates: > > 707 ; main.c:107: sprintf (str,"%x", > > (uint8) * > > sys_rstack); > > 01B4 A9 10 708 mov r1,_sys_rstack > > 01B6 87 07 709 mov ar7,@r1 > > 01B8 C0 07 710 push ar7 > > 01BA 74 53 711 mov a,#__str_3 > > 01BC C0 E0 712 push acc > > 01BE 74 7E 713 mov a,#(__str_3 >> 8) > > 01C0 C0 E0 714 push acc > > 01C2 74 80 715 mov a,#0x80 > > 01C4 C0 E0 716 push acc > > 01C6 74 DC 717 mov a,#_str > > 01C8 C0 E0 718 push acc > > 01CA 74 01 719 mov a,#(_str >> 8) > > 01CC C0 E0 720 push acc > > 01CE E4 721 clr a > > 01CF C0 E0 722 push acc > > 01D1 12 7D 15 723 lcall _sprintf > > 01D4 E5 81 724 mov a,sp > > 01D6 24 F9 725 add a,#0xf9 > > 01D8 F5 81 726 mov sp,a > > 727 ; main.c:108: lcd_print(2, str); > > > > The code above appears to be loading the contents of > > sys_rstack (at 0x10 in data) in to r7 but something undesirable happens > > after that (which may well be operator error on my part). > > Since you use an explicit cast to char on the parameter passed to a > varargs function (sprintf) the value is not passed as an int as normal. > This is an extension to save memory. But then your formatter must also > tell it to expect a char instead of an int as %x does. Maybe it's better > to just remove the inline cast. what difference does the cast make? the declaration is already uint8, so isn't the cast a no-op? what am i missing? this sdcc behavior bites us (bytes us? :-) all the time -- i'm always having to go back to add "(uint)foo" casts when printing byte-wide values as %x or %d, to make the values show correctly. unless there are new format chars for byte-wide parameters, how does this save memory? what am i missing? paul > > HTH, > Maarten > =--------------------- paul fox, pg...@la... |
From: Raphael N. <rn...@we...> - 2011-09-23 17:03:43
|
Hi, > > > main.c:107: sprintf (str,"%x", (uint8) *sys_rstack); > > > 01B4 A9 10 708 mov r1,_sys_rstack > > > 01B6 87 07 709 mov ar7,@r1 > > > 01B8 C0 07 710 push ar7 [...] > what difference does the cast make? the declaration is already > uint8, so isn't the cast a no-op? what am i missing? As Maarten said, the cast inhibits automatic promotion to int: > > Since you use an explicit cast to char on the parameter passed to a > > varargs function (sprintf) the value is not passed as an int as > > normal. > this sdcc behavior bites us (bytes us? :-) all the time -- i'm always > having to go back to add "(uint)foo" casts when printing byte-wide > values as %x or %d, to make the values show correctly. unless there > are new format chars for byte-wide parameters, Not sure, but does our printf() support, say, "%hx" with "h" as a size-modifier for byte-sized args? > how does this save memory? > what am i missing? Look at the code above: Pushing one argument byte costs 6 byte code space and 1 byte stack space. If we promote byte args to int, this would cost 12 byte code space and 2 byte on the stack. At every variadic call site. And for every variadic argument. We had discussed this problem when it was implemented and did not find *the* ideal solution back then. Not sure if we can find one now :-( Best regards Raphael |
From: Philipp K. K. <pk...@sp...> - 2011-09-23 17:30:53
|
Am 23.09.2011 19:03, schrieb Raphael Neider: > > We had discussed this problem when it was implemented and did not > find *the* ideal solution back then. Not sure if we can find one now > :-( Where can I find this discussion? Not doing the argument promotions (i.e. float to double, small thing like unsigned char to int, big things to long) required by the standard looks like a bug to me. Philipp |
From: Maarten B. <sou...@ds...> - 2011-09-23 19:04:34
|
> Am 23.09.2011 19:03, schrieb Raphael Neider: > > > > > We had discussed this problem when it was implemented and did not > > find *the* ideal solution back then. Not sure if we can find one now > > :-( > > Where can I find this discussion? Not doing the argument promotions > (i.e. float to double, small thing like unsigned char to int, big things > to long) required by the standard looks like a bug to me. I'm not sure where the discussion was held, though probably on the developer mailing list. Of course there is no "ideal" solution. But if you don't want this behaviour then do not use the SDCC extensions and use --std-c99 or --std-c89 instead. The extension is useful for "small devices" which are the exact target of SDCC. SDCC != GCC. > what difference does the cast make? the declaration is already uint8, > so isn't the cast a no-op? what am i missing? No, it tells SDCC *NOT* to cast the uint8 to int as it otherwise would. > this sdcc behavior bites us (bytes us? :-) all the time -- i'm always > having to go back to add "(uint)foo" casts when printing byte-wide > values as %x or %d, to make the values show correctly. unless there > are new format chars for byte-wide parameters, how does this save > memory? There certainly are new format chars to specify byte- wide parameters. If I remember correctly they originated in the PIC backends but printf_large.c (the printf engine) supports at least the 'b' modifier. You should not have to 'go back to add "(uint)foo" casts' as the default without a cast is to pass every char as an int. Just don't add an explicit (char) cast. Maarten |
From: Philipp K. K. <pk...@sp...> - 2011-09-23 19:18:33
|
Am 23.09.2011 21:04, schrieb Maarten Brock: >> Am 23.09.2011 19:03, schrieb Raphael Neider: >> >>> >>> We had discussed this problem when it was implemented and did not >>> find *the* ideal solution back then. Not sure if we can find one now >>> :-( >> >> Where can I find this discussion? Not doing the argument promotions >> (i.e. float to double, small thing like unsigned char to int, big things >> to long) required by the standard looks like a bug to me. > > I'm not sure where the discussion was held, though > probably on the developer mailing list. > > Of course there is no "ideal" solution. But if you don't > want this behaviour then do not use the SDCC extensions > and use --std-c99 or --std-c89 instead. The extension is > useful for "small devices" which are the exact target of > SDCC. SDCC != GCC. Ah, if standard behaviour is enabled by using --std-c99 / --std-c89 it's okay. Nevertheless, IMO breaking standard-compliance to save a few bytes or cycles is not worth it. There's so much untapped potential for optimization and cases where sdcc generates horrible code; there's much more to be gained by improvements that don't break standard-compliance. Philipp |
From: Peter V. E. <va...@sf...> - 2011-09-23 20:19:27
|
On Fri, Sep 23, 2011 at 08:06:49AM +0200, Maarten Brock wrote: > Hello Peter, > <snip> > > The code above appears to be loading the contents of > > sys_rstack (at 0x10 in data) in to r7 but something undesirable happens > > after that (which may well be operator error on my part). > > Since you use an explicit cast to char on the parameter passed to a > varargs function (sprintf) the value is not passed as an int as normal. > This is an extension to save memory. But then your formatter must also > tell it to expect a char instead of an int as %x does. Maybe it's better > to just remove the inline cast. > > HTH, > Maarten > Sorry, my bad I originally had sprintf (str,"%x", *sys_rstack); and that gives 61 on the lcd, however 61 isn't the correct value, 45 is. But I see wbere my problem is, because 61 is what is in 45 of data (i.e. what 10 is pointing to and what I asked for). What I really want is sprintf (str,"%x", sys_rstack); which is the contents of Data 10h. However the above gets 4000 on the LCD because its a pointer. 01B1 12 48 50 706 lcall _lcd_print 707 ; main.c:107: sprintf (str,"%x", sys_rstac k); 01B4 AD 10 708 mov r5,_sys_rstack 01B6 7E 00 709 mov r6,#0x00 01B8 7F 40 710 mov r7,#0x40 01BA C0 05 711 push ar5 01BC C0 06 712 push ar6 01BE C0 07 713 push ar7 however sprintf (str,"%x", (int) sys_rstack); does what I wish and displays the (truncated) pointer value correctly. As I expected my problem was an incorrect understanding of what I wanted :-) By the way sprintf (str,"%hx", *sys_rstack); displays Hx on the lcd not the now expected 61. In any case thanks for the help! Peter Van Epp |
From: Maarten B. <sou...@ds...> - 2011-09-24 08:19:38
|
> > By the way > > > > sprintf (str,"%hx", *sys_rstack); > > > > displays Hx on the lcd not the now expected 61. In any case thanks for the > > help! > > Since int and short int are identical in SDCC the 'h' modifier is > not needed. And apparently printf_large.c does not support it. printf_large.c now accepts and ignores the integer modifying flags h,j,t,z in revision 6874. Maarten |
From: Maarten B. <sou...@ds...> - 2011-09-23 21:22:54
|
> What I really want is > > sprintf (str,"%x", sys_rstack); > > which is the contents of Data 10h. However the above gets 4000 on the LCD > because its a pointer. > > 01B1 12 48 50 706 lcall _lcd_print > 707 ; main.c:107: sprintf (str,"%x", sys_rstac > k); > 01B4 AD 10 708 mov r5,_sys_rstack > 01B6 7E 00 709 mov r6,#0x00 > 01B8 7F 40 710 mov r7,#0x40 > 01BA C0 05 711 push ar5 > 01BC C0 06 712 push ar6 > 01BE C0 07 713 push ar7 If you want to print a pointer, wouldn't it be wise to use the pointer format specifier (%p)? > however > > sprintf (str,"%x", (int) sys_rstack); > > does what I wish and displays the (truncated) pointer value correctly. As I > expected my problem was an incorrect understanding of what I wanted :-) > By the way > > sprintf (str,"%hx", *sys_rstack); > > displays Hx on the lcd not the now expected 61. In any case thanks for the > help! Since int and short int are identical in SDCC the 'h' modifier is not needed. And apparently printf_large.c does not support it. Maarten |
From: Peter V. E. <va...@sf...> - 2011-09-24 01:12:28
|
On Fri, Sep 23, 2011 at 11:22:47PM +0200, Maarten Brock wrote: <snip> > > If you want to print a pointer, wouldn't it be wise to use the > pointer format specifier (%p)? > Yes that does the trick without the cast. I'm just from the dark ages when there weren't pointer formats in printf. Thanks! Peter Van Epp |