diff mbox

[Patch.AVR,4.6] Fix PR51002

Message ID 4ED4BEDE.4000600@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay Nov. 29, 2011, 11:15 a.m. UTC
For devices with 8-bit SP reading the high byte SP_H of SP will get garbage.

The patch uses CLR instead of IN SP_H to "read" the high part of SP.

There are two issues with this patch:

== 1 ==

I cannot really test it because for devices that small running test suite
does not give usable results.  So I just looked at the patch and the
small test case like the following compiled

$ avr-gcc-4.6.2 -Os -mmcu=attiny26 -m[no]call-prologues

long long a, b;

long long __attribute__((noinline,noclione))
bar (char volatile *c)
{
    *c = 1;
    return a+b;
}

long long foo()
{
    char buf[16];
    return bar (buf);
}


int main (void)
{
    return foo();
}


The C parts look fine but...


== 2 ==

The libgcc parts will still read garbage to R29 as explained in the
FIXMEs there.

Solving the FIXMEs can only be achieved by splitting multilibs avr2 and avr25,
i.e. the mutlilibs that mix devices with/without SP.H, into avr2, avr21, avr24,
avr25, say.

I don't think it's a good idea to have real 8-bit SP/FP and that it would cause
all sorts of trouble.

Ok to commit to 4.6?

What about splitting multilibs? Is this appropriate for 4.7?

Johann

	PR target/51002
	* config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__):
	Enclose parts using __SP_H__ in defined (__AVR_HAVE_8BIT_SP__).
	Add FIXME comments.
	* config/avr/avr.md (movhi_sp_r_irq_off, movhi_sp_r_irq_on): Set
	insn condition to !AVR_HAVE_8BIT_SP.
	* config/avr/avr.c (output_movhi): "clr%B0" instead of "in
	%B0,__SP_H__" if AVR_HAVE_8BIT_SP.
	(avr_file_start): Only print "__SP_H__ = 0x3e" if !AVR_HAVE_8BIT_SP.

Comments

Denis Chertykov Nov. 30, 2011, 5:46 a.m. UTC | #1
2011/11/29 Georg-Johann Lay <avr@gjlay.de>:
> For devices with 8-bit SP reading the high byte SP_H of SP will get garbage.
>
> The patch uses CLR instead of IN SP_H to "read" the high part of SP.
>
> There are two issues with this patch:
>
> == 1 ==
>
> I cannot really test it because for devices that small running test suite
> does not give usable results.  So I just looked at the patch and the
> small test case like the following compiled
>
> $ avr-gcc-4.6.2 -Os -mmcu=attiny26 -m[no]call-prologues
>
> long long a, b;
>
> long long __attribute__((noinline,noclione))
> bar (char volatile *c)
> {
>    *c = 1;
>    return a+b;
> }
>
> long long foo()
> {
>    char buf[16];
>    return bar (buf);
> }
>
>
> int main (void)
> {
>    return foo();
> }
>
>
> The C parts look fine but...
>
>
> == 2 ==
>
> The libgcc parts will still read garbage to R29 as explained in the
> FIXMEs there.
>
> Solving the FIXMEs can only be achieved by splitting multilibs avr2 and avr25,
> i.e. the mutlilibs that mix devices with/without SP.H, into avr2, avr21, avr24,
> avr25, say.
>
> I don't think it's a good idea to have real 8-bit SP/FP and that it would cause
> all sorts of trouble.

I'm agree.

>
> Ok to commit to 4.6?

Approved.

>
> What about splitting multilibs?

Seems that splitting multilibs is a right way.

> Is this appropriate for 4.7?

As I understand, any changes appropriate for our port in any stage.

> Johann
>
>        PR target/51002
>        * config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__):
>        Enclose parts using __SP_H__ in defined (__AVR_HAVE_8BIT_SP__).
>        Add FIXME comments.
>        * config/avr/avr.md (movhi_sp_r_irq_off, movhi_sp_r_irq_on): Set
>        insn condition to !AVR_HAVE_8BIT_SP.
>        * config/avr/avr.c (output_movhi): "clr%B0" instead of "in
>        %B0,__SP_H__" if AVR_HAVE_8BIT_SP.
>        (avr_file_start): Only print "__SP_H__ = 0x3e" if !AVR_HAVE_8BIT_SP.
>

Denis.
Georg-Johann Lay Nov. 30, 2011, 10:31 a.m. UTC | #2
Georg-Johann Lay wrote:

