Menu

#604 Alignment for pdk

None
open
nobody
None
5
2024-01-12
2019-03-13
No

Padauk devices have some instructions (idxm, ldtabl, ldtabh, stt, ldt, pushw, popw , igoto, icall) operating on 16-bit values that require their operands to be aligned to 16 bits.
In some cases use of these instruction would help reduce register pressure.

SDCC should try to align 16-bit values (int, generic pointers, etc) on 16-bit boundaries, and make alignment information available to code genration to be able to use those instructions better.
There is a trade-off here, and I'd suggest not to make this a struct alignment requirement - requiring padding in structs would waste too much memory.
So we would just align to 16-bits any variable that has size that is a multiple of 16 bits. This way we would not waste any RAM on gaps. This could be implemented by having a separate segment for aligned variables, that placed before the "normal" DATA segment.

What about the overlay? Order variables in the overlay, so that 16-bit stuff is first, followed by the rest?

So the idea to not waste even a single byte, but still get good alignment would be:

PREG (16 bits, at address 0)
DATA16 (multiple of 16 bits, holds all non-overlay stuff that should be aligned)
OVR (within OVR: 16-bit-aigned stuff first)
DATA (anything else)

For some uses of pushw / popw, we'd also need alignment on the stack, which our Chaitin-style stack allocator is already prepared for to handle, so enabling it shouldn't be much extra effort (but we'd have to check if it is worth it, as it might increase stack memory usage).

Philipp

Related

Feature Requests: #689
Wiki: NGI0-Commons-SDCC

Discussion

  • Philipp Klaus Krause

    • Description has changed:

    Diff:

    --- old
    +++ new
    @@ -2,7 +2,7 @@
     In some cases use of these instruction would help reduce register pressure.
    
     SDCC should try to align 16-bit values (int, generic pointers, etc) on 16-bit boundaries, and make alignment information available to code genration to be able to use those instructions better.
    -Thre is a rade-off here, and I'd suggest not to make this a struct alignmetn requirement - requiring padding in structs would waste too much memory.
    +There is a trade-off here, and I'd suggest not to make this a struct alignment requirement - requiring padding in structs would waste too much memory.
     So we would just align to 16-bits any variable that has size that is a multiple of 16 bits. This way we would not waste any RAM on gaps. This could be implemented by having a separate segment for aligned variables, that placed before the "normal" DATA segment.
    
     What about the overlay? Order variables in the overlay, so that 16-bit stuff is first, followed by the rest?
    
    • Group: -->
     
  • Philipp Klaus Krause

    Also very useful would be to have a way to explicitly specify word alignment, i.e. support for _Alignas(2) from the ISO C11 standard. This could require padding bytes in structs.

     
  • Sebastian Riedel

    Would _Alignas(n) just emit .bndry n?
    The linker moves an area to an address that satisfies the least common multiple of all .bndry in a relocatable object file. If an area is defined in multiple relocatable object files, each will be placed separately.

     
    • Philipp Klaus Krause

      I guess it is more complicated: We can't just have .bndry n on the DATA area, or so, since then we'll have some 8-bit objects in between, which will mess up the alignment of subsequent objects. Those 8-bit objects would need "padding" (not meant in the C sense) after them. To avoid wasting space for padding, we'd want to have all 2-aligned objects of size multiple of 2 in the area, and other stuff in a different area. But where the user explicitly requests 2-alignment on an object where size is not a multiple of 2, we'd want to use the space at the end for an 8bit object. Doing this perfectly would be a link-time optimization. But maybe we could just create a DATA2 area for objects of even size, and put all global ints there for a start (and also allow the user to put other objects of even size there).

       
  • Basil Hussain

    Basil Hussain - 2024-01-11

    I would like to add my support and encouragement for this feature.

    I am currently writing some code for PDK and am needing to use inline assembly with an stt16 instruction to load a value into the 16-bit timer counter (it's not accessible as a register, only by stt16 and ldt16 special instructions). I'm using a global uint16_t variable as the source value.

    static volatile uint16_t t16_reset_val = 1234; // must be word-aligned
    
    __asm__("stt16 _t16_reset_val\n");
    

    However, the memory location the value is loaded from must be word-aligned, and there is currently no way to explicitly specify this to SDCC. Either you must rely on circumstance that a variable happens to be located at an even address, or indirectly ensure it by making the variable the very first one allocated (so it ends up at 0x2).

    In case it helps anybody, I also experimented with creating and initialising the word-aligned source variable in the inline assembly using a .even directive, like so:

    __asm
        .area DATA
        .even
        0001$:
        .blkw 1
        .area CODE
        mov a, #(0xAABB)
        mov 0001$+0, a
        mov a, #(0xAABB >> 8)
        mov 0001$+1, a
        stt16 0001$
    __endasm;
    

    But I stayed with a global variable and didn't use this approach in the end.

    By the way, I also experimented using .bndry, but I don't think it works properly in SDAS. Instead of making the location an integer multiple of N, it makes it the area base addres plus multiple of N. For example, on PDK, DATA area's base address is 0x2; if I specify .bndry 8 instead of .even in the code above, I end up with an address of 0xA (i.e. 2+8). Same for 16, which gives 0x12. This is obviously not the desired effect, especially in the context of ensuring memory alignment.

    I also think a more general-purpose ability to specify alignment of variables (perhaps via an __align() attribute) on all platforms would be good. A use case would be for platforms that feature DMA controllers with the ability to make word-size transfers that require word-aligned memory source/target addresses. One example being certain STM8L/ATM8AL devices.

     
    • Maarten Brock

      Maarten Brock - 2024-01-12

      AFAIK the .bndry and .even directives work in the assembler, but the linker does not know how to handle them. So .even aligned code may still end up at an odd address.

       
      • Philipp Klaus Krause

        For pdk, we already have PREG that needs to be at address 0, and have a size of 16 bits. So if we place DATA16 immediately after PREG, the DATA16 area would be at an even address, and all .even directives inside it should align to 16 bits (assuming nothing goes wrong when the linker combines DATA16 from multiple files).

        P.S.: Would it be sufficient to put an .even at the end of DATA16 in each file to ensure that all the DATA16 parts from different files all start at an even address, and thus .even would work inside them as expected?

         

        Last edit: Philipp Klaus Krause 2024-01-12
        • Maarten Brock

          Maarten Brock - 2024-01-12

          It looks like a .even directive at the end will indeed insert space to make sure it actually ends at an even address.

                  .area DATA16
                  .even
          tstvar: .db 7,8,9
                  .even
          

          results in this REL:

          A DATA16 size 4 flags 0 addr 0
          T 00 00 00
          R 00 00 01 00
          T 00 00 00 07 08 09
          R 00 00 01 00
          T 04 00 00
          R 00 00 01 00
          
           
      • Basil Hussain

        Basil Hussain - 2024-01-12

        I suppose that makes sense. The assembler may be setting the current address according to the directive as far as it knows, but then at linking time the area offset is applied and screws things up.

        The current ASxxxx documentation claims that boundary specifications are preserved at linking time. But when looking at the ASxxxx changelog, I see the following note:

        Completed the functionality for propagating the boundary specifications .odd, .even, and .bndry processed during assembly to the linker.

        So it seems it didn't always do that, and the previous behaviour is what is currently in SDAS. But that ASxxxx change was in v5.2 from January 2017, quite some time ago. Am I mis-remembering, or didn't SDAS sometime in the last few years get features ported across to gain parity with upstream?

         

Log in to post a comment.

MongoDB Logo MongoDB