This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

maybe bug: far argument to printf fails

Hallo,

I may have hit a bug in CX51 Ver 7.06.
If a far variable is passed as an argument
to printf function; it fails. I wrote
this program:

#include <Philips\reg51m.h>
#include <stdio.h>

#pragma USERCLASS (HDATA=MYRAM)

far long int l ;

void main ()
{
	T2CON = 0x34 ;
	RCAP2H = 0xff ;
	RCAP2L = 0xdc ;
	SCON = 0x70 ;
	TI = 1 ;
	l = 100 ;
	printf("simple text message\n") ;
	printf("value = %ld\n",l) ;
	printf("value = %ld\n",12345678L) ;
}

The first printf works ok.
The second fails. It prints nothing.
The third again works ok.
I looked at the assembler code generated
by the compiler, and I think it is a bug:

; 	printf("simple text message\n") ;
			; SOURCE LINE # 16
	MOV  	R3,#BYTE2 (?SC_0)
	MOV  	R2,#HIGH (?SC_0)
	MOV  	R1,#LOW (?SC_0)
	LCALL	_printf
; 	printf("value = %ld\n",l) ;
			; SOURCE LINE # 17
	MOV  	R3,#BYTE2 (l)
	MOV  	R2,#HIGH (l)
	MOV  	R1,#LOW (l)
	LCALL	?C?LLDPTR
	MOV  	?_printf?BYTE+06H,R7
	MOV  	?_printf?BYTE+05H,R6
	MOV  	?_printf?BYTE+04H,R5
	MOV  	?_printf?BYTE+03H,R4
	LCALL	_printf
; 	printf("value = %ld\n",12345678L) ;
			; SOURCE LINE # 18
	MOV  	R3,#BYTE2 (?SC_21)
	MOV  	R2,#HIGH (?SC_21)
	MOV  	R1,#LOW (?SC_21)
	MOV  	?_printf?BYTE+06H,#04EH
	MOV  	?_printf?BYTE+05H,#061H
	MOV  	?_printf?BYTE+04H,#0BCH
	MOV  	?_printf?BYTE+03H,#00H
	LJMP 	_printf

Is this really a bug, or am I doing something
wrong?
If I am wrong, then what is right?
If this is a bug, then is there a workaround?

thanks to all readers!

mk

Parents Reply Children
  • Hallo Mr.Neil,


    Do your 'far' variables work elsewhere?


    Yes! no other problem with far variables.

  • Hello,

    In september i wrote a program using FAR variables
    on a TRISCEND E5, and for debug purpose i use printf,

    and i have NO problem, except that LX51 make wrong code packing. Keil has corrected that.

    So i use Cx51 V7.07a (not 7.06).
    And if you want to make a test, disable linker code packing...

    sincerely
    Christophe.

  • Dear Mr.Christophe,

    It is interesting to note that you did not
    have problems with printf and far variables.
    What processor did you use? I am using MX.

    Besides, the assembler code seems to be
    wrong (at least to me).
    The second and third printf are very similar,
    but the code is different.
    Consider the third printf (which works ok):
    pointer to format string is loaded in R1,R2,
    and R3.
    the long int argument (12345678L) is copied
    to (?_printf?BYTE+03H), (?_printf?BYTE+04H),
    (?_printf?BYTE+05H) and (?_printf?BYTE+06H).
    This works ok.
    Now compare this with the second printf:
    the long int argument (l) is copied
    to (?_printf?BYTE+03H), (?_printf?BYTE+04H),
    (?_printf?BYTE+05H) and (?_printf?BYTE+06H).
    But the pointer to format string is NOT
    loaded in R1, R2, R3. And the second printf
    does not work (prints nothing). If I assign
    the far var l to another non-far variable
    and then pass it to printf, then it works
    very well. This is the code generated:

    ; 	l2 = l ;
    			; SOURCE LINE # 19
    	MOV  	R3,#BYTE2 (l)
    	MOV  	R2,#HIGH (l)
    	MOV  	R1,#LOW (l)
    	LCALL	?C?LLDPTR
    	MOV  	l2+03H,R7
    	MOV  	l2+02H,R6
    	MOV  	l2+01H,R5
    	MOV  	l2,R4
    ; 	printf("value = %ld\n",l2) ;
    			; SOURCE LINE # 20
    	MOV  	R3,#BYTE2 (?SC_21)
    	MOV  	R2,#HIGH (?SC_21)
    	MOV  	R1,#LOW (?SC_21)
    	MOV  	?_printf?BYTE+06H,R7
    	MOV  	?_printf?BYTE+05H,R6
    	MOV  	?_printf?BYTE+04H,R5
    	MOV  	?_printf?BYTE+03H,R4
    	LCALL	_printf
    

    Clearly, the code generated is different
    depending on whether the argument is a far
    variable or non-far (or constant).

    I think it is a bug.
    Are you sure, this is fixed in Ver 7.07a?
    How can I get an upgrade?
    If this is not fixed yet, then what is the
    work around? I can not afford to use one
    extra variable and one extra statement to
    copy the far var into non-far var (because
    I will need to do it at so many places).

    Has somebody found a work around?

    Waiting...
    mk

  • Dear Mr.Christophe,

    How to disable "linker code packing" ???
    I could not find such an option.

    Meanwhile, I have another observation
    whiich further indicates that it is a bug.
    I changed the optimization to level 7
    (earlier, it was the default level 8).
    And see what difference it made to the
    generated code:

    ; 	printf("value = %ld\n",l) ;
    			; SOURCE LINE # 18
    
    	MOV  	R3,#BYTE2 (?SC_21)
    	MOV  	R2,#HIGH (?SC_21)
    	MOV  	R1,#LOW (?SC_21)
    
    	MOV  	R3,#BYTE2 (l)
    	MOV  	R2,#HIGH (l)
    	MOV  	R1,#LOW (l)
    	LCALL	?C?LLDPTR
    	MOV  	?_printf?BYTE+06H,R7
    	MOV  	?_printf?BYTE+05H,R6
    	MOV  	?_printf?BYTE+04H,R5
    	MOV  	?_printf?BYTE+03H,R4
    	LCALL	_printf
    

    The first 3 statements actually load the
    pointer to format string in R1, R2, R3.
    (These 3 statements were removed by
    8th level optimization?). But it still
    does not work, because this pointer is
    destroied before lcall _printf.

    Now I am sure that this is a bug, and not
    a problem in my program
    .

    But what can I do now?

    mk

  • Hello,

    My processor isn't a MX device. it's a 8051 with extended memory areas.

    For my test i use the version 7.07a.
    you can download it to the upgrade page on keil website.
    http://www.keil.com/update/c51.htm

    In the release note keil talk about far pointer and MX processors, in different manner, but your problem maybe solved with this release.

    Did you tried to make a step by step run in asm in this following line ? Just to check that all is ok and check what line goes wrong... (Like wrong address calculated by linker or another mistake... ) ?

    Christophe.

  • Hallo,

    Thanks! I will try to download the upgrade.

    I did not debug, but the error is obvious
    in the assembler code generated. The pointer
    to format string is simply not passed to
    printf function. As a result, there is no
    output.

    mk