> For devices with 8-bit SP reading the high byte SP_H of SP will get garbage.
> 
> The patch uses CLR instead of IN SP_H to "read" the high part of SP.
> 
> There are two issues with this patch:
> 
> == 1 ==
> 
> I cannot really test it because for devices that small running test suite
> does not give usable results.  So I just looked at the patch and the
> small test case like the following compiled
> 
> $ avr-gcc-4.6.2 -Os -mmcu=attiny26 -m[no]call-prologues
> 
> long long a, b;
> 
> long long __attribute__((noinline,noclione))
> bar (char volatile *c)
> {
>     *c = 1;
>     return a+b;
> }
> 
> long long foo()
> {
>     char buf[16];
>     return bar (buf);
> }
> 
> 
> int main (void)
> {
>     return foo();
> }
> 
> 
> The C parts look fine but...
> 
> 
> == 2 ==
> 
> The libgcc parts will still read garbage to R29 as explained in the
> FIXMEs there.
> 
> Solving the FIXMEs can only be achieved by splitting multilibs avr2 and avr25,
> i.e. the mutlilibs that mix devices with/without SP.H, into avr2, avr21, avr24,
> avr25, say.
> 
> I don't think it's a good idea to have real 8-bit SP/FP and that it would cause
> all sorts of trouble.
> 
> Ok to commit to 4.6?
> 
> What about splitting multilibs? Is this appropriate for 4.7?
> 
> Johann
> 
> 	PR target/51002
> 	* config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__):
> 	Enclose parts using __SP_H__ in defined (__AVR_HAVE_8BIT_SP__).
> 	Add FIXME comments.
> 	* config/avr/avr.md (movhi_sp_r_irq_off, movhi_sp_r_irq_on): Set
> 	insn condition to !AVR_HAVE_8BIT_SP.
> 	* config/avr/avr.c (output_movhi): "clr%B0" instead of "in
> 	%B0,__SP_H__" if AVR_HAVE_8BIT_SP.
> 	(avr_file_start): Only print "__SP_H__ = 0x3e" if !AVR_HAVE_8BIT_SP.
> 

Dropping this patch...

There is ATtiny4313 (and maybe others) that have 8-bit SP and 0x100 RAM.
As RAM starts at 0x60, I wonder what the meaning of SP is?
Is it RAM-address % 0x100? Or offset to 0x60? Maybe Eric can clarify this?

The sequence to read SP would then be something like

IN  %A0, __SP_L__
CPI %A0, 0x60
SBC %B0, %B0
NEG %B0

to reconstruct the hight part in the first case and

IN  %A0, __SP_L__
CPI %A0, 0xA0
SBC %B0, %B0
INC %B0

the the second. It might even need more instructions because CPI need D-reg but
in movhi there is just general reg.

Moreover, the data sheet just mentions SP_L but not SP_H. Yet the sample
program from above disassembles to

...
0000002a <__ctors_end>:
  2a:	11 24       	eor	r1, r1
  2c:	1f be       	out	0x3f, r1	; 63
  2e:	cf e5       	ldi	r28, 0x5F	; 95
  30:	d1 e0       	ldi	r29, 0x01	; 1
  32:	de bf       	out	0x3e, r29	; 62
  34:	cd bf       	out	0x3d, r28	; 61
...

i.e. start-up code from avr-libc is initializing 0x3e (SP_H) with 1.

Is this bug in avr-libc or typo in the manual? The "AVR538: Migrating from
ATtiny2313 to ATtiny4313" application note does not address this either.

Johann
Joerg Wunsch Nov. 30, 2011, 10:50 a.m. UTC | #3
As Georg-Johann Lay wrote:

> There is ATtiny4313 (and maybe others) that have 8-bit SP and 0x100 RAM.
> As RAM starts at 0x60, I wonder what the meaning of SP is?

I think this is simply a bug in the datasheet.  The device description
XML file of the ATtiny4313 mentions an SPH register, and it would not
make any much sense without it.
Georg-Johann Lay Nov. 30, 2011, 11:54 a.m. UTC | #4
Joerg Wunsch wrote:
> As Georg-Johann Lay wrote:
> 
>> There is ATtiny4313 (and maybe others) that have 8-bit SP and 0x100 RAM.
>> As RAM starts at 0x60, I wonder what the meaning of SP is?
> 
> I think this is simply a bug in the datasheet.  The device description
> XML file of the ATtiny4313 mentions an SPH register, and it would not
> make any much sense without it.

Then avr-mcus.def adopted this bug from the manual for ATtiny4313 at least:

AVR_MCU ("attiny4313", ARCH_AVR25, "__AVR_ATtiny4313__", 1 /* short_sp, should
be 0 ? */, 0, 0x0060, "tn4313")

Johann
Joerg Wunsch Nov. 30, 2011, 12:49 p.m. UTC | #5
As Georg-Johann Lay wrote:

> Then avr-mcus.def adopted this bug from the manual for ATtiny4313 at least:
> 
> AVR_MCU ("attiny4313", ARCH_AVR25, "__AVR_ATtiny4313__", 1 /* short_sp, should
> be 0 ? */, 0, 0x0060, "tn4313")

Not unlikely.

I just ordered one.  Hopefully, it will be here by tomorrow, so I can
test it on a live device.
Georg-Johann Lay Dec. 1, 2011, 11:30 a.m. UTC | #6
Joerg Wunsch wrote:
> As Georg-Johann Lay wrote:
> 
>> Then avr-mcus.def adopted this bug from the manual for ATtiny4313 at least:
>>
>> AVR_MCU ("attiny4313", ARCH_AVR25, "__AVR_ATtiny4313__", 1 /* short_sp, should
>> be 0 ? */, 0, 0x0060, "tn4313")
> 
> Not unlikely.
> 
> I just ordered one.  Hopefully, it will be here by tomorrow, so I can
> test it on a live device.

