bit shift code generation

2006-11-20
2013-03-12
  • kosmonaut_pirx

    kosmonaut_pirx - 2006-11-20

    hello,
    in using the hc08-port of sdcc, i was suprised the following bit shift operation works not as expected:

    unsigned char bufno;
    /* .. and set bufno to something ..  */

    // set appropriate bit in control register
    CTFLG = (1 << bufno);

    results in:

        lda    #0x01
        sta    _CTFLG
        ldx    _can_schedule_msg_bufno_1_1 ; this is the symbolic for bufno
        tstx
        beq    00136$
    00135$:
        lda    _CTFLG
        lsla
        sta    _CTFLG
        decx
        bne    00135$
    00136$:

    as you can see, the 'sta' isn't out of the loop, so the '1' is shifted through the target register. some more effort as necessary, but should do the trick. in normal ways. of course, in my case 'CTFLG' is a mcu-controlled register (don't know the real name for this kind of). in setting a one, something other action is taken automatically (the bit is cleared in fact. for the interested, this is from the mscan-module of the hc908az60a). bit shifting in the target registers just only disturbs here.

    what can i do about it?
    to discussion: is this really good to store again and again? one last 'sta' should be enough, i guess.

    thansk a lot, have a nice evening,
    bye kosmo

     
    • Maarten Brock

      Maarten Brock - 2006-11-20

      What you could try is use a volatile intermediate variable.

      volatile unsigned char mask = 1 << bufno;
      CTFLG = mask;

      How is the special function register CTFLG defined? It might also help to make it explicitly volatile allthough it should be automatically volatile already if defined as sfr.

       
      • kosmonaut_pirx

        kosmonaut_pirx - 2006-11-21

        ok, finished looking at the sources.
        i think, it's really not possible to left-shift a (multi-byte)-variable without storing each byte after the shift (on a 8bit-machine), if not using the stack. so i understand the compiler intention. which brings me to the point, why is the compiler not using the stack?
        besides of this, in the code generation of the mcs51 a distinction between one byte variables and bigger ones is made. maybe that would help as a first step, see the proposal below. i don't really like the way the accumulator register is catched regardless anything, but it's only a first draft. maybe someone has better ideas, too.

        --- /home/diederic/apps/hc08/sdcc-stable/src/sdcc/src/hc08/gen.c        2006-07-06 23:24:36.000000000 +0200
        +++ src/hc08/gen.c      2006-11-21 10:50:29.000000000 +0100
        @@ -6551,14 +6551,18 @@
             {
               size = AOP_SIZE (result);
               offset = 0;
        -      while (size--)
        -       {
        -         transferAopAop (AOP (left), offset, AOP (result), offset);
        -         offset++;
        -       }
        +      if ( size == 1 ){
        +       loadRegFromAop ( hc08_reg_a, AOP (left), offset);
        +      }
        +      else{
        +       while (size--)
        +         {
        +           transferAopAop (AOP (left), offset, AOP (result), offset);
        +           offset++;
        +         }
        +      }
             }
           freeAsmop (left, NULL, ic, TRUE);
        -
           tlbl = newiTempLabel (NULL);
           size = AOP_SIZE (result);
           offset = 0;
        @@ -6569,15 +6573,23 @@
           emitBranch ("beq", tlbl1);
           emitLabel (tlbl);

        -  shift="lsl";
        -  for (offset=0;offset<size;offset++)
        -    {
        -      rmwWithAop (shift, AOP (result), offset);
        -      shift="rol";
        -    }
        +  if ( size == 1 ){
        +    emitcode ("lsla", "");
        +  }
        +  else{
        +    shift="lsl";
        +    for (offset=0;offset<size;offset++)
        +      {
        +       rmwWithAop (shift, AOP (result), offset);
        +       shift="rol";
        +      }
        +  }
           rmwWithReg ("dec", hc08_reg_x);
           emitBranch ("bne", tlbl);
           emitLabel (tlbl1);
        +  if ( size == 1 ){
        +    storeRegToAop (hc08_reg_a, AOP(result), offset);
        +  }
           hc08_freeReg (hc08_reg_x);

           freeAsmop (result, NULL, ic, TRUE);

         
    • kosmonaut_pirx

      kosmonaut_pirx - 2006-11-20

      hello maarten,
      the sfr is already defined as volatile:

      volatile xdata at 0x0506 char CTFLG;

      yes, i did something like you proposed, and it works very well.

      have looked in the gen.c of hc08 for the cause of the behaviour too. but haven't finished yet.
      thanks.

       
    • Erik Petrich

      Erik Petrich - 2006-11-30

      This bug has now been fixed in SDCC #4492. The one byte case is not yet optimized (shifts on a stack location instead of a register); this is tricky because either the left or right operand might already exist in a register and we don't want to prematurely overwrite it. I'll optimize it on another night.

       
      • kosmonaut_pirx

        kosmonaut_pirx - 2006-11-30

        hello erik,
        thanks a lot. will switch from stable to svn-version then and try it.

         

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks