------------------------------------------------------------------------------ -- -- -- GNAT RUN-TIME COMPONENTS -- -- -- -- S Y S T E M . B I T F I E L D _ U T I L S -- -- -- -- S p e c -- -- -- -- Copyright (C) 2019-2024, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ package System.Bitfield_Utils is -- This package provides a procedure for copying arbitrarily large and -- arbitrarily bit-aligned bit fields. -- Type Val is used to represent small bit fields. Val_2 represents a -- contiguous pair of Vals. Val_2'Alignment is half of its size in bytes, -- which is likely not the natural alignment. This is done to ensure that -- any bit field that fits in a Val can fit in an aligned Val_2, starting -- somewhere in the first half, and possibly crossing over into the second -- half. This allows us to isolate a Val value by shifting and masking the -- Val_2. -- -- Val can be 8, 16, or 32 bits; larger values are more efficient. It can't -- be 64 bits, because we need Val_2 to be a double-wide shiftable type, -- and 128 bits is not supported. Instantiating with an 8-bit Val is useful -- for testing and debugging; 32 bits should be used for production. -- -- We use modular types here, not because we want modular arithmetic, but -- so we can do shifting and masking. The actual for Val_2 should have -- pragma Provide_Shift_Operators, so that the Shift_Left and Shift_Right -- intrinsics can be passed in. It is impossible to put that pragma on a -- generic formal, or on a type derived from a generic formal, so they have -- to be passed in. -- -- Endian indicates whether we're on a little- or big-endian machine. pragma Elaborate_Body; Little : constant Bit_Order := Low_Order_First; Big : constant Bit_Order := High_Order_First; generic type Val is mod <>; type Val_2 is mod <>; with function Shift_Left (Value : Val_2; Amount : Natural) return Val_2 is <>; with function Shift_Right (Value : Val_2; Amount : Natural) return Val_2 is <>; Endian : Bit_Order := Default_Bit_Order; package G is -- Assert that Val has one of the allowed sizes, and that Val_2 is twice -- that. pragma Assert (Val'Size in 8 | 16 | 32); pragma Assert (Val_2'Size = Val'Size * 2); -- Assert that both are aligned the same, to the size in bytes of Val -- (not Val_2). pragma Assert (Val'Alignment = Val'Size / Storage_Unit); pragma Assert (Val_2'Alignment = Val'Alignment); type Val_Array is array (Positive range <>) of Val; -- It might make more sense to have: -- subtype Val is Val_2 range 0 .. 2**Val'Size - 1; -- But then GNAT gets the component size of Val_Array wrong. pragma Assert (Val_Array'Alignment = Val'Alignment); pragma Assert (Val_Array'Component_Size = Val'Size); subtype Bit_Size is Natural; -- Size in bits of a bit field subtype Small_Size is Bit_Size range 1 .. Val'Size; -- Size of a small one subtype Bit_Offset is Small_Size'Base range 0 .. Val'Size - 1; -- Starting offset subtype Bit_Offset_In_Byte is Bit_Offset range 0 .. Storage_Unit - 1; procedure Copy_Bitfield (Src_Address : Address; Src_Offset : Bit_Offset_In_Byte; Dest_Address : Address; Dest_Offset : Bit_Offset_In_Byte; Size : Bit_Size); -- An Address and a Bit_Offset together form a "bit address". This -- copies the source bit field to the destination. Size is the size in -- bits of the bit field. The bit fields can be arbitrarily large, but -- the starting offsets must be within the first byte that the Addresses -- point to. The Address values need not be aligned. -- -- For example, a slice assignment of a packed bit field: -- -- D (D_First .. D_Last) := S (S_First .. S_Last); -- -- can be implemented using: -- -- Copy_Bitfield -- (S (S_First)'Address, S (S_First)'Bit, -- D (D_First)'Address, D (D_First)'Bit, -- Size); function Fast_Copy_Bitfield (Src : Val_2; Src_Offset : Bit_Offset; Dest : Val_2; Dest_Offset : Bit_Offset; Size : Small_Size) return Val_2 with Inline; -- Faster version of Copy_Bitfield, with a different calling convention. -- In particular, we pass by copy rather than passing Addresses. The bit -- field must fit in Val_Bits. Src and Dest must be properly aligned. -- The result is supposed to be assigned back into Dest, as in: -- -- Dest := Fast_Copy_Bitfield (Src, ..., Dest, ..., ...); end G; end System.Bitfield_Utils;