Jörg, do you have an easy way to review avr-mcus.def?

http://gcc.gnu.org/viewcvs/trunk/gcc/config/avr/avr-mcus.def?content-type=text%2Fplain&view=co

If you have XML hardware descriptions that are more accurate and much more easy
to use than 1E2...1E3 PDFs that might be not too painful.

The column in question is the column after the built-in define definition like
"__AVR_AT90S2313__" i.e. the 4th column.

Johann
diff mbox

Patch

Index: config/avr/libgcc.S
===================================================================
--- config/avr/libgcc.S	(revision 181783)
+++ config/avr/libgcc.S	(working copy)
@@ -582,6 +582,15 @@  __prologue_saves__:
 	push r17
 	push r28
 	push r29
+#if defined (__AVR_HAVE_8BIT_SP__)
+;; FIXME: __AVR_HAVE_8BIT_SP__ is set on device level, not on core level
+;;        so this lines are dead code.  To make it work, devices without
+;;        SP_H must get their own multilib(s).
+	in	r28,__SP_L__
+	sub	r28,r26
+	clr	r29
+	out	__SP_L__,r28
+#else
 	in	r28,__SP_L__
 	in	r29,__SP_H__
 	sub	r28,r26
@@ -591,6 +600,7 @@  __prologue_saves__:
 	out	__SP_H__,r29
 	out	__SREG__,__tmp_reg__
 	out	__SP_L__,r28
+#endif
 #if defined (__AVR_HAVE_EIJMP_EICALL__)
 	eijmp
 #else
@@ -625,6 +635,15 @@  __epilogue_restores__:
 	ldd	r16,Y+4
 	ldd	r17,Y+3
 	ldd	r26,Y+2
+#if defined (__AVR_HAVE_8BIT_SP__)
+;; FIXME: __AVR_HAVE_8BIT_SP__ is set on device level, not on core level
+;;        so this lines are dead code.  To make it work, devices without
+;;        SP_H must get their own multilib(s).
+	ldd	r29,Y+1
+	add	r28,r30
+	out	__SP_L__,r28
+	mov	r28, r26
+#else
 	ldd	r27,Y+1
 	add	r28,r30
 	adc	r29,__zero_reg__
@@ -635,6 +654,7 @@  __epilogue_restores__:
 	out	__SP_L__,r28
 	mov_l	r28, r26
 	mov_h	r29, r27
+#endif
 	ret
 .endfunc
 #endif /* defined (L_epilogue) */
Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md	(revision 181783)
+++ config/avr/avr.md	(working copy)
@@ -299,7 +299,7 @@  (define_insn "movhi_sp_r_irq_off"
   [(set (match_operand:HI 0 "stack_register_operand" "=q")
         (unspec_volatile:HI [(match_operand:HI 1 "register_operand"  "r")] 
 			    UNSPECV_WRITE_SP_IRQ_OFF))]
-  ""
+  "!AVR_HAVE_8BIT_SP"
   "out __SP_H__, %B1
 	out __SP_L__, %A1"
   [(set_attr "length" "2")
@@ -309,7 +309,7 @@  (define_insn "movhi_sp_r_irq_on"
   [(set (match_operand:HI 0 "stack_register_operand" "=q")
         (unspec_volatile:HI [(match_operand:HI 1 "register_operand"  "r")] 
 			    UNSPECV_WRITE_SP_IRQ_ON))]
-  ""
+  "!AVR_HAVE_8BIT_SP"
   "cli
         out __SP_H__, %B1
 	sei
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 181783)
+++ config/avr/avr.c	(working copy)
@@ -1879,9 +1879,12 @@  output_movhi (rtx insn, rtx operands[],
 	    }
 	  else if (test_hard_reg_class (STACK_REG, src))
 	    {
-	      *l = 2;	
-	      return (AS2 (in,%A0,__SP_L__) CR_TAB
-		      AS2 (in,%B0,__SP_H__));
+              *l = 2;
+              return AVR_HAVE_8BIT_SP
+                ? (AS2 (in,%A0,__SP_L__) CR_TAB
+                   AS1 (clr,%B0))
+                : (AS2 (in,%A0,__SP_L__) CR_TAB
+                   AS2 (in,%B0,__SP_H__));
 	    }
 
 	  if (AVR_HAVE_MOVW)
@@ -5173,10 +5176,10 @@  avr_file_start (void)
 
   default_file_start ();
 
-/*  fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
-  fputs ("__SREG__ = 0x3f\n"
-	 "__SP_H__ = 0x3e\n"
-	 "__SP_L__ = 0x3d\n", asm_out_file);
+  fputs ("__SREG__ = 0x3f\n", asm_out_file);
+  if (!AVR_HAVE_8BIT_SP)
+    fputs ("__SP_H__ = 0x3e\n", asm_out_file);
+  fputs ("__SP_L__ = 0x3d\n", asm_out_file);
   
   fputs ("__tmp_reg__ = 0\n" 
          "__zero_reg__ = 1\n", asm_out_file);