0

im trying to do a multithreading library for atmega controller and firstly i try to manipulate the stack pointer and after the return of function "go_to_func" the program goes in function "func". The function "go_to_func" is written in asm1.s file and this is the function where the stack pointer is modify for the program to return at the start address of "func" but my program don't geos on "func" after the return of "go_to_func"(When the program arrive on "func" the PORTD bit 3 is turned on). Can anyone tell my what i have to write on "go_to_func" to make my program works fine. Here is the hole information of my code.

main.c

#include <avr/io.h>
#include <stdlib.h>
#include "asm1.h"


#define  CALL_FCT    __attribute__ ((noinline))

#define RETURN_SIZE 2

uint8_t fn_stack[128];

uint8_t addr_l;
uint8_t addr_h;

void  CALL_FCT  func( void )
{
    PORTD = 0x08 ;

    while(1)
    {

    }
}

void  CALL_FCT  init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
    *(stack + stack_size - RETURN_SIZE    ) = (uint16_t)fn >> 8;
    *(stack + stack_size - RETURN_SIZE + 1) = (uint8_t)(uint16_t)fn;

    addr_l = (uint8_t)(uint16_t)(stack + stack_size    );
    addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);

    go_to_func(addr_l,addr_h);
}

int  CALL_FCT  main(void)
{
    DDRD |= 0x0C ;

    init(func,fn_stack,sizeof(fn_stack));

    PORTD = 0x04 ;

    while (1)
    {
    }
}

asm1.h

#ifndef HEADER_H_
#define HEADER_H_

#include <stdint.h>

extern void go_to_func(uint8_t,uint8_t);

#endif /* HEADER_H_ */

asm1.s

 #include <avr/io.h>

 .global go_to_func
go_to_func:
  out _SFR_IO_ADDR(SPH), r22
  out _SFR_IO_ADDR(SPL), r24
  ret


/* *.lss the file of my program in assembly */
void  CALL_FCT  func( void )
{
    PORTD = 0x08 ;
  96:   88 e0           ldi r24, 0x08   ; 8
  98:   8b b9           out 0x0b, r24   ; 11
  9a:   ff cf           rjmp    .-2         ; 0x9a <func+0x4>

0000009c <init>:
    }
}

void  CALL_FCT  init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
     *(stack + stack_size - RETURN_SIZE    ) = (uint16_t)fn >> 8;
  9c:   9b 01           movw    r18, r22
  9e:   24 0f           add r18, r20
  a0:   35 1f           adc r19, r21
  a2:   f9 01           movw    r30, r18
  a4:   32 97           sbiw    r30, 0x02   ; 2
  a6:   90 83           st  Z, r25
     *(stack + stack_size - RETURN_SIZE + 1) = (uint8_t)(uint16_t)fn;
  a8:   31 96           adiw    r30, 0x01   ; 1
  aa:   80 83           st  Z, r24

     addr_l = (uint8_t)(uint16_t)(stack + stack_size    );
  ac:   20 93 01 01     sts 0x0101, r18 ; 0x800101 <addr_l>
     addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
  b0:   4f 5f           subi    r20, 0xFF   ; 255
  b2:   5f 4f           sbci    r21, 0xFF   ; 255
  b4:   64 0f           add r22, r20
  b6:   75 1f           adc r23, r21
  b8:   60 93 00 01     sts 0x0100, r22 ; 0x800100 <_edata>

     go_to_func(addr_l,addr_h);
  bc:   82 2f           mov r24, r18
  be:   0e 94 48 00     call    0x90    ; 0x90 <go_to_func>
  c2:   08 95           ret

000000c4 <main>:
}

int  CALL_FCT  main(void)
{
    DDRD |= 0x0C ;
  c4:   8a b1           in  r24, 0x0a   ; 10
  c6:   8c 60           ori r24, 0x0C   ; 12
  c8:   8a b9           out 0x0a, r24   ; 10

    init(func,fn_stack,sizeof(fn_stack));
  ca:   40 e8           ldi r20, 0x80   ; 128
  cc:   50 e0           ldi r21, 0x00   ; 0
  ce:   62 e0           ldi r22, 0x02   ; 2
  d0:   71 e0           ldi r23, 0x01   ; 1
  d2:   8b e4           ldi r24, 0x4B   ; 75
  d4:   90 e0           ldi r25, 0x00   ; 0
  d6:   0e 94 4e 00     call    0x9c    ; 0x9c <init>

    PORTD = 0x04 ;
  da:   84 e0           ldi r24, 0x04   ; 4
  dc:   8b b9           out 0x0b, r24   ; 11
  de:   ff cf           rjmp    .-2         ; 0xde <main+0x1a>

000000e0 <_exit>:
  e0:   f8 94           cli

000000e2 <__stop_program>:
  e2:   ff cf           rjmp    .-2         ; 0xe2 <__stop_program>
4

1 回答 1

0
addr_l = (uint8_t)(uint16_t)(stack + stack_size    );
addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);

your "addr_h" either needs some shifting, or you have to use r23 or r25 in your go_to_func() function. (it's not the only thing wrong, but it's the big thing.) I don't know why you're not just passing the full-length "int" ...

You know that there's a lot more to switching tasks than changing the SP, right? You haven't done anything with the registers that are supposed to be saved by the callee...

I'd suggest laying out and manipulating the new stack the same way that the processor does, with post-decrement of a pointer for push...

void  CALL_FCT  init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
    uint8_t *newsp = (stack+stack_size) - 1;  // last byte of new stack
    *newsp-- = (uint8_t)(uint16_t)fn; // "push" low fn addr
    *newsp-- = (uint16_t)fn >> 8;  // "push" high fn addr
    go_to_func(newsp);  // newsp is now properly decremented for a "ret"
}

PS: this is a good time to learn to use the simulator in AS7...

于 2018-04-07T05:37:01.523 回答