* Does Ada support endiannes? @ 2011-12-12 8:57 Gerd 2011-12-12 9:23 ` Niklas Holsti 2011-12-12 11:27 ` Dmitry A. Kazakov 0 siblings, 2 replies; 30+ messages in thread From: Gerd @ 2011-12-12 8:57 UTC (permalink / raw) Hello, a while ago, I worked at Siemens company, with a (CHILL-)compiler that supports endianess similar to this: litte : Integer; pragma Datalayout(Little_Endian); big : Integer; pragma Dtalayout(Big_Endian); little := big; -- compiler generates code for converting big endian to little endian if little = big -- compiler converts the variables to machines nativ format before testing Is there something similar available with Ada? Or has someone any suggestions how to rewrite it in ada? Regards, Gerd ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 8:57 Does Ada support endiannes? Gerd @ 2011-12-12 9:23 ` Niklas Holsti 2011-12-12 11:27 ` Dmitry A. Kazakov 1 sibling, 0 replies; 30+ messages in thread From: Niklas Holsti @ 2011-12-12 9:23 UTC (permalink / raw) On 11-12-12 10:57 , Gerd wrote: > Hello, > > a while ago, I worked at Siemens company, with a (CHILL-)compiler that > supports endianess similar to this: > > litte : Integer; pragma Datalayout(Little_Endian); > big : Integer; pragma Dtalayout(Big_Endian); > > little := big; -- compiler generates code for converting big endian to > little endian > > if little = big -- compiler converts the variables to machines nativ > format before testing > > > Is there something similar available with Ada? No. > Or has someone any suggestions how to rewrite it in ada? Assuming that the native format is big-endian, you could define a new type: type Little_Endian_Integer is record ... end record; and write representation specifications to lay out the components of the type in a little-endian way. But you would then have write your own implementations of all arithmetic operations on Little_Endian_Integer, for example the "+" operator, including forms that mix types, for example for Integer + Little_Endian_Integer. In practice, it would be much easier to write only two conversion functions, to convert to and from the non-native endianness, and call those functions only at the start and end of a computation to load and store the variables that use the non-native endianness. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 8:57 Does Ada support endiannes? Gerd 2011-12-12 9:23 ` Niklas Holsti @ 2011-12-12 11:27 ` Dmitry A. Kazakov 2011-12-12 12:44 ` Gerd 2011-12-12 12:46 ` Gerd 1 sibling, 2 replies; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-12 11:27 UTC (permalink / raw) On Mon, 12 Dec 2011 00:57:32 -0800 (PST), Gerd wrote: > a while ago, I worked at Siemens company, with a (CHILL-)compiler that > supports endianess similar to this: > > litte : Integer; pragma Datalayout(Little_Endian); > big : Integer; pragma Dtalayout(Big_Endian); > > little := big; -- compiler generates code for converting big endian to > little endian > > if little = big -- compiler converts the variables to machines nativ > format before testing > > > Is there something similar available with Ada? Or has someone any > suggestions how to rewrite it in ada? You simply convert all inputs when reading them and keep everything in the native format. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 11:27 ` Dmitry A. Kazakov @ 2011-12-12 12:44 ` Gerd 2011-12-12 19:23 ` Jeffrey Carter 2011-12-13 14:19 ` Gautier write-only 2011-12-12 12:46 ` Gerd 1 sibling, 2 replies; 30+ messages in thread From: Gerd @ 2011-12-12 12:44 UTC (permalink / raw) On 12 Dez., 12:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote: Any suggestion on how to convert, others that "/" and "mod"? ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 12:44 ` Gerd @ 2011-12-12 19:23 ` Jeffrey Carter 2011-12-13 14:25 ` Gerd 2011-12-13 14:19 ` Gautier write-only 1 sibling, 1 reply; 30+ messages in thread From: Jeffrey Carter @ 2011-12-12 19:23 UTC (permalink / raw) On 12/12/2011 05:44 AM, Gerd wrote: > > Any suggestion on how to convert, others that "/" and "mod"? Let's presume you're on a little-ending machine. Then you can write something like type Byte is mod 2 ** 8; for Byte'Size use 8; type Native is record MSB : Byte; MSB_1 : Byte; LSB_1 : Byte; LSB : Byte; end record; for Native use record MSB at 3 range 0 .. 7; MSB_1 at 2 range 0 .. 7; LSB_1 at 1 range 0 .. 7; LSB at 0 range 0 .. 7; end record; for Native'Size use 32; function From_Native is new Ada.Unchecked_Conversion (Source => Native, Target => Interfaces.Integer_32); function To_Native is new Ada.Unchecked_Conversion (Source => Interfaces.Integer_32, Target => Native); type Foreign is new Native; for Foreign use record MSB at 0 range 0 .. 7; MSB_1 at 1 range 0 .. 7; LSB_1 at 2 range 0 .. 7; LSB at 3 range 0 .. 7; end record; for Foreign'Size use 32; function From_Foreign is new Ada.Unchecked_Conversion (Source => Foreign, Target => Interfaces.Integer_32); function To_Foreign is new Ada.Unchecked_Conversion (Source => Interfaces.Integer_32, Target => Foreign); Now, if you have something in big-endian format in Value, you can convert it to little-ending by From_Native (Native (To_Foreign (Value) ) ) which you would probably want to encapsulate function Foreign_To_Native (Value : in Interfaces.Integer_32) return Interfaces.Integer_32 is -- null; begin -- Foreign_To_Native return From_Native (Native (To_Foreign (Value) ) ); end Foreign_To_Native; You could also read your foreign value byte by byte, putting the bytes into the appropriate fields of a Native, then unchecked-convert that to an integer. -- Jeff Carter "Pray that there's intelligent life somewhere up in space, 'cause there's bugger all down here on earth." Monty Python's Meaning of Life 61 --- Posted via news://freenews.netfront.net/ - Complaints to news@netfront.net --- ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 19:23 ` Jeffrey Carter @ 2011-12-13 14:25 ` Gerd 0 siblings, 0 replies; 30+ messages in thread From: Gerd @ 2011-12-13 14:25 UTC (permalink / raw) On 12 Dez., 20:23, Jeffrey Carter <spam.jrcarter....@spam.not.acm.org> wrote: Jeffrey, this looks like what I was looking for. Thanks. -- Regards, Gerd ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 12:44 ` Gerd 2011-12-12 19:23 ` Jeffrey Carter @ 2011-12-13 14:19 ` Gautier write-only 2011-12-14 16:16 ` Gerd 1 sibling, 1 reply; 30+ messages in thread From: Gautier write-only @ 2011-12-13 14:19 UTC (permalink / raw) On 12 déc, 13:44, Gerd <Gerd...@t-online.de> wrote: > Any suggestion on how to convert, others that "/" and "mod"? If you use "/" and "mod" (or "shift"'s and "and"'s to go faster) and use endianess only for I/O, you'll have perfectly portable solution on a wide range of compilers and operating systems. See this: http://unzip-ada.sf.net/ for an example. HTH _________________________ Gautier's Ada programming http://gautiersblog.blogspot.com/search/label/Ada NB: follow the above link for a valid e-mail address ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-13 14:19 ` Gautier write-only @ 2011-12-14 16:16 ` Gerd 2011-12-14 18:16 ` Dmitry A. Kazakov 2011-12-14 20:16 ` Gautier write-only 0 siblings, 2 replies; 30+ messages in thread From: Gerd @ 2011-12-14 16:16 UTC (permalink / raw) On 13 Dez., 15:19, Gautier write-only <gautier_niou...@hotmail.com> wrote: Are you sure the "/" and mod would work correct? Assume, that the Value 16#000000FF# shall be converted to 16#FF000000#. Native : Integer := 16#000000FF#; Remote : Integer; Remote := 16#01000000# * ()Native mod 16#000000FF#); -- overflow! -- Gerd PS: The task is to exchange Integer Values between an Motorola 68k and an Intel x86. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-14 16:16 ` Gerd @ 2011-12-14 18:16 ` Dmitry A. Kazakov 2011-12-14 20:16 ` Gautier write-only 1 sibling, 0 replies; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-14 18:16 UTC (permalink / raw) On Wed, 14 Dec 2011 08:16:02 -0800 (PST), Gerd wrote: > On 13 Dez., 15:19, Gautier write-only <gautier_niou...@hotmail.com> > wrote: > > Are you sure the "/" and mod would work correct? Always. Arithmetic is complete in the sense that any possible function can be implemented using these operations. > Assume, that the Value 16#000000FF# shall be converted to > 16#FF000000# > > Native : Integer := 16#000000FF#; > > Remote : Integer; > > Remote := 16#01000000# * ()Native mod 16#000000FF#); -- overflow! Either it is not Integer (e.g. Unsigned_32) or else overflow is not an error but a legal outcome indicating protocol error, for example. The decision depends on the application. Note that if you used a representation clause and/or Unchecked_Conversion, you would have to use X'Valid attribute in order to check obtained value for being an integer. For all cases where arithmetic would raise Constraint_Error, X'Value should yield false, which is not guaranteed of course. This is another reason why not to use representation clauses, because some illegal representation might get misinterpreted as proper values. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-14 16:16 ` Gerd 2011-12-14 18:16 ` Dmitry A. Kazakov @ 2011-12-14 20:16 ` Gautier write-only 2011-12-15 11:27 ` Gerd 1 sibling, 1 reply; 30+ messages in thread From: Gautier write-only @ 2011-12-14 20:16 UTC (permalink / raw) On 14 déc, 17:16, Gerd <Gerd...@t-online.de> wrote: > Are you sure the "/" and mod would work correct? > > Assume, that the Value 16#000000FF# shall be converted to > 16#FF000000#. > > Native : Integer := 16#000000FF#; > > Remote : Integer; > > Remote := 16#01000000# * ()Native mod 16#000000FF#); -- overflow! > > PS: The task is to exchange Integer Values between an Motorola 68k and > an Intel x86. Then you will use modular types, and with a definite size. Native: Unsigned_32; Remote: Unsigned_32; They never overflow. But typically (as you can see in Zip-Ada [1]) you won't presume anything about the native endianness. The "/" and "mod" (or faster: "Shift_Right" and "and") will do the job automatically for you. So your code will work on Intel, PowerPC, 68K - whatever - and communicate with a remote hardware or media with a specific endianness. [1] http://unzip-ada.sf.net/za_html/zip-headers__adb.htm#32_12 _________________________ Gautier's Ada programming http://gautiersblog.blogspot.com/search/label/Ada NB: follow the above link for a valid e-mail address ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-14 20:16 ` Gautier write-only @ 2011-12-15 11:27 ` Gerd 2011-12-15 13:01 ` Simon Wright ` (2 more replies) 0 siblings, 3 replies; 30+ messages in thread From: Gerd @ 2011-12-15 11:27 UTC (permalink / raw) On 14 Dez., 21:16, Gautier write-only <gautier_niou...@hotmail.com> wrote: The problem space requires integers (signed), so using unsigned is not the right option. Could you please explain: What do you think how the data send from 68k to x86 will be converted from one data layout to the other? Will it happen "magically" on the wire? I think, conversion must be done explicit either on one side or on the other side, and this requires some code. Currently I use the htonl ntohl functions for it, which (as stated above) is not a good choice as it limits the allowed values to unsigned. > On 14 déc, 17:16, Gerd <Gerd...@t-online.de> wrote: > > > Are you sure the "/" and mod would work correct? > > > Assume, that the Value 16#000000FF# shall be converted to > > 16#FF000000#. > > > Native : Integer := 16#000000FF#; > > > Remote : Integer; > > > Remote := 16#01000000# * (Native mod 16#000000FF#); -- overflow! > > > PS: The task is to exchange Integer Values between an Motorola 68k and > > an Intel x86. > > Then you will use modular types, and with a definite size. > Native: Unsigned_32; > Remote: Unsigned_32; > They never overflow. > But typically (as you can see in Zip-Ada [1]) you won't presume > anything about the native endianness. > The "/" and "mod" (or faster: "Shift_Right" and "and") will do the job > automatically for you. > So your code will work on Intel, PowerPC, 68K - whatever - and > communicate with a remote hardware or media with a specific > endianness. > > [1]http://unzip-ada.sf.net/za_html/zip-headers__adb.htm#32_12 > _________________________ > Gautier's Ada programminghttp://gautiersblog.blogspot.com/search/label/Ada > NB: follow the above link for a valid e-mail address ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-15 11:27 ` Gerd @ 2011-12-15 13:01 ` Simon Wright 2011-12-15 13:37 ` Dmitry A. Kazakov 2011-12-15 20:12 ` Jeffrey Carter 2 siblings, 0 replies; 30+ messages in thread From: Simon Wright @ 2011-12-15 13:01 UTC (permalink / raw) Gerd <GerdM.O@t-online.de> writes: > The problem space requires integers (signed), so using unsigned is not > the right option. > > Could you please explain: What do you think how the data send from 68k > to x86 will be converted from one data layout to the other? Will it > happen "magically" on the wire? I think, conversion must be done > explicit either on one side or on the other side, and this requires > some code. > > Currently I use the htonl ntohl functions for it, which (as stated > above) is not a good choice as it limits the allowed values to > unsigned. Some code I wrote -- not quite the same problem -- which handles 8-byte signed quantities and conversion to/from wire format, and works just fine on i386, x86_64, powerpc, is type SNTP_Timestamp is delta 2.0 ** (-32) range -2.0 ** 31 .. 2.0 ** 31; for SNTP_Timestamp'Size use 64; subtype Timestamp_Slice is Ada.Streams.Stream_Element_Array (1 .. 8); function To_Timestamp_Slice (T : SNTP_Timestamp) return Timestamp_Slice is function Convert is new Ada.Unchecked_Conversion (SNTP_Timestamp, Timestamp_Slice); Tmp : constant Timestamp_Slice := Convert (T); begin if Big_Endian then return Tmp; else return (1 => Tmp (8), 2 => Tmp (7), 3 => Tmp (6), 4 => Tmp (5), 5 => Tmp (4), 6 => Tmp (3), 7 => Tmp (2), 8 => Tmp (1)); end if; end To_Timestamp_Slice; function To_SNTP_Timestamp (T : Timestamp_Slice) return SNTP_Timestamp is function Convert is new Ada.Unchecked_Conversion (Timestamp_Slice, SNTP_Timestamp); begin if Big_Endian then return Convert (T); else return Convert ((1 => T (8), 2 => T (7), 3 => T (6), 4 => T (5), 5 => T (4), 6 => T (3), 7 => T (2), 8 => T (1))); end if; end To_SNTP_Timestamp; No real possibility of validation of this data type at the conversion level, of course. I think the chance of using wierd machines where this doesn't work is pretty low. And don't forget you can come a cropper because of compiler changes: previous to Ada 2005, GNAT's representation of Ada.Calendar.Time used the Unix epoch, so a conversion based on that seemed a pretty safe bet. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-15 11:27 ` Gerd 2011-12-15 13:01 ` Simon Wright @ 2011-12-15 13:37 ` Dmitry A. Kazakov 2011-12-15 20:12 ` Jeffrey Carter 2 siblings, 0 replies; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-15 13:37 UTC (permalink / raw) On Thu, 15 Dec 2011 03:27:48 -0800 (PST), Gerd wrote: > Could you please explain: What do you think how the data send from 68k > to x86 will be converted from one data layout to the other? Assuming 68k is big endian, two's complement: type Octet is new Unsigned_8; function From_Motorola (First, Second : Octet) return Integer_16 is begin if First > 127 then return -1 - Integer_16 (not First) * 256 - Integer_16 (not Second); else return Integer_16 (First) * 256 + Integer_16 (Second); end if; end From_Motorola; Note that the code is target machine's endianness agnostic. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-15 11:27 ` Gerd 2011-12-15 13:01 ` Simon Wright 2011-12-15 13:37 ` Dmitry A. Kazakov @ 2011-12-15 20:12 ` Jeffrey Carter 2 siblings, 0 replies; 30+ messages in thread From: Jeffrey Carter @ 2011-12-15 20:12 UTC (permalink / raw) On 12/15/2011 04:27 AM, Gerd wrote: > > The problem space requires integers (signed), so using unsigned is not > the right option. What you're talking about is not values, but bit patterns. Until you get the bit pattern correct, you can't think about the value. In Ada, bit patterns are represented by modular integers, packed arrays of Boolean, or records with representation clauses. Once you have the bit pattern correct, you use Unchecked_Conversion to interpret the bit pattern as a value of the desired type (signed integer in this case). It depends on how you're getting the bytes that hold the bit pattern in question. If you're getting individual bytes, from the network for example, then you can stick those bytes in the appropriate parts of a structure of the right size (array of 4 bytes or record containing 4 1-byte components) and unchecked-convert that into your target type. If for some reason you're starting with signed integer values with the bytes scrambled, then you need to uncheck-convert that to get at the bit pattern, do the byte swapping, and uncheck-convert the result back to the target type. In this case, the automatic conversion between derived types with different representations I outlined earlier does the byte swapping for you. Of course, you can always unchecked-convert to a bit pattern representation and do the byte swapping yourself. -- Jeff Carter "I would never want to belong to any club that would have someone like me for a member." Annie Hall 41 --- Posted via news://freenews.netfront.net/ - Complaints to news@netfront.net --- ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 11:27 ` Dmitry A. Kazakov 2011-12-12 12:44 ` Gerd @ 2011-12-12 12:46 ` Gerd 2011-12-12 13:22 ` Dmitry A. Kazakov 2011-12-12 13:33 ` Robert A Duff 1 sibling, 2 replies; 30+ messages in thread From: Gerd @ 2011-12-12 12:46 UTC (permalink / raw) On 12 Dez., 12:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote: Any suggestion on how to convert, others than using "/" and "mod"? ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 12:46 ` Gerd @ 2011-12-12 13:22 ` Dmitry A. Kazakov 2011-12-12 17:07 ` Charles H. Sampson 2011-12-12 13:33 ` Robert A Duff 1 sibling, 1 reply; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-12 13:22 UTC (permalink / raw) On Mon, 12 Dec 2011 04:46:22 -0800 (PST), Gerd wrote: > On 12 Dez., 12:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> > wrote: > > Any suggestion on how to convert, others than using "/" and "mod"? Why not to use them? It would be a bad idea trying to avoid them. It won't give you much performance, because memory mapping would require unpacking, alignment, checksum evaluation, stuff which would turn into extra copying. So why not just: type Octet is new Unsigned_8; type Word is new Unsigned_16; type Octet_Array is array (Positive range <>) of Octet; procedure Get_Little_Endian (Data : Octet_Array; Index : in out Integer; Value : out Word) is -- No extra copying begin Value := Word (Data (Index)) + Word (Data (Index + 1)) * 256; Index := Index + 2; end Get_Little_Endian; Arithmetic is cheap. Memory access is expensive. Note also, that a real-life protocol could also have specially encoded values reserved for indication of status (overflow, underflow etc). So memory mapping would not work anyway. P.S. We are developing hard real-time communication applications handling various quite weird hardware protocols. Believe or not, we are using no representation clauses at all. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 13:22 ` Dmitry A. Kazakov @ 2011-12-12 17:07 ` Charles H. Sampson 2011-12-12 18:33 ` Dmitry A. Kazakov 0 siblings, 1 reply; 30+ messages in thread From: Charles H. Sampson @ 2011-12-12 17:07 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Mon, 12 Dec 2011 04:46:22 -0800 (PST), Gerd wrote: > > > On 12 Dez., 12:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> > > wrote: > > > > Any suggestion on how to convert, others than using "/" and "mod"? > > Why not to use them? It would be a bad idea trying to avoid them. > > It won't give you much performance, because memory mapping would require > unpacking, alignment, checksum evaluation, stuff which would turn into > extra copying. So why not just: > > type Octet is new Unsigned_8; > type Word is new Unsigned_16; > type Octet_Array is array (Positive range <>) of Octet; > > procedure Get_Little_Endian (Data : Octet_Array; Index : in out Integer; > Value : out Word) is -- No extra copying > begin > Value := Word (Data (Index)) + Word (Data (Index + 1)) * 256; > Index := Index + 2; > end Get_Little_Endian; > > ... Don't you think this approach obscures what's going on, Dmitry, thereby negating one of the design goals of Ada? Sure, most of us who have bit-twiddled in the bad old days can figure out what's going on, or at least convince ourselves that we've figured out what's going on, but I much prefer the clarity of something like type Single_Precision is -- old IBM single-precision record Negative : Boolean; Characteristic : Seven_Bit_Integer; Mantissa : Twenty_Four_Bit_Fixed_Point; end record; A_Variable : Single_Precision; ... A_Variable := ( Negative => ... Characteristic => ... Mantissa => ...); LIke you, I've worked on a hard real-time system that had to interface with hardware having a lot of different protocols and interfaces. My experience was that worries about code efficiency were more apparent than real. Charlie P. S. Please forgive any errors in the syntax of my example. I don't have a compiler available to check them with. P. P. S. I don't advocate the style of the above assignment statement. I used the first newline only to retain control of the column alignment. In a reasonable development system, I'd let the editor handle that for me. -- [A certain TV newsreader] had a role to play: presenter of the Other Side of the Argument, to whom fair-minded people were obligated to pay heed, no matter what nonsense he spouted. Charlie Pierce, Idiot America ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 17:07 ` Charles H. Sampson @ 2011-12-12 18:33 ` Dmitry A. Kazakov 2011-12-14 5:19 ` Charles H. Sampson 0 siblings, 1 reply; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-12 18:33 UTC (permalink / raw) On Mon, 12 Dec 2011 09:07:24 -0800, Charles H. Sampson wrote: > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > >> On Mon, 12 Dec 2011 04:46:22 -0800 (PST), Gerd wrote: >> >>> On 12 Dez., 12:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> >>> wrote: >>> >>> Any suggestion on how to convert, others than using "/" and "mod"? >> >> Why not to use them? It would be a bad idea trying to avoid them. >> >> It won't give you much performance, because memory mapping would require >> unpacking, alignment, checksum evaluation, stuff which would turn into >> extra copying. So why not just: >> >> type Octet is new Unsigned_8; >> type Word is new Unsigned_16; >> type Octet_Array is array (Positive range <>) of Octet; >> >> procedure Get_Little_Endian (Data : Octet_Array; Index : in out Integer; >> Value : out Word) is -- No extra copying >> begin >> Value := Word (Data (Index)) + Word (Data (Index + 1)) * 256; >> Index := Index + 2; >> end Get_Little_Endian; >> >> ... > > Don't you think this approach obscures what's going on, Dmitry, > thereby negating one of the design goals of Ada? No. The Ada's design goal was to allow the programmer to describe the semantics the data types involved and to program in that terms. Representation clauses rather defeat that idea than support it. The number read from the wire must look and feel as a number rather than some messy record, which cannot be a numeric parameter of a generic, has no 'Image, no meaningful literals etc... > Sure, most of us who > have bit-twiddled in the bad old days can figure out what's going on, or > at least convince ourselves that we've figured out what's going on, but > I much prefer the clarity of something like > > type Single_Precision is -- old IBM single-precision > record > Negative : Boolean; > Characteristic : Seven_Bit_Integer; > Mantissa : Twenty_Four_Bit_Fixed_Point; > end record; > > A_Variable : Single_Precision; And defining all arithmetic on it? Elementary functions including? I don't remember the IBM layout, but are you sure that you have got the order of fields right? What about the literals? No, I would never do it this way. In a comparable case: http://www.dmitry-kazakov.de/ada/components.htm#IEEE_754 I read IEEE 754 representations into the native floating point rather than messing up with representation clauses, even if the machine is natively IEEE 754. I just don't care. Granted, defining IEEE 754 as a record (Unchecked_Union?), denormalized numbers, NaN, +/-Inf, hidden mantissa bit, must be a HUGE fun! -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 18:33 ` Dmitry A. Kazakov @ 2011-12-14 5:19 ` Charles H. Sampson 2011-12-14 8:56 ` Dmitry A. Kazakov 0 siblings, 1 reply; 30+ messages in thread From: Charles H. Sampson @ 2011-12-14 5:19 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Mon, 12 Dec 2011 09:07:24 -0800, Charles H. Sampson wrote: > > > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > > > >> On Mon, 12 Dec 2011 04:46:22 -0800 (PST), Gerd wrote: > >> > >>> On 12 Dez., 12:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> > >>> wrote: > >>> > >>> Any suggestion on how to convert, others than using "/" and "mod"? > >> > >> Why not to use them? It would be a bad idea trying to avoid them. > >> > >> It won't give you much performance, because memory mapping would require > >> unpacking, alignment, checksum evaluation, stuff which would turn into > >> extra copying. So why not just: > >> > >> type Octet is new Unsigned_8; > >> type Word is new Unsigned_16; > >> type Octet_Array is array (Positive range <>) of Octet; > >> > >> procedure Get_Little_Endian (Data : Octet_Array; Index : in out Integer; > >> Value : out Word) is -- No extra copying > >> begin > >> Value := Word (Data (Index)) + Word (Data (Index + 1)) * 256; > >> Index := Index + 2; > >> end Get_Little_Endian; > >> > >> ... > > > > Don't you think this approach obscures what's going on, Dmitry, > > thereby negating one of the design goals of Ada? > > No. The Ada's design goal was to allow the programmer to describe the > semantics the data types involved and to program in that terms. > Representation clauses rather defeat that idea than support it. The number > read from the wire must look and feel as a number rather than some messy > record, which cannot be a numeric parameter of a generic, has no 'Image, no > meaningful literals etc... I think I see the place where we have the greatest disagreement in concept. To me, in general, data coming "over a wire" are just a stream of bits until we have interpreted them and found out what they mean. (The primary, and maybe the only, exception would be a homogenous data stream. No interpretation is required.) So for me, again in general, there is no such idea as reading a number from such data. As a result, I need all sorts of ways of converting bit streams to various internal data types. > > Sure, most of us who > > have bit-twiddled in the bad old days can figure out what's going on, or > > at least convince ourselves that we've figured out what's going on, but > > I much prefer the clarity of something like > > > > type Single_Precision is -- old IBM single-precision > > record > > Negative : Boolean; > > Characteristic : Seven_Bit_Integer; > > Mantissa : Twenty_Four_Bit_Fixed_Point; > > end record; > > > > A_Variable : Single_Precision; > > And defining all arithmetic on it? Elementary functions including? I don't > remember the IBM layout, but are you sure that you have got the order of > fields right? What about the literals? If the a bit stream is interpreted as a target machine native number, then I have to use two views into each variable of that numeric type. One view looks at it as a native number and the other view would show its component structure. All the number's operations and elementary functions are available by using the native number view. These two views are a form of aliasing, which I don't like very much at all. This can be minimized through the use of conversion functions, limiting the aliasing to the body of the functions. There's no execution penalty to this approach because the conversion functions are easily inlined. At that requires a bit mor writing than your approach, Dmitry, but that's o. k. with me. The design of Ada was permitted to require "extra" writing for the purpose of clarity of code. If I'm willing to write voluminous comments to document the source code, and I am, I don't begrudge a few keystroke when writing code itself. I'm 99.97% sure that I have the IBM single-precision layout correct, including the order, but it doesn't matter. In practice I would always use a representation specification. I always use rep specs when I'm defining a type whose bit layout (or encoding, for an enumeration type) has been specified. In the case of an enumeration type I do that even if the specification is the LRM-defined one. My coding style is that a rep spec means that the layout or encoding has been specified somewhere. If it hasn't been, I'm pretty rigorous about letting the compiler choose the representation. > No, I would never do it this way. In a comparable case: > > http://www.dmitry-kazakov.de/ada/components.htm#IEEE_754 > > I read IEEE 754 representations into the native floating point rather than > messing up with representation clauses, even if the machine is natively > IEEE 754. I just don't care. > > Granted, defining IEEE 754 as a record (Unchecked_Union?), denormalized > numbers, NaN, +/-Inf, hidden mantissa bit, must be a HUGE fun! I did it and it wasn't a big deal at all. Charlie -- [A certain TV newsreader] had a role to play: presenter of the Other Side of the Argument, to whom fair-minded people were obligated to pay heed, no matter what nonsense he spouted. Charlie Pierce, Idiot America ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-14 5:19 ` Charles H. Sampson @ 2011-12-14 8:56 ` Dmitry A. Kazakov 2011-12-14 9:46 ` Simon Wright 2011-12-15 9:14 ` Charles H. Sampson 0 siblings, 2 replies; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-14 8:56 UTC (permalink / raw) On Tue, 13 Dec 2011 21:19:07 -0800, Charles H. Sampson wrote: > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > >> No. The Ada's design goal was to allow the programmer to describe the >> semantics the data types involved and to program in that terms. >> Representation clauses rather defeat that idea than support it. The number >> read from the wire must look and feel as a number rather than some messy >> record, which cannot be a numeric parameter of a generic, has no 'Image, no >> meaningful literals etc... > > I think I see the place where we have the greatest disagreement in > concept. To me, in general, data coming "over a wire" are just a stream > of bits until we have interpreted them and found out what they mean. Right, I prefer typed approaches over untyped ones. This is BTW why I prefer Ada over other languages. Stream of bits is a transport layer, at best, to be hidden under higher protocol layers, spilling properly typed objects to the clients. No conversions. One advantage of this approach is that the transport being properly encapsulated could be easily replaced. > At that requires a bit mor writing than your approach, Dmitry, but > that's o. k. with me. The design of Ada was permitted to require > "extra" writing for the purpose of clarity of code. I think the problem here is not the volume of the code, but an untyped nature of it. Note that if the native and remote objects were distinct types (not subtypes), you would not be able to have them as views of the *same* object. Thus you would have to convert the remote object to a native one. But once you had the latter you would not need the former anymore. The next step is just to get rid of it. Why anybody (a client) should see it at all? That is my approach. As a by-product you get a highly portable code as Gautier pointed out in another response. IMO, representation clauses are evil and not Ada (TM). -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-14 8:56 ` Dmitry A. Kazakov @ 2011-12-14 9:46 ` Simon Wright 2011-12-15 9:14 ` Charles H. Sampson 1 sibling, 0 replies; 30+ messages in thread From: Simon Wright @ 2011-12-14 9:46 UTC (permalink / raw) It seems to me that there's violent agreement going on here. The only point of disagreement is how to convert the stream of bits into native, unrepresented, application data. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-14 8:56 ` Dmitry A. Kazakov 2011-12-14 9:46 ` Simon Wright @ 2011-12-15 9:14 ` Charles H. Sampson 2011-12-15 9:46 ` Dmitry A. Kazakov 1 sibling, 1 reply; 30+ messages in thread From: Charles H. Sampson @ 2011-12-15 9:14 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Tue, 13 Dec 2011 21:19:07 -0800, Charles H. Sampson wrote: > > > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > > > >> No. The Ada's design goal was to allow the programmer to describe the > >> semantics the data types involved and to program in that terms. > >> Representation clauses rather defeat that idea than support it. The number > >> read from the wire must look and feel as a number rather than some messy > >> record, which cannot be a numeric parameter of a generic, has no 'Image, no > >> meaningful literals etc... > > > > I think I see the place where we have the greatest disagreement in > > concept. To me, in general, data coming "over a wire" are just a stream > > of bits until we have interpreted them and found out what they mean. > > Right, I prefer typed approaches over untyped ones. This is BTW why I > prefer Ada over other languages. > > Stream of bits is a transport layer, at best, to be hidden under higher > protocol layers, spilling properly typed objects to the clients. No > conversions. One advantage of this approach is that the transport being > properly encapsulated could be easily replaced. Well, yes. You do definitely want to encapsulate all this stuff. Even though the ugly stuff is hidden to from the clients, I still want to make the ugly stuff as pretty and understandable as possible. > > At that requires a bit more writing than your approach, Dmitry, but > > that's o. k. with me. The design of Ada was permitted to require > > "extra" writing for the purpose of clarity of code. > > I think the problem here is not the volume of the code, but an untyped > nature of it. My code gets "typed" as soon as possible, as soon as I can recognize what its type is supposed to be. The reason I wrote _typed_ in quotes is that a stream of bits, where I start, is typed: type Bit is range 0 .. 1; for Bit'Size use 1; type Bit_Stream is array (Positive range <>) of Bit; pragma Pack (Bit_Stream); > Note that if the native and remote objects were distinct types (not > subtypes), you would not be able to have them as views of the *same* > object. Thus you would have to convert the remote object to a native one. > But once you had the latter you would not need the former anymore. The next > step is just to get rid of it. Why anybody (a client) should see it at all? > That is my approach. The only time I need two views of an object when I need to access its components, such as when constructing the object or accessing its components to, for example, construct some other object from them. I absolutely agree that you should get numeric values into a proper native type as soon as possible. This conversion between native and non-native type should be confined to IO time. Sometime the time between the IO and the conversion is longer than you might hope, at least on the input side. Referring again to the last system I worked on, we often had to read part of the input to determine the length of the incoming bit string, then read the rest in, and then begin the checking to determine exactly what we had. > As a by-product you get a highly portable code as Gautier pointed out in > another response. I don't understand this claim of highly portable code without using a rep spec. A rep spec is necessary to insure proper allocation of a record's components. Your earlier questioning of the order of the components in my definition of the type Single_Precision leads me to think that you aren't aware that there is no link between the lexical order of a record type definition and the layout of its components in memory. In other words, a compiler is free to "move components around". They usually do this to achieve an efficient memory layout but they could do in just on a whim of the compiler writer. > IMO, representation clauses are evil and not Ada (TM). IMO, representation clauses are a blessing that allows me to take full control of the representation when I need to. That's one of many reasons why I prefer Ada to any other language I know, to the point that I refuse to program in any other language. (Being past retirement age has certain benefits.) By the way, Dmitry, I hope you understand that by carrying on this dialog I don't intend to imply that you're a idiot who has no idea what he's doing. That's obviously not true. All I'm trying to do is lead you to enlightenment by exposing you to my clearly superior ideas. :-) Charlie -- [A certain TV newsreader] had a role to play: presenter of the Other Side of the Argument, to whom fair-minded people were obligated to pay heed, no matter what nonsense he spouted. Charlie Pierce, Idiot America ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-15 9:14 ` Charles H. Sampson @ 2011-12-15 9:46 ` Dmitry A. Kazakov 2011-12-25 21:42 ` Charles H. Sampson 0 siblings, 1 reply; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-15 9:46 UTC (permalink / raw) On Thu, 15 Dec 2011 01:14:15 -0800, Charles H. Sampson wrote: > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > >> I think the problem here is not the volume of the code, but an untyped >> nature of it. > > My code gets "typed" as soon as possible, as soon as I can > recognize what its type is supposed to be. The reason I wrote _typed_ > in quotes is that a stream of bits, where I start, is typed: > > type Bit is range 0 .. 1; > for Bit'Size use 1; > type Bit_Stream is array (Positive range <>) of Bit; > pragma Pack (Bit_Stream); In order to make this working with representation clause you have to get bits out of this stream and store them into a properly aligned array of Storage_Unit. Doing so, you will have to take into account native storage unit bit endianness, which may differ from the endiannes of the protocol. Furthermore, since almost all protocols are octet-oriented rather than bit-oriented, you will need to decode the protocol's stream of octets into bits and then recode that into an array of storage units to apply a representation clause on that. A rationale for such an exercise is beyond me, but certainly this is not what anybody could call "simple" or "readable." > Sometime the time between the IO and the conversion is longer than > you might hope, at least on the input side. Referring again to the last > system I worked on, we often had to read part of the input to determine > the length of the incoming bit string, then read the rest in, and then > begin the checking to determine exactly what we had. Yes, and this is yet another argument against representation clauses which tend to convert things as a whole. The problem is that protocols are using finer grained elements, that data might be corrupted, not ready as a whole etc. Using representation clauses you will have problems with validating data after conversion. You must ensure that no invalid bit pattern may become a valid value after re-interpretation using a representation clause. When using arithmetic of octets this is done in the course of conversion, almost automatically. With representation clauses you would likely have to add some extra checks before storing the data and after the re-interpretation. >> As a by-product you get a highly portable code as Gautier pointed out in >> another response. > > I don't understand this claim of highly portable code without using > a rep spec. The semantics of a representation clause depends on the native machine bit and storage unit endianness, the size of the storage unit, alignment constraints. The semantics of arithmetic operations and shifts is fully machine-independent. The rule of thumb: representation clauses shall be used exclusively for the machine hardware. This is the only legitimate case for them. > All I'm trying to do is lead > you to enlightenment by exposing you to my clearly superior ideas. :-) (:-)) -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-15 9:46 ` Dmitry A. Kazakov @ 2011-12-25 21:42 ` Charles H. Sampson 2011-12-26 10:47 ` Dmitry A. Kazakov 0 siblings, 1 reply; 30+ messages in thread From: Charles H. Sampson @ 2011-12-25 21:42 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Thu, 15 Dec 2011 01:14:15 -0800, Charles H. Sampson wrote: > > > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > > > >> I think the problem here is not the volume of the code, but an untyped > >> nature of it. > > > > My code gets "typed" as soon as possible, as soon as I can > > recognize what its type is supposed to be. The reason I wrote _typed_ > > in quotes is that a stream of bits, where I start, is typed: > > > > type Bit is range 0 .. 1; > > for Bit'Size use 1; > > type Bit_Stream is array (Positive range <>) of Bit; > > pragma Pack (Bit_Stream); > > In order to make this working with representation clause you have to get > bits out of this stream and store them into a properly aligned array of > Storage_Unit. Doing so, you will have to take into account native storage > unit bit endianness, which may differ from the endiannes of the protocol. > Furthermore, since almost all protocols are octet-oriented rather than > bit-oriented, you will need to decode the protocol's stream of octets into > bits and then recode that into an array of storage units to apply a > representation clause on that. He's baaaaack! Sorry to leave such a time gap in this thread but I had to find time during this busy season to commune with the LRM at bit. > > A rationale for such an exercise is beyond me, but certainly this is not > what anybody could call "simple" or "readable." > > > Sometime the time between the IO and the conversion is longer than > > you might hope, at least on the input side. Referring again to the last > > system I worked on, we often had to read part of the input to determine > > the length of the incoming bit string, then read the rest in, and then > > begin the checking to determine exactly what we had. > > Yes, and this is yet another argument against representation clauses which > tend to convert things as a whole. The problem is that protocols are using > finer grained elements, that data might be corrupted, not ready as a whole > etc. Using representation clauses you will have problems with validating > data after conversion. You must ensure that no invalid bit pattern may > become a valid value after re-interpretation using a representation clause. > When using arithmetic of octets this is done in the course of conversion, > almost automatically. With representation clauses you would likely have to > add some extra checks before storing the data and after the > re-interpretation. I'm not clear on what you mean by "representation clauses ... tend to convert things as a whole". Representation clauses don't convert anything. They just specify how the bits are laid out in memory. It doesn't matter how those bits got there. In the present case, probably a low-level routine was called telling it to place the incoming packet at a certain place in memory. It's only after the bits are in the proper place that any conversion takes place. For example, to change the endianess of a two-byte word, I might write something like Internal_Small_Word := 256 * Incoming.Byte_2 + Byte_1; It's more than likely that I would use a representation clause for Internal_Small_Word also and just do two assignments: Internal_Small_Word.Byte_1 := Incoming.Byte_2; Internal_Small_Word.Byte_2 := Incoming.Byte_1; It won't surprise you when I say that I think the latter is much clearer as to intent and meaning than any arithmetic manipulating, including my former example. Data corruption is handled by whatever mechanism is in the data packets to guard against corruption. In my experience that was usually a pretty simple-minded checksum. Whenever a corrupted packet was detected, all of its data were thrown away. As to checks of incoming data before storing, I usually let Ada do that for me by properly defining the target data type. I remember having to occasionally use 'Valid but I don't remember exactly when. I think it had something to do with holey enumerations. > >> As a by-product you get a highly portable code as Gautier pointed out in > >> another response. > > > > I don't understand this claim of highly portable code without using > > a rep spec. > > The semantics of a representation clause depends on the native machine bit > and storage unit endianness, the size of the storage unit, alignment > constraints. The semantics of arithmetic operations and shifts is fully > machine-independent. You've given rep clauses more semantics than the LRM. They simply specify how bits are laid out. I (and the people I lead) avoid storage unit issues by writing component clauses of the form for Component use at 0 range ... That is, the layout is specified relative to the beginning of the record. Comments usually tie this to the document that specified the data layout. I could also get around native machine endianess by specifying the bit order; for some reason I didn't. The down side of this form of component clause is that, without the comments, it is a little obscure. I decided to make that tradeoff in order to get better native machine transportability. > The rule of thumb: representation clauses shall be used exclusively for the > machine hardware. This is the only legitimate case for them. Isn't that what I've been advocating? Using representation clauses when the hardware of one machine doesn't match the hardware of another? I hope nothing I've written was interpreted as meaning you should sprinkle rep clauses around like holy water. I religiously avoid using them except when absolutely necessary. (Your meaning of "absolutely necessary" might differ from mine.) Charlie -- Nobody in this country got rich on his own. You built a factory--good. But you moved your goods on roads we all paid for. You hired workers we all paid to educate. So keep a big hunk of the money from your factory. But take a hunk and pay it forward. Elizabeth Warren (paraphrased) ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-25 21:42 ` Charles H. Sampson @ 2011-12-26 10:47 ` Dmitry A. Kazakov 2011-12-27 10:38 ` Georg Bauhaus 2012-01-04 4:33 ` Charles H. Sampson 0 siblings, 2 replies; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-26 10:47 UTC (permalink / raw) On Sun, 25 Dec 2011 13:42:45 -0800, Charles H. Sampson wrote: > I'm not clear on what you mean by "representation clauses ... tend > to convert things as a whole". Representation clauses don't convert > anything. They just specify how the bits are laid out in memory. But you want to use them for conversions. You somehow put raw data there and then reinterpret that as an integral ADT object, usually an integer. What about a task object? Consider an agent-based application using some protocol to transport agents (tasks) over the network. Would you reconstruct an agent from bits and bytes using a representation clause? (:-)) > For example, to change > the endianess of a two-byte word, I might write something like > > Internal_Small_Word := 256 * Incoming.Byte_2 + Byte_1; > > It's more than likely that I would use a representation clause for > Internal_Small_Word also and just do two assignments: > > Internal_Small_Word.Byte_1 := Incoming.Byte_2; > Internal_Small_Word.Byte_2 := Incoming.Byte_1; > > It won't surprise you when I say that I think the latter is much clearer > as to intent and meaning than any arithmetic manipulating, including my > former example. No. The first variant follows the mathematical definition of how an integer of the range 0 .. 2**16 - 1 is encoded as a sequence of octets (integers range 0 .. 2**8 - 1). Your code uses obscure assignments to some fields of some record type, which connection to the mathematical definition of an encoded number is not clear to the reader, as well as the correctness of the code, because the order of bytes and gaps between them is specified somewhere else by a representation clause. Note also that all examples you and others have so far provided, go no further swapping bytes and trivial bit fields extraction. This is too little for real-life applications. Consider a PT100 WAGO Modbus module. It delivers a WORD (two bytes) in so-called Siemens format. 12 MSBs encode the value from -200 to 883 degree Celsius represented as 0400..7FF8. Bigger and lesser values are cropped. The 4 LSBs bits are the diagnostics bits (curcuit open/close etc). You could not handle this using a representation clause in one step. You will have first to swap bytes to build a 16 bit integer and use it to obtain the temperature masking and shifting. Or, first reorder and extract 12 bits, extract 4 bits, check, recode 12 bits into value. In both cases arithmetical operations are unavoidable. > Data corruption is handled by whatever mechanism is in the data > packets to guard against corruption. As I said, you need something to add, in order to check validity of the values obtained from the conversion. X'Valid is no help in the examples like above, when values are saturated and/or additional bits or patterns are used to indicate validness. Another example chain codes. E.g. the following encoding of cardinal numbers: 0 -> 2#0000_000# 1 -> 2#0000_0001# ... 127 -> 2#0111_1111# 128 -> 2#1000_0000# 2#0000_0001# 129 -> 2#1000_0001# 2#0000_0001# ... 4095 -> 2#1111_1111# 2#0111_1111# 4096 -> 2#1000_0000# 2#1000_0000# 2#0000_0001# ... [Chain codes are used when the upper bound of the transported number is unspecified and it is expected that lesser values are more frequent than bigger ones. UTF-8, is chain code.] Care to write a representation clause for the above? >> The rule of thumb: representation clauses shall be used exclusively for the >> machine hardware. This is the only legitimate case for them. > > Isn't that what I've been advocating? In that case we are in agreement that they should not be used for handling I/O protocols. The only useful examples of representation clauses I saw were descriptions of machine registers, e.g. the bits of the processor status word, of the memory mapping registers etc. IMO, this is the only legitimate use for them: systems programming, machine-specific, once in 10 years or never. > Using representation clauses > when the hardware of one machine doesn't match the hardware of another? All sorts of I/O: reading data from a hardware port, from a socket, from dual-ported shared memory etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-26 10:47 ` Dmitry A. Kazakov @ 2011-12-27 10:38 ` Georg Bauhaus 2011-12-27 12:35 ` Dmitry A. Kazakov 2012-01-04 4:33 ` Charles H. Sampson 1 sibling, 1 reply; 30+ messages in thread From: Georg Bauhaus @ 2011-12-27 10:38 UTC (permalink / raw) On 26.12.11 11:47, Dmitry A. Kazakov wrote: > Your code uses obscure assignments to some fields of some record type, Or, as one might say, the expression 256 * Incoming.Byte_2 + Byte_1 is an obscure arithmetical formula involving the magic number 256. It takes careful study by someone with mathematical training and also requires knowledge of language fine print and data representation or else 256 is not meaningful, but obscure! So, regarding obscurity, the formula would at first show little advantage. Neither will it be more readable in this sense. > 4095 -> 2#1111_1111# 2#0111_1111# > 4096 -> 2#1000_0000# 2#1000_0000# 2#0000_0001# > ... > > [Chain codes are used when the upper bound of the transported number is > unspecified and it is expected that lesser values are more frequent than > bigger ones. UTF-8, is chain code.] > > Care to write a representation clause for the above? Arguably, a chain code might not what a regular programmer would see as something to which a record representation clause will apply as a whole. What will the concrete data type for the above chain code look like, as a whole, if it is not a list or array of some sort and if, for example, a chain code is being used precisely because there is a lot more to link than can be represented in what physically corresponds to range 0 .. 2**System.Word_Size? It seems there is value in distinguishing an encoding from a representation, and establish their relationship. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-27 10:38 ` Georg Bauhaus @ 2011-12-27 12:35 ` Dmitry A. Kazakov 0 siblings, 0 replies; 30+ messages in thread From: Dmitry A. Kazakov @ 2011-12-27 12:35 UTC (permalink / raw) On Tue, 27 Dec 2011 11:38:32 +0100, Georg Bauhaus wrote: > On 26.12.11 11:47, Dmitry A. Kazakov wrote: > >> Your code uses obscure assignments to some fields of some record type, > > Or, as one might say, the expression > > 256 * Incoming.Byte_2 + Byte_1 > > is an obscure arithmetical formula involving the magic number 256. Data (Index) * 2**8 + Data (Index + 1) > It takes careful study by someone with mathematical training and also > requires knowledge of language fine print and data representation or > else 256 is not meaningful, but obscure! You need mathematical training in order to understand how numbers are encoded. Representation clauses require much *additional* understanding on top of that. Difficulties people keep on having with understanding and proper usage of the clauses reflect this simple fact. > So, regarding obscurity, the formula would at first show little advantage. > Neither will it be more readable in this sense. It is. This is the way these things are defined in first place. E.g. http://en.wikipedia.org/wiki/Two_complement There is simply no other way. The only thing you can do with a number is to use numeric operations. Anything else is on top of that. Remember that binary representation of a number is an encoding, itself defined through mathematical operations. >> 4095 -> 2#1111_1111# 2#0111_1111# >> 4096 -> 2#1000_0000# 2#1000_0000# 2#0000_0001# >> ... >> >> [Chain codes are used when the upper bound of the transported number is >> unspecified and it is expected that lesser values are more frequent than >> bigger ones. UTF-8, is chain code.] >> >> Care to write a representation clause for the above? > > Arguably, a chain code might not what a regular programmer would see > as something to which a record representation clause will apply as a whole. Regular programmer does not bother about encoding anyway. But if someone have to, my advise is: don't waste your time on understanding representation clauses. They won't help you. Beyond trivial cases, if you are not a language lawyer, you will never understand why that mess works or does not work. > What will the concrete data type for the above chain code look like, An integer number > as a whole, if it is not a list or array of some sort and if, for example, > a chain code is being used precisely because there is a lot more to link > than can be represented in what physically corresponds to > range 0 .. 2**System.Word_Size? That was another point against representation clauses: they fall short when it comes to validity checks. The peers of the protocol like above would impose certain implementation-specific limits on the number range. Upon decoding (using arithmetic operations), the program would necessarily get Constraint_Error when the limit is exceeded, and reroute to Protocol_Error. It is a very simple and effective method handling protocols in general. > It seems there is value in distinguishing an encoding from a representation, > and establish their relationship. (Ah, you know my weakness of giving definitions. (:-)) OK, here it one: [Machine] representation is an encoding with the alphabet based on the values of a machine type. P.S. A not yet mentioned argument against representation clauses is their unfriendliness to correctness proof and testing (you would likely need a full coverage test). -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-26 10:47 ` Dmitry A. Kazakov 2011-12-27 10:38 ` Georg Bauhaus @ 2012-01-04 4:33 ` Charles H. Sampson 2012-01-04 11:56 ` Dmitry A. Kazakov 1 sibling, 1 reply; 30+ messages in thread From: Charles H. Sampson @ 2012-01-04 4:33 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > On Sun, 25 Dec 2011 13:42:45 -0800, Charles H. Sampson wrote: > > > I'm not clear on what you mean by "representation clauses ... tend > > to convert things as a whole". Representation clauses don't convert > > anything. They just specify how the bits are laid out in memory. > > But you want to use them for conversions. You somehow put raw data there > and then reinterpret that as an integral ADT object, usually an integer. I don't reinterpret the raw data, Based on some knowledge of the data the representation clause defines its interpretation. Until we get to that point, the data are, for me, just a string of bits. Very seldom is that interpretation an integer; most often it is a somewhat complex structure of non-homogenous components, the very definition of a record. > What about a task object? Consider an agent-based application using some > protocol to transport agents (tasks) over the network. Would you > reconstruct an agent from bits and bytes using a representation clause? > (:-)) I have no concept of a task object being transported over a network. The closest I can come is an indicator (integer or enumeration type) specifying a task object on the receiving machine to be used. For anything else, I'll have to wait until I see one to decide what my strategy would be. > > For example, to change > > the endianess of a two-byte word, I might write something like > > > > Internal_Small_Word := 256 * Incoming.Byte_2 + Byte_1; > > > > It's more than likely that I would use a representation clause for > > Internal_Small_Word also and just do two assignments: > > > > Internal_Small_Word.Byte_1 := Incoming.Byte_2; > > Internal_Small_Word.Byte_2 := Incoming.Byte_1; > > > > It won't surprise you when I say that I think the latter is much clearer > > as to intent and meaning than any arithmetic manipulating, including my > > former example. > > No. The first variant follows the mathematical definition of how an integer > of the range 0 .. 2**16 - 1 is encoded as a sequence of octets (integers > range 0 .. 2**8 - 1). And the second variant shows how to rearrange some of the incoming bits to get the same value in native machine form. > > Your code uses obscure assignments to some fields of some record type, > which connection to the mathematical definition of an encoded number is not > clear to the reader, as well as the correctness of the code, because the > order of bytes and gaps between them is specified somewhere else by a > representation clause. And your code uses obscure multiplications that are really a disguised form of shifts. If you're thinking shifts, why not use a shift function? From a mathematical point of view, your multiplication code is treating two bytes of the incoming code as digits in a base 256 representation. For a mathematician, that's clear. It can be confusing and surprising to a non-mathematician. > Note also that all examples you and others have so far provided, go no > further swapping bytes and trivial bit fields extraction. This is too > little for real-life applications. The subject of this thread had to do with endianess. > Consider a PT100 WAGO Modbus module. It delivers a WORD (two bytes) in > so-called Siemens format. 12 MSBs encode the value from -200 to 883 degree > Celsius represented as 0400..7FF8. Bigger and lesser values are cropped. > The 4 LSBs bits are the diagnostics bits (curcuit open/close etc). You > could not handle this using a representation clause in one step. You will > have first to swap bytes to build a 16 bit integer and use it to obtain the > temperature masking and shifting. Or, first reorder and extract 12 bits, > extract 4 bits, check, recode 12 bits into value. In both cases > arithmetical operations are unavoidable. I'm pretty sure I could do it to my satisfaction but I've got too many questions about your description to actually write any code. For example, are 200 and 883 in decimal or hex? What about endianess? Doesn't the value 7FF8 preclude using the 4 LSBs as diagnostic bits? Regarding "You could not handle this using a representation clause in one step.", I don't know what "this" refers to. Even if I did, what is the importance of "one step"? Am I correct in assuming that "one step" means "one statement"? If so, that's unimportant to a reasonably good optimizing compiler, which can ofter encode sequences of statement as though they were one complex statement. > > Data corruption is handled by whatever mechanism is in the data > > packets to guard against corruption. > > As I said, you need something to add, in order to check validity of the > values obtained from the conversion. X'Valid is no help in the examples > like above, when values are saturated and/or additional bits or patterns > are used to indicate validness. > > Another example chain codes. E.g. the following encoding of cardinal > numbers: > > 0 -> 2#0000_000# > 1 -> 2#0000_0001# > ... > 127 -> 2#0111_1111# > 128 -> 2#1000_0000# 2#0000_0001# > 129 -> 2#1000_0001# 2#0000_0001# > ... > 4095 -> 2#1111_1111# 2#0111_1111# > 4096 -> 2#1000_0000# 2#1000_0000# 2#0000_0001# > ... > > [Chain codes are used when the upper bound of the transported number is > unspecified and it is expected that lesser values are more frequent than > bigger ones. UTF-8, is chain code.] > > Care to write a representation clause for the above? No, because they are not of a record type. Give me some information about how the chains are laid out in memory and I should be able to come up with some useful type definitions. > >> The rule of thumb: representation clauses shall be used exclusively for the > >> machine hardware. This is the only legitimate case for them. > > > > Isn't that what I've been advocating? > > In that case we are in agreement that they should not be used for handling > I/O protocols. > > The only useful examples of representation clauses I saw were descriptions > of machine registers, e.g. the bits of the processor status word, of the > memory mapping registers etc. IMO, this is the only legitimate use for > them: systems programming, machine-specific, once in 10 years or never. > > > Using representation clauses > > when the hardware of one machine doesn't match the hardware of another? > > All sorts of I/O: reading data from a hardware port, from a socket, from > dual-ported shared memory etc. I started to say once before that I think I see the primary difference between us but I never quite got it out. To me, data being input "over a wire" are a sequence of bits and I use record types with representation clauses as soon as I can to specify the meaning of those bits. You seem to see those data as a stream of bytes that contain integers in the range 0 .. 255 and you specify the meaning by doing arithmetic manipulations. I also believe in "programming with data" and it appears that you don't, or at least you don't to the degree that I do. Those are pretty fundamental differences between us from the get-go so it's not suprising that we end up with quite different looking code to accomplish the same task. If my characterization of your approach is correct, then how you do you handle a stream of bytes when some of them represent characters? Do you use 'Val? What do you do when some of the bytes, when combined properly, represent a "signed" integer (i.e. a value that could be negative)? Charlie -- Nobody in this country got rich on his own. You built a factory--good. But you moved your goods on roads we all paid for. You hired workers we all paid to educate. So keep a big hunk of the money from your factory. But take a hunk and pay it forward. Elizabeth Warren (paraphrased) ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2012-01-04 4:33 ` Charles H. Sampson @ 2012-01-04 11:56 ` Dmitry A. Kazakov 0 siblings, 0 replies; 30+ messages in thread From: Dmitry A. Kazakov @ 2012-01-04 11:56 UTC (permalink / raw) On Tue, 3 Jan 2012 20:33:30 -0800, Charles H. Sampson wrote: > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote: > >> On Sun, 25 Dec 2011 13:42:45 -0800, Charles H. Sampson wrote: >> >>> I'm not clear on what you mean by "representation clauses ... tend >>> to convert things as a whole". Representation clauses don't convert >>> anything. They just specify how the bits are laid out in memory. >> >> But you want to use them for conversions. You somehow put raw data there >> and then reinterpret that as an integral ADT object, usually an integer. > > I don't reinterpret the raw data, Based on some knowledge of the > data the representation clause defines its interpretation. Until we get > to that point, the data are, for me, just a string of bits. Very seldom > is that interpretation an integer; most often it is a somewhat complex > structure of non-homogenous components, the very definition of a record. String of bits (array) /= record. >> What about a task object? Consider an agent-based application using some >> protocol to transport agents (tasks) over the network. Would you >> reconstruct an agent from bits and bytes using a representation clause? >> (:-)) > > I have no concept of a task object being transported over a > network. That is because you have no concept of an object at all. A task is an object and an integer is also an object. Neither is a string of bits, though a string of bits could be used to represent [encode] either. >>> For example, to change >>> the endianess of a two-byte word, I might write something like >>> >>> Internal_Small_Word := 256 * Incoming.Byte_2 + Byte_1; >>> >>> It's more than likely that I would use a representation clause for >>> Internal_Small_Word also and just do two assignments: >>> >>> Internal_Small_Word.Byte_1 := Incoming.Byte_2; >>> Internal_Small_Word.Byte_2 := Incoming.Byte_1; >>> >>> It won't surprise you when I say that I think the latter is much clearer >>> as to intent and meaning than any arithmetic manipulating, including my >>> former example. >> >> No. The first variant follows the mathematical definition of how an integer >> of the range 0 .. 2**16 - 1 is encoded as a sequence of octets (integers >> range 0 .. 2**8 - 1). > > And the second variant shows how to rearrange some of the incoming > bits to get the same value in native machine form. Value of what? Same to what? Where and how is it defined? >> Your code uses obscure assignments to some fields of some record type, >> which connection to the mathematical definition of an encoded number is not >> clear to the reader, as well as the correctness of the code, because the >> order of bytes and gaps between them is specified somewhere else by a >> representation clause. > > And your code uses obscure multiplications that are really a > disguised form of shifts. If you're thinking shifts, why not use a > shift function? On the contrary, shifts are disguised multiplications. See the question above. Any encoding of integer values *shall* in its definition use arithmetical operations to reconstruct the value. A more general statement is that any encoding of whatever object must in its definition use the operations defined on the corresponding ADT. That immediately follows from the definition of ADT in a typed language. You just have no other means to create an object, again, if the language is typed. > From a mathematical point of view, your multiplication code is > treating two bytes of the incoming code as digits in a base 256 > representation. For a mathematician, that's clear. It can be confusing > and surprising to a non-mathematician. There is no other view, sorry. Encoding is *defined* as a translation into an alphabet, which in the case of octets are symbols 0,1,..,255. >> Note also that all examples you and others have so far provided, go no >> further swapping bytes and trivial bit fields extraction. This is too >> little for real-life applications. > > The subject of this thread had to do with endianess. So? >> Consider a PT100 WAGO Modbus module. It delivers a WORD (two bytes) in >> so-called Siemens format. 12 MSBs encode the value from -200 to 883 degree >> Celsius represented as 0400..7FF8. Bigger and lesser values are cropped. >> The 4 LSBs bits are the diagnostics bits (curcuit open/close etc). You >> could not handle this using a representation clause in one step. You will >> have first to swap bytes to build a 16 bit integer and use it to obtain the >> temperature masking and shifting. Or, first reorder and extract 12 bits, >> extract 4 bits, check, recode 12 bits into value. In both cases >> arithmetical operations are unavoidable. > > I'm pretty sure I could do it to my satisfaction but I've got too > many questions about your description to actually write any code. For > example, are 200 and 883 in decimal or hex? Decimal. > What about endianess? None, in the sense that different ModBus commands allows you to read individual bytes and/or words at some ModBus addresses, which meaning depends in the command mode being used. Furthermore, bytes can be scattered, i.e. lie on non-consequent ModBus addresses. Welcome to the real world! > Doesn't the value 7FF8 preclude using the 4 LSBs as diagnostic bits? No. > Regarding "You could not handle this using a representation clause > in one step.", I don't know what "this" refers to. Even if I did, what > is the importance of "one step"? Am I correct in assuming that "one > step" means "one statement"? If the representation clauses could have handled real-life protocols, then you would need no other means on order to get values out of read data. Which would mean that all happens in just one step: you read data into memory and then take values from the data structure located at the physically same address. That does not work except for quite elementary cases. >>> Data corruption is handled by whatever mechanism is in the data >>> packets to guard against corruption. >> >> As I said, you need something to add, in order to check validity of the >> values obtained from the conversion. X'Valid is no help in the examples >> like above, when values are saturated and/or additional bits or patterns >> are used to indicate validness. >> >> Another example chain codes. E.g. the following encoding of cardinal >> numbers: >> >> 0 -> 2#0000_000# >> 1 -> 2#0000_0001# >> ... >> 127 -> 2#0111_1111# >> 128 -> 2#1000_0000# 2#0000_0001# >> 129 -> 2#1000_0001# 2#0000_0001# >> ... >> 4095 -> 2#1111_1111# 2#0111_1111# >> 4096 -> 2#1000_0000# 2#1000_0000# 2#0000_0001# >> ... >> >> [Chain codes are used when the upper bound of the transported number is >> unspecified and it is expected that lesser values are more frequent than >> bigger ones. UTF-8, is chain code.] >> >> Care to write a representation clause for the above? > > No, because they are not of a record type. Why should they be? > Give me some > information about how the chains are laid out in memory and I should be > able to come up with some useful type definitions. They aren't laid anywhere. It is you way of thinking of it. [Which is inherently flawed, as I am trying to show you by these examples] The octets are sent over some octet stream, that is all. >>> Using representation clauses >>> when the hardware of one machine doesn't match the hardware of another? >> >> All sorts of I/O: reading data from a hardware port, from a socket, from >> dual-ported shared memory etc. > > I started to say once before that I think I see the primary > difference between us but I never quite got it out. To me, data being > input "over a wire" are a sequence of bits and I use record types with > representation clauses as soon as I can to specify the meaning of those > bits. You seem to see those data as a stream of bytes that contain > integers in the range 0 .. 255 and you specify the meaning by doing > arithmetic manipulations. No, you are wrong. The transport protocol (wire) can be of any sort. IFF that protocol is *serial* http://en.wikipedia.org/wiki/Serial_communication THEN, per definition of serial, it is a stream of bits. There exist zillions of protocols which aren't serial. All this boils down to the definition of encoding. Remember, encoding is a translation into certain alphabet: http://en.wikipedia.org/wiki/Encoding When the alphabet is {0,1}, you have a serial or binary protocol. There are other alphabets, you know. Network protocols use streams of octets {0,1,2,...,255}, or packets of octets. The typewriter uses letters. Morse Code uses dot and dash, etc. > I also believe in "programming with data" and > it appears that you don't, or at least you don't to the degree that I > do. Those are pretty fundamental differences between us from the > get-go so it's not suprising that we end up with quite different looking > code to accomplish the same task. Well, if you believe in "programming with data," then there must be "programming without data" in your world... Not in mine. > If my characterization of your approach is correct, then how you do > you handle a stream of bytes when some of them represent characters? That depends on: 1. the meaning of the word byte 2. the character type. We have many in Ada. 3. the encoding. There are many so character encodings: UTF-n, USC-n, EBCDIC, RADIX-50, ASCII, KOI-n, to name a few. > Do you use 'Val? If 1 = octet, 2 = Character, 3 = ASCII or Latin-1 > What do you do when some of the bytes, when combined > properly, represent a "signed" integer (i.e. a value that could be > negative)? See 1. You first give the mathematical definition of byte, e.g. 1. Integer range 0..255 2. Integer range -128..127 3. Ordered set of bits {0,1}**8 4. Ordered set of hexadecimal digits {0,1,2,3,5,6,7,8,9,A,B,C,D,E,F}**2 ... based on how the communication hardware and the machine type chosen to represent byte interact. Then you define the encoding, i.e. a mapping from the values of the Ada character type to the symbols the alphabet above. E.g.: A -> -34 B -> 56 C -> 1 ... Then that mapping gets implemented. If 'Val is appropriate for that, then why not to use it? In the real-life octet/Interfaces.Unsigned_8, Character, ASCII covers almost 90% cases. For them, I am customary using Character'Val. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Does Ada support endiannes? 2011-12-12 12:46 ` Gerd 2011-12-12 13:22 ` Dmitry A. Kazakov @ 2011-12-12 13:33 ` Robert A Duff 1 sibling, 0 replies; 30+ messages in thread From: Robert A Duff @ 2011-12-12 13:33 UTC (permalink / raw) Gerd <GerdM.O@t-online.de> writes: > Any suggestion on how to convert, others than using "/" and "mod"? GNAT has a package called GNAT.Byte_Swapping in g-bytswa.ads. - Bob ^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2012-01-04 11:58 UTC | newest] Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-12-12 8:57 Does Ada support endiannes? Gerd 2011-12-12 9:23 ` Niklas Holsti 2011-12-12 11:27 ` Dmitry A. Kazakov 2011-12-12 12:44 ` Gerd 2011-12-12 19:23 ` Jeffrey Carter 2011-12-13 14:25 ` Gerd 2011-12-13 14:19 ` Gautier write-only 2011-12-14 16:16 ` Gerd 2011-12-14 18:16 ` Dmitry A. Kazakov 2011-12-14 20:16 ` Gautier write-only 2011-12-15 11:27 ` Gerd 2011-12-15 13:01 ` Simon Wright 2011-12-15 13:37 ` Dmitry A. Kazakov 2011-12-15 20:12 ` Jeffrey Carter 2011-12-12 12:46 ` Gerd 2011-12-12 13:22 ` Dmitry A. Kazakov 2011-12-12 17:07 ` Charles H. Sampson 2011-12-12 18:33 ` Dmitry A. Kazakov 2011-12-14 5:19 ` Charles H. Sampson 2011-12-14 8:56 ` Dmitry A. Kazakov 2011-12-14 9:46 ` Simon Wright 2011-12-15 9:14 ` Charles H. Sampson 2011-12-15 9:46 ` Dmitry A. Kazakov 2011-12-25 21:42 ` Charles H. Sampson 2011-12-26 10:47 ` Dmitry A. Kazakov 2011-12-27 10:38 ` Georg Bauhaus 2011-12-27 12:35 ` Dmitry A. Kazakov 2012-01-04 4:33 ` Charles H. Sampson 2012-01-04 11:56 ` Dmitry A. Kazakov 2011-12-12 13:33 ` Robert A Duff
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox