From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 X-Received: by 2002:a37:a5d1:: with SMTP id o200mr2073450qke.93.1562317061654; Fri, 05 Jul 2019 01:57:41 -0700 (PDT) X-Received: by 2002:a9d:1b21:: with SMTP id l30mr2064433otl.5.1562317061313; Fri, 05 Jul 2019 01:57:41 -0700 (PDT) Path: eternal-september.org!reader01.eternal-september.org!feeder.eternal-september.org!news.dns-netz.com!news.freedyn.net!newsreader4.netcologne.de!news.netcologne.de!peer01.ams1!peer.ams1.xlned.com!news.xlned.com!peer01.am4!peer.am4.highwinds-media.com!peer02.iad!feed-me.highwinds-media.com!news.highwinds-media.com!m24no8638331qtm.0!news-out.google.com!g23ni228qtq.1!nntp.google.com!m24no8638326qtm.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Fri, 5 Jul 2019 01:57:41 -0700 (PDT) Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=85.204.137.153; posting-account=9DmjiwoAAAD-KD7MAll0qPzDsSqXm2Qs NNTP-Posting-Host: 85.204.137.153 User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: Subject: Odd AVR-Ada code generation issue with constant record type From: Per Jakobsen Injection-Date: Fri, 05 Jul 2019 08:57:41 +0000 Content-Type: text/plain; charset="UTF-8" X-Received-Bytes: 5770 X-Received-Body-CRC: 826288153 Xref: reader01.eternal-september.org comp.lang.ada:56817 Date: 2019-07-05T01:57:41-07:00 List-Id: I'm trying to demonstrate some of Ada's strengths with regard to low-level programming, and ran into the following issue: Having a byte-record consisting of bit-fields of different types (typical microcontroller register definitions). Compiling the below Ada code using avr-ada 1.2.2 (avr-gnat 4.9.3) gives some odd assembly code. Summary: All assignments is really constants that ought to be calculated in full at compile time. 1) Clearing all bitfields in the byte as one assignment, it loads, clears and stores for each field even though the result is constant. *Very* inefficient and even dangerous if the bitfields are assumed to be set atomically!!! 2) Setting one field (any), a calculated byte constant is stored directly. 3) Setting more than one field, a calculated byte constant is initialized in SRAM and used during execution. Inefficient. 4) Clearing a non-composite byte is done directly. 5) Setting a non-composite byte is done directly. Is there an option or pragma I need to set, or is this something more fundamental with the compiler? Code: ------------------------------------ ### main.adb, compiled with Makefile and build.gpr from uart_echo in avr-ada package. with AVR; with System; with Interfaces; procedure Main is use AVR; use Interfaces; type Enum_Type is (B00, B01, B10, B11); for Enum_Type use (B00 => 0, B01 => 1, B10 => 2, B11 => 3); type List_Type is array (0 .. 4) of Boolean with Pack; type Reg_Type is record Enum : Enum_Type; Bool : Boolean; List : List_Type; end record; for Reg_Type use record Enum at 0 range 6 .. 7; Bool at 0 range 5 .. 5; List at 0 range 0 .. 4; end record; for Reg_Type'Size use 8; -- Reg_A -- Reg_A : Reg_Type; for Reg_A'Address use System.Address (16#7a#); pragma Volatile (Reg_A); -- Reg_B -- Reg_B : Reg_Type; for Reg_B'Address use System.Address (16#7b#); pragma Volatile (Reg_B); -- Reg_C -- Reg_C : Reg_Type; for Reg_C'Address use System.Address (16#7c#); pragma Volatile (Reg_C); -- Reg_D -- Reg_D : Unsigned_8; for Reg_D'Address use System.Address (16#7d#); pragma Volatile (Reg_D); -- Reg_E -- Reg_E : Unsigned_8; for Reg_E'Address use System.Address (16#7e#); pragma Volatile (Reg_E); begin -- Set composite with resulting zero-byte. Reg_A := (Enum => B00, Bool => False, List => (others => False)); -- Generated assembly: -- ldi r30, 0x7A ; Set address of register -- ldi r31, 0x00 -- ld r24, Z ; Load -- andi r24, 0xE0 ; Clear List. -- st Z, r24 ; Store -- ld r18, Z ; Load -- andi r18, 0xDF ; Clear Bool. -- st Z, r18 ; Store -- ld r19, Z ; Load -- andi r19, 0x3F ; Clear Enum. -- st Z, r19 ; Store -- Result : 22 bytes code, 0 bytes SRAM, 17 cycles -- Optimal: 4 bytes code, 0 bytes SRAM, 2 cycles -- Set composite with resulting non-zero-byte (any one field is set, others zero). Reg_B := (Enum => B00, Bool => True, List => (others => False)); -- Generated assembly: -- ldi r20, 0x20 ; Set register bits -- sts 0x007B, r20 ; Store -- Result: 6 bytes code, 0 bytes SRAM, 3 cycles -- Is optimal! -- Set composite with resulting non-zero-byte (multiple fields is set). Reg_C := (Enum => B11, Bool => True, List => (others => True)); -- Generated assembly: -- lds r21, 0x0100 ; Load pre-initialized SRAM-stored constant. -- sts 0x007C, r21 ; Store -- Result : 8 bytes code, 1 bytes SRAM, 4 cycles, requires initialization. -- Optimal: 6 bytes code, 0 bytes SRAM, 3 cycles, no initialization. -- Clear Unsigned_8 directly. Reg_D := 16#00#; -- Generated assembly: -- sts 0x007D, r1 ; Store with "reserved" zero-register. -- Result: 4 bytes code, 0 bytes SRAM, 2 cycles -- Is optimal! -- Setting Unsigned_8 directly. Reg_E := 16#FF#; -- Generated assembly: -- ldi r22, 0xFF ; Load constant. -- sts 0x007E, r22 ; Store -- Result: 6 bytes code, 0 bytes SRAM, 3 cycles -- Is optimal! end Main;