This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Accessing 20-bit memory range - issues with indirect addressing mode

Expert 1140 points

Hi,
I'm trying to figure out how to properly erase (and then to write, but
this is the fist step to have anything working) flash region from high
memory (over 64kB), thus using 20-bit mode.

The erase procedure is quite straightforward:

unsigned long flash_addr = 0x1c400;
unsigned long flash;
unsigned int sr;

FCTL3 = FWKEY; // Clear Lock bit
while (FCTL3 & BUSY) ;
FCTL1 = FWKEY + MERAS; // Set MERAS bit

__asm__ __volatile__ ("mov r2,%0":"=r"(sr):); // save SR before disabling IRQ
__dint();
__asm__ __volatile__ ("movx.a %1,%0":"=r"(flash):"m"(flash_addr)); //
move 20 bit flash address from variable to a register
__asm__ __volatile__ ("clrx @%0"::"r"(flash));  // dummy write 0 (or
clrx) to the address contained in the register
__asm__ __volatile__ ("mov %0,r2"::"r"(sr)); // restore previous SR
and IRQ state
__eint();

while (FCTL3 & BUSY) ; // test busy
FCTL1 = FWKEY; // Clear MERAS bit
FCTL3 = FWKEY + LOCK; // Set LOCK bit

This code does not work, I've been struggling with it for a couple of
hours and still miss what is wrong.
Disassembly looks like this:

unsigned long flash_addr = 0x1c400;
    4458: b4 40 00 c4 mov #-15360,-10(r4) ;#0xc400, 0xfff6(r4)
    445c: f6 ff
    445e: 94 43 f8 ff mov #1, -8(r4) ;r3 As==01, 0xfff8(r4)
unsigned long flash;
unsigned int sr;

FCTL3 = FWKEY; // Clear Lock bit
    4462: b2 40 00 a5 mov #-23296,&0x0144 ;#0xa500
    4466: 44 01
while (FCTL3 & BUSY) ;
    4468: 03 43       nop
    446a: 1f 42 44 01 mov &0x0144,r15
    446e: 1f f3       and #1, r15 ;r3 As==01
    4470: 4f 4f       mov.b r15, r15
    4472: 4f 93       tst.b r15
    4474: fa 23       jnz $-10     ;abs 0x446a
FCTL1 = FWKEY + MERAS; // Set MERAS bit
    4476: b2 40 04 a5 mov #-23292,&0x0140 ;#0xa504
    447a: 40 01

__asm__ __volatile__ ("mov r2,%0":"=r"(sr):); // save SR before disabling IRQ
    447c: 0b 42       mov r2, r11
    447e: 84 4b f0 ff mov r11, -16(r4) ;0xfff0(r4)
__dint();
    4482: 32 c2       dint
    4484: 03 43       nop
__asm__ __volatile__ ("movx.a %1,%0":"=r"(flash):"m"(flash_addr)); //
mov 20-bit flash address from variable to a reg
    4486: 80 1f 5a 44 movx.a -10(r4),r10 ;0xffff6(r4)
    448a: f6 ff
    448c: 84 4a f2 ff mov r10, -14(r4) ;0xfff2(r4)
    4490: 84 4b f4 ff mov r11, -12(r4) ;0xfff4(r4)
__asm__ __volatile__ ("clrx @%0"::"r"(flash)); // dummy write 0 (or
clrx) to the address contained in the reg
    4494: 1e 44 f2 ff mov -14(r4),r14 ;0xfff2(r4)
    4498: 1f 44 f4 ff mov -12(r4),r15 ;0xfff4(r4)
    449c: 40 18 8e 43 clrx 0(r14) ;0x00000(r14)

The address 0x1c400 is properly stored on the stack in -10(r4) (4458
and 445e). Then at 4486 it is mov'ed to r10, which is ok.
What happens in 448c and 4490? What is expected at -14(r4) and why is
the SR used in 4490 (mov'ed to r11 in 447c)? There is no C code
accompanying it.

I guess this is the problem as I can see in 448c and 4490 some strange
data to be written to the stack and when the clrx is called at 449c it
uses an indexed r14 with an offset of 0. I made a big mess :-)
Where is the issue in my code?

Using
__asm__ __volatile__ ("movx #0,&0x1c400");
works correctly, my goal was to make this address stored in a variable.

I thought that maybe there is no need to move the flash_addr to the register and to use "m" constraint, like this:

__asm__ __volatile__ ("clrx %0"::"m"(flash_addr));

But it does not work either, the most important disassembly part looks this way:

	unsigned long flash_addr = 0x1c400;
    4454:	b4 40 00 c4 	mov	#-15360,-8(r4)	;#0xc400, 0xfff8(r4)
    4458:	f8 ff 
    445a:	94 43 fa ff 	mov	#1,	-6(r4)	;r3 As==01, 0xfffa(r4)
[...cut...]
	__asm__ __volatile__ ("clrx %0"::"m"(flash_addr)); 		// dummy write 0 (or clrx) to the address contained in the reg
    4482:	4f 18 84 43 	clrx	-8(r4)		;0xffff8(r4)
    4486:	f8 ff 

This time it looks like clrx gets stack contents at -8(r4) but I am not sure if it reaches the contents of -6(r4) so to produce the corect 0x1c400 address.

Do you have any idea where do I make it wrong?


Best Regards,
tml

  • OK, the problem is narrowed down to the difference between:

    __asm__ __volatile__ ("movx #0, @%0"::"r"(flash));

    versus

    char Byte = 0;
    __asm__ __volatile__ ("movx.b %1, @%0":"=r"(flash):"m"(Byte));

    The first one causes the program to mess up the flash bank A from where I run the code and erase from address 0xc400 instead of 0x1c400.

    The latter one works ok.

    They seem to me to be the same, why they are not? It does not matter if I use movx.b or movx (where word is applied).

  • Ok, found it! I have misplaced the input and output operands:
    Correct: __asm__ __volatile__ ("movx.b #0, @%0":"=r"(flash):);
    Incorrect: __asm__ __volatile__ ("movx.b #0, @%0"::"=r"(flash));

    Case closed.

**Attention** This is a public forum