This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

incorrect behavior with [somewhat] complex struct...

I have a somewhat complex structure in my C code, and driver functions to read or write data with it.

The simpler parts of the struct (such as ioflags2 below) and their driver functions work just fine. However, the more complex parts of the struct (such as ioflags3) do not.

The symptom is that only the drivers for the first part of the more complex parts of the structure work right, and the rest don't appear to change the "word" part of the structure.

However, if I step through the code with the simulator, all of the individual parts of the more complex parts of the struct work just fine with the driver functions, but the "word" part doesn't change (well, except for the 1st part of the more complex parts, i.e., module1 works, but module2 - module5 don't).

Finally, I cut/paste the whole struct and drivers to a Visual C++ program and stepped through the code with their debugger. *ALL* of the driver functions had the expected effect on *ALL* of the parts of the whole struct.

Can anyone tell me what, if anything, is wrong with this code, and how to make it work with KEIL's ARM tools?

  union{
    u16 word;
    struct{
      unsigned sensor1:1;
      unsigned sensor2:1;
      unsigned sensor3:1;
      unsigned sensor4:1;
      unsigned sensor5:1;
      unsigned sensor6:1;
      unsigned sensor7:1;
      unsigned sensor8:1;
      unsigned sensor9:1;
      unsigned sensor10:1;
      unsigned reserved_bit_10:1;
      unsigned reserved_bit_11:1;
      unsigned reserved_bit_12:1;
      unsigned reserved_bit_13:1;
      unsigned reserved_bit_14:1;
      unsigned reserved_bit_15:1;
    }bit;
  }ioflags2;

  union{
    u16 word;
    struct{
      struct{
        struct{
          unsigned run:1;
          unsigned direction:1;
        }stepper_motor;
      }module1;

      union{
        struct{
          unsigned extend:1;
          unsigned retract:1;
        }ioctl;
        struct{
          unsigned run:1;
          unsigned direction:1;
        }dc_motor;
      }module2;

      union{
        struct{
          unsigned open:1;
          unsigned close:1;
        }ioctl;
        struct{
          unsigned run:1;
          unsigned direction:1;
        }dc_motor;
      }module3;

      union{
        struct{
          unsigned open:1;
          unsigned close:1;
        }ioctl;
        struct{
          unsigned run:1;
          unsigned direction:1;
        }dc_motor;
      }module4;

      union{
        struct{
          unsigned reserved_bit_0:1;
          unsigned fan:1;
        }ioctl;
        struct{
          unsigned direction:1;
          unsigned run:1;
        }dc_motor;
      }module5;

      unsigned reserved_bit_10:1;
      unsigned reserved_bit_11:1;
      unsigned reserved_bit_12:1;
      unsigned reserved_bit_13:1;
      unsigned reserved_bit_14:1;
      unsigned reserved_bit_15:1;
    }bit;
  }ioflags3;

And here's how my drivers manipulate the structure.

int set_module2_retract(int state){
  int previous_state;

  ASSERT(module2_type() == TYPE_IOCTL);

  if(module2_type() != TYPE_IOCTL){
    return(-1);
  }

  if(state){
    set_module1_extend(0); // protect the hardware!
  }

  previous_state = variable.ioflags3.bit.module2.ioctl.retract;

  variable.ioflags3.bit.module2.ioctl.retract = state ? 1u : 0u;

  return(previous_state);
}

Parents
  • > The problem example in my first post was for a processor that
    > auto-acknowledges status bits as they are read. That means that the
    > software must do one (1) read and then process all bits.

    I think I got that part.

    > The solution to that (if we ignore other problems with bit fields) is
    > to copy the register value once to a union of an unsigned and the bit
    > fields and write:

    Sure, as I said. But the requirement of having to read the register
    just once in this case is not specific to bit fields, is it.

    > Alas, I managed to **** up the example of the old-style
    > solution. There shouldn't have been any |= in the assign, but just an
    > assign. Sorry for the confusion.

    No problem, but to be sure that we are on the same page I would still
    like to see a self contained minimal example, and preferably an
    example of a device (ideally ARM based) which exibits the difference
    behavior that you are trying to show. And I am not talking about a
    handful of perhaps redundant instructions, but code that actually
    behaves incorrectly.

    > But when leaving the ARM world, it isn't even known if the bits will
    > be allocated low-to-high or high-to-low, so switching between two
    > different compilers but staying with the same processor can
    > completely break everything.

    Possibly. It all depends on what degree of protability I need. I don't
    expect to find e.g. ARMv6/v7 page table descriptors in other
    architectures. It is perhaps a choice whether I prefer using the
    "traditional" approach with macros/enums/bit-ops everywhere or
    whether I would rather have an architecture specific header file with
    appropriate bit-field definitions.

    I don't claim that bit fields are always the better approach, but it
    seems that many people show some knee-jerk reactions against bit
    fields wherever the question comes up.

    There are valid arguments against using bit fields in certain
    situations. But most arguments thrown out by people can be disproved
    easily.

    Regards
    Marcus
    http://www.doulos.com/arm/

Reply
  • > The problem example in my first post was for a processor that
    > auto-acknowledges status bits as they are read. That means that the
    > software must do one (1) read and then process all bits.

    I think I got that part.

    > The solution to that (if we ignore other problems with bit fields) is
    > to copy the register value once to a union of an unsigned and the bit
    > fields and write:

    Sure, as I said. But the requirement of having to read the register
    just once in this case is not specific to bit fields, is it.

    > Alas, I managed to **** up the example of the old-style
    > solution. There shouldn't have been any |= in the assign, but just an
    > assign. Sorry for the confusion.

    No problem, but to be sure that we are on the same page I would still
    like to see a self contained minimal example, and preferably an
    example of a device (ideally ARM based) which exibits the difference
    behavior that you are trying to show. And I am not talking about a
    handful of perhaps redundant instructions, but code that actually
    behaves incorrectly.

    > But when leaving the ARM world, it isn't even known if the bits will
    > be allocated low-to-high or high-to-low, so switching between two
    > different compilers but staying with the same processor can
    > completely break everything.

    Possibly. It all depends on what degree of protability I need. I don't
    expect to find e.g. ARMv6/v7 page table descriptors in other
    architectures. It is perhaps a choice whether I prefer using the
    "traditional" approach with macros/enums/bit-ops everywhere or
    whether I would rather have an architecture specific header file with
    appropriate bit-field definitions.

    I don't claim that bit fields are always the better approach, but it
    seems that many people show some knee-jerk reactions against bit
    fields wherever the question comes up.

    There are valid arguments against using bit fields in certain
    situations. But most arguments thrown out by people can be disproved
    easily.

    Regards
    Marcus
    http://www.doulos.com/arm/

Children
  • "I would still like to see a self contained minimal example, and preferably an example of a device (ideally ARM based) which exibits the difference behavior that you are trying to show. And I am not talking about a handful of perhaps redundant instructions, but code that actually
    behaves incorrectly."

    you will find, as many others have, that Per is an expert on irrelevancy and s/he will talk about anything but.

    Put my words down: Per will NOT produce such an example in the next 10 posts of his.