Menu

#3556 Bug with new calling convention in STM8

closed-fixed
None
STM8
5
2023-03-16
2023-02-19
Ahmed Eshra
No

I have attached a Makefile, main.c and 8 artifacts. They are all made from the Makefile and can be cleaned using make clean.

There are 2 rules in the Makefile:
Nobug which builds the code with sdcccall 0, and everything works as expected, and
Bug which builds the code with sdcccall 1, and experiences buggy behavior.

Expected Behavior for both Make rules: Pin PA1 follows PB2.
Nobug Behavior: Exactly as expected.
Bug Behavior: PA1 stays 0, can't see where execution is since i don't have a debugger setup.

10 Attachments

Related

Wiki: NGI0-Entrust-SDCC

Discussion

  • Maarten Brock

    Maarten Brock - 2023-02-19

    Have you tried to build with --no-peep to see if this is introduced by the peephole optimizer?

     
  • Philipp Klaus Krause

    Wich version of SDCC did you use (sdcc --version)?

     
  • Philipp Klaus Krause

    I current SDCC, using default options, I get the same asm code as you get for the "bug" rule.

    But when I test the functions individually, they all work as expected. I didn't test on STM8 hardware, though.

    In particular, the following regression test passes:

    /* bug-3556.c
       ?
     */
    
    #include <testfwk.h>
    
    #include <stdint.h>
    #include <stdio.h>
    #include <setjmp.h>
    
    jmp_buf buf;
    
    uint8_t pa_odr, pb_idr, dummy;
    
    #define PA_ODR pa_odr
    #define PA_DDR dummy
    #define PA_CR1 dummy
    #define PA_CR2 dummy
    #define PB_IDR pb_idr
    
    void setBit(uint8_t* port, uint8_t bit){
        (*(port)) |= (1 << bit);
    }
    
    void clearBit(uint8_t* port, uint8_t bit){
        (*(port)) &= ~(1 << bit);
    }
    
    void toggleBit(uint8_t* port, uint8_t bit){
        (*(port)) ^= (1 << bit);
    }
    
    uint8_t extractBit(uint8_t port, uint8_t bit){
       return ((port & (1 << bit)) >> bit);
    }
    
    void writeBit(uint8_t* port, uint8_t bit, uint8_t value){
        if(value){
            setBit(port, bit);
        }
        else{
            clearBit(port, bit);
        }
        longjmp (buf, 1);
    }
    
    void m(){
        setBit(&PA_DDR, 1); // configure PA1 as output
        setBit(&PA_CR1, 1); // push-pull mode
        setBit(&PA_CR2, 1); // high speed
    
        while (1) 
        {
            writeBit(&PA_ODR, 1, extractBit(PB_IDR, 2));
        }
    }
    
    void writeBit2(uint8_t* port, uint8_t bit, uint8_t value){
        if(value){
            setBit(port, bit);
        }
        else{
            clearBit(port, bit);
        }
    }
    
    void m2(){
        int i = 1;
        setBit(&PA_DDR, 1); // configure PA1 as output
        setBit(&PA_CR1, 1); // push-pull mode
        setBit(&PA_CR2, 1); // high speed
    
        while (i--) 
        {
            writeBit2(&PA_ODR, 1, extractBit(PB_IDR, 2));
        }
    }
    
    void
    testBug1 (void) {
        pb_idr = 1 << 2;
        pa_odr = 0;
        if (!setjmp (buf))
            m ();
        ASSERT (pa_odr == 1 << 1);
    
        pb_idr = 0 << 2;
        pa_odr = 0;
        if (!setjmp (buf))
            m ();
        ASSERT (pa_odr == 0 << 1);
    
        pb_idr = 1 << 2;
        pa_odr = 0;
        m2 ();
        ASSERT (pa_odr == 1 << 1);
    
        pb_idr = 0 << 2;
        pa_odr = 0;
        m2 ();
        ASSERT (pa_odr == 0 << 1);
    }
    
     
    • Philipp Klaus Krause

      Even this passes for test-stm8 (but will fail for other targets, since the 0x5000 address range is used otherwise there):

      /* bug-3556.c
         ?
       */
      
      #include <testfwk.h>
      
      #include <stdint.h>
      #include <stdio.h>
      #include <setjmp.h>
      
      jmp_buf buf;
      
      #define PA_ODR (*(volatile uint8_t *)(0x5000))
      #define PA_DDR (*(volatile uint8_t *)(0x5002))
      #define PA_CR1 (*(volatile uint8_t *)(0x5003))
      #define PA_CR2 (*(volatile uint8_t *)(0x5004))
      #define PB_IDR (*(volatile uint8_t *)(0x5006))
      
      
      void setBit(uint8_t* port, uint8_t bit){
          (*(port)) |= (1 << bit);
      }
      
      void clearBit(uint8_t* port, uint8_t bit){
          (*(port)) &= ~(1 << bit);
      }
      
      void toggleBit(uint8_t* port, uint8_t bit){
          (*(port)) ^= (1 << bit);
      }
      
      uint8_t extractBit(uint8_t port, uint8_t bit){
         return ((port & (1 << bit)) >> bit);
      }
      
      void writeBit(uint8_t* port, uint8_t bit, uint8_t value){
          if(value){
              setBit(port, bit);
          }
          else{
              clearBit(port, bit);
          }
          longjmp (buf, 1);
      }
      
      void m(){
          setBit(&PA_DDR, 1); // configure PA1 as output
          setBit(&PA_CR1, 1); // push-pull mode
          setBit(&PA_CR2, 1); // high speed
      
          while (1) 
          {
              writeBit(&PA_ODR, 1, extractBit(PB_IDR, 2));
          }
      }
      
      void writeBit2(uint8_t* port, uint8_t bit, uint8_t value){
          if(value){
              setBit(port, bit);
          }
          else{
              clearBit(port, bit);
          }
      }
      
      void m2(){
          int i = 1;
          setBit(&PA_DDR, 1); // configure PA1 as output
          setBit(&PA_CR1, 1); // push-pull mode
          setBit(&PA_CR2, 1); // high speed
      
          while (i--) 
          {
              writeBit2(&PA_ODR, 1, extractBit(PB_IDR, 2));
          }
      }
      
      void
      testBug (void) {
          PB_IDR = 1 << 2;
          PA_ODR = 0;
          if (!setjmp (buf))
              m ();
          ASSERT (PA_ODR == 1 << 1);
      
          PB_IDR = 0 << 2;
          PA_ODR = 0;
          if (!setjmp (buf))
              m ();
          ASSERT (PA_ODR == 0 << 1);
      
          PB_IDR = 1 << 2;
          PA_ODR= 0;
          m2 ();
          ASSERT (PA_ODR == 1 << 1);
      
          PB_IDR = 0 << 2;
          PA_ODR = 0;
          m2 ();
          ASSERT (PA_ODR == 0 << 1);
      }
      
       
    • Philipp Klaus Krause

      Interestingly, this test fails for pdk15 --stack-auto.

      P.S.: Having had a first look at the failure in the simulator, apparently extractBit always returns 0.

       

      Last edit: Philipp Klaus Krause 2023-03-16
      • Philipp Klaus Krause

        The pdk-specific issue is fixed in [r13906].

         

        Related

        Commit: [r13906]

  • Philipp Klaus Krause

    • assigned_to: Philipp Klaus Krause
     
  • Philipp Klaus Krause

    • status: open --> closed-fixed
     
  • Philipp Klaus Krause

    I have now tested this on a STM8S105K4T6, and see the bug using the .ihx files you provided. Looks like the bug where a pop a was used to adjust the stack overwriting a still-needed parameter in a just before a tail-call optimized call. That bug was fixed a while ago.
    When I compile your code using current sdcc 4.2.14 [r13906], I see pin PA1 follow PB2.

     

    Related

    Commit: [r13906]


Log in to post a comment.

MongoDB Logo MongoDB