comp.lang.ada
 help / color / mirror / Atom feed
* Type conversion / computing problem
@ 2000-02-17  0:00 Andreas
  2000-02-17  0:00 ` Robert A Duff
  0 siblings, 1 reply; 4+ messages in thread
From: Andreas @ 2000-02-17  0:00 UTC (permalink / raw)


Hi!

I need advice on a nice problem with data type conversions in Ada95 with GNAT:
I am writing an small interpreter for an assembly-like language whose entire 
data should be stored in memory as the amount of bytes needed for a particular
Ada-type (e.g. 4 bytes for Integers, 8 bytes for Long_Floats) and each of those
bytes should be separately addressable. A register for this assembler should be
8 bytes and the rightmost byte is the least significant one.
A register (just an array variable of type RegType) has to be an intermediate 
variable that should allow converting any type A to any type B (so I don't have 
to write separate functions for each possible conversion). So the functionality 
should be this (e.g.):

4-byte-Integer (e.g. 5) --> Register, bytes 5-8, least significant right --> 
    8-byte-Integer (e.g. 5)

or

4-byte-Integer (e.g. 5) --> Register, bytes 5-8, least significant right --> 
    2-byte-Integer (e.g. 5)

(the --> denote conversions). Of course, the value of the integers should not 
change when converted to a larger type. When converted to a Ada type, only 
the amount of bytes required for this type should be considered in the Register,
thus (perhaps) changing the value (e.g. use the rightmost 2 bytes of the
register
for a Short_Integer).

Currently I am using the following code for splitting/converting the Integer 
types into the array of bytes (register) and back (only functions for 
Standard.Integer given, for other Integers same algorithm):

type Byte     is mod 256;                -- an unsigned byte
type RegType  is array (1..8) of Byte;   -- register
type BitIndexType is mod 8;              -- for converting purposes

-- This function converts data type Integer into an array of Byte's
function RAS_Integer2Reg (IntValue: in Integer) return RegType is
    TempReg:       RegType:= (others => 0); -- initialize with 0
    BitIndex:      BitIndexType := 0;   
    ByteIndex:     Integer := 8; -- least significant byte right in register
    Remainder:     Integer;
    LocalIntValue: Integer;
begin
    LocalIntValue := IntValue;
    while LocalIntValue /= 0 loop
        Remainder := LocalIntValue mod 2;
        LocalIntValue := LocalIntValue / 2;
        TempReg(ByteIndex) := TempReg(ByteIndex) + Byte(Remainder *
2**Integer(BitIndex));
        if BitIndex = 7 then
            ByteIndex := ByteIndex - 1; -- switch to next byte
        end if;
        BitIndex := BitIndex + 1;
    end loop;
    return TempReg;
end RAS_Integer2Reg;

-- This function converts the array of Byte's into an Integer value
function RAS_Reg2Integer (RegValue: in RegType) return Integer is
    TempInt:  Integer := 0;
    BitIndex: Integer := 0; -- this time no mod type!
begin
    for ByteIndex in reverse 5..8 loop  -- Integer is only 4 bytes out of the 
                                        -- 8 in RegType
        TempInt := TempInt + Integer(RegValue(ByteIndex)) * 2**BitIndex;
        BitIndex := BitIndex + 8;
    end loop;
    return TempInt;
end RAS_Reg2Integer;

Now, the problem is that these functions work perfectly only for positive 
Integers (I guess because of the unsigned Byte), not for negative values.
Unfortunately, I cannot change the types Byte and RegType since they are 
required. How can I use the same data types for processing negative values
without defining a signed byte like "type Byte is Integer range -128..127" 
(and I don't even think this would help)???

Furthermore it's required for an associated debugger that the entire register 
should be displayed as an 8-byte-Integer (I use Long_Long_Integer, but have 
already also tried a self-defined 64-bit-type for this). So if you do the 
conversion:

4-byte-Integer (Standard.Integer) --> RegType --> 8-byte-Integer (Long_Long_Int)

the original value should of course be the same in 8-byte-Integer.
This as well, when using the algorithms above, works only for positive values.
For this example, I already tried defining a 8-Byte-array, doing an 
Unchecked_Conversion and changing the byte order "manually" (of course by
program ;-)). But when I do this, Unchecked_Conversion seems to fill the byte
array from left to right, not as required, from right to left, thus changing the
original value. And the problem with negative values still persists.

I would greatly appreciate any hints on how I can solve this problem of storing
negative (Integer) values in an array of unsigned bytes with least significant
byte right.

(Yes, I'm looking for a rather uncomplicated solution, not writing a long
algorithm with distinction between positive and negative values :-), but I would
also be very happy about such a longer solution).

Thanks in advance!

Andreas

P.S. Could you please send the reply via e-mail, too?! :-)




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Type conversion / computing problem
  2000-02-17  0:00 Type conversion / computing problem Andreas
@ 2000-02-17  0:00 ` Robert A Duff
  2000-02-22  0:00   ` Oliver Kellogg
  0 siblings, 1 reply; 4+ messages in thread
From: Robert A Duff @ 2000-02-17  0:00 UTC (permalink / raw)


Andreas <Amun_Ra72@gmx.net> writes:

> Now, the problem is that these functions work perfectly only for positive 
> Integers (I guess because of the unsigned Byte), not for negative values.

You could convert each signed integer to a modular of the same size
using Unchecked_Conversion.  And I think your code already knows how to
convert that to an array-of-8-bytes, with the right byte ordering.

Or, unchecked conv signed to modular of same size, then use a normal
type_conversion to convert to a "mod 2**64" type, then unchecked convert
that to array-of-8-bytes, then apply a byte-swap procedure to that
array.

- Bob




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Type conversion / computing problem
@ 2000-02-17  0:00 Andreas
  0 siblings, 0 replies; 4+ messages in thread
From: Andreas @ 2000-02-17  0:00 UTC (permalink / raw)


Hi!

I need advice on a nice problem with data type conversions in Ada95 with GNAT:
I am writing an small interpreter for an assembly-like language whose entire 
data should be stored in memory as the amount of bytes needed for a particular
Ada-type (e.g. 4 bytes for Integers, 8 bytes for Long_Floats) and each of those
bytes should be separately addressable. A register for this assembler should be
8 bytes and the rightmost byte is the least significant one.
A register (just an array variable of type RegType) has to be an intermediate 
variable that should allow converting any type A to any type B (so I don't have 
to write separate functions for each possible conversion). So the functionality 
should be this (e.g.):

4-byte-Integer (e.g. 5) --> Register, bytes 5-8, least significant right --> 
    8-byte-Integer (e.g. 5)

or

4-byte-Integer (e.g. 5) --> Register, bytes 5-8, least significant right --> 
    2-byte-Integer (e.g. 5)

(the --> denote conversions). Of course, the value of the integers should not 
change when converted to a larger type. When converted to a Ada type, only 
the amount of bytes required for this type should be considered in the Register,
thus (perhaps) changing the value (e.g. use the rightmost 2 bytes of the
register
for a Short_Integer).

Currently I am using the following code for splitting/converting the Integer 
types into the array of bytes (register) and back (only functions for 
Standard.Integer given, for other Integers same algorithm):

type Byte     is mod 256;                -- an unsigned byte
type RegType  is array (1..8) of Byte;   -- register
type BitIndexType is mod 8;              -- for converting purposes

-- This function converts data type Integer into an array of Byte's
function RAS_Integer2Reg (IntValue: in Integer) return RegType is
    TempReg:       RegType:= (others => 0); -- initialize with 0
    BitIndex:      BitIndexType := 0;   
    ByteIndex:     Integer := 8; -- least significant byte right in register
    Remainder:     Integer;
    LocalIntValue: Integer;
begin
    LocalIntValue := IntValue;
    while LocalIntValue /= 0 loop
        Remainder := LocalIntValue mod 2;
        LocalIntValue := LocalIntValue / 2;
        TempReg(ByteIndex) := TempReg(ByteIndex) + Byte(Remainder *
2**Integer(BitIndex));
        if BitIndex = 7 then
            ByteIndex := ByteIndex - 1; -- switch to next byte
        end if;
        BitIndex := BitIndex + 1;
    end loop;
    return TempReg;
end RAS_Integer2Reg;

-- This function converts the array of Byte's into an Integer value
function RAS_Reg2Integer (RegValue: in RegType) return Integer is
    TempInt:  Integer := 0;
    BitIndex: Integer := 0; -- this time no mod type!
begin
    for ByteIndex in reverse 5..8 loop  -- Integer is only 4 bytes out of the 
                                        -- 8 in RegType
        TempInt := TempInt + Integer(RegValue(ByteIndex)) * 2**BitIndex;
        BitIndex := BitIndex + 8;
    end loop;
    return TempInt;
end RAS_Reg2Integer;

Now, the problem is that these functions work perfectly only for positive 
Integers (I guess because of the unsigned Byte), not for negative values.
Unfortunately, I cannot change the types Byte and RegType since they are 
required. How can I use the same data types for processing negative values
without defining a signed byte like "type Byte is Integer range -128..127" 
(and I don't even think this would help)???

Furthermore it's required for an associated debugger that the entire register 
should be displayed as an 8-byte-Integer (I use Long_Long_Integer, but have 
already also tried a self-defined 64-bit-type for this). So if you do the 
conversion:

4-byte-Integer (Standard.Integer) --> RegType --> 8-byte-Integer (Long_Long_Int)

the original value should of course be the same in 8-byte-Integer.
This as well, when using the algorithms above, works only for positive values.
For this example, I already tried defining a 8-Byte-array, doing an 
Unchecked_Conversion and changing the byte order "manually" (of course by
program ;-)). But when I do this, Unchecked_Conversion seems to fill the byte
array from left to right, not as required, from right to left, thus changing the
original value. And the problem with negative values still persists.

I would greatly appreciate any hints on how I can solve this problem of storing
negative (Integer) values in an array of unsigned bytes with least significant
byte right.

(Yes, I'm looking for a rather uncomplicated solution, not writing a long
algorithm with distinction between positive and negative values :-), but I would
also be very happy about such a longer solution).

Thanks in advance!

Andreas

P.S. Could you please send the reply via e-mail, too?! :-)




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Type conversion / computing problem
  2000-02-17  0:00 ` Robert A Duff
@ 2000-02-22  0:00   ` Oliver Kellogg
  0 siblings, 0 replies; 4+ messages in thread
From: Oliver Kellogg @ 2000-02-22  0:00 UTC (permalink / raw)


Bob Duff pointed the way; here's a possible implementation
(I happen to have had a similar problem a while ago.)

with Ada.Text_IO;
with Interfaces, System, Unchecked_Conversion;
use Interfaces;

procedure RegTest is

   subtype Byte is Unsigned_8;
   subtype Var_Positive is Positive range 1 .. 8;
   type Byte_Array is array (Var_Positive range <>) of Byte;
   pragma Pack (Byte_Array);
   subtype Two_Bytes is Byte_Array (1 .. 2);
   subtype Four_Bytes is Byte_Array (1 .. 4);
   subtype RegType is Byte_Array (1 .. 8);
   function To_Bytes is new Unchecked_Conversion
            (Unsigned_64, RegType);

   function Maybe_Swap (Bytes : Byte_Array)
                              return Byte_Array is
      Tmp : Byte_Array (1 .. Bytes'Length);
   begin
      if System."=" (System.Default_Bit_Order,
                     System.Low_Order_First) then
         for I in Tmp'Range loop
            Tmp (I) := Bytes (Bytes'Last - I + 1);
         end loop;
      else
         Tmp := Bytes;
      end if;
      return Tmp;
   end Maybe_Swap;

   function Int2Reg (Value : Integer_32) return RegType is
      function To_Unsigned is new Unchecked_Conversion
                                   (Integer_64, Unsigned_64);
      U64 : Unsigned_64;
   begin
      U64 := To_Unsigned (Integer_64 (Value));
      return Maybe_Swap (To_Bytes (U64));
   end Int2Reg;

   function Reg2Int (Value : RegType) return Integer_32 is
      function To_Integer is new Unchecked_Conversion
                                   (Four_Bytes, Integer_32);
   begin
      return To_Integer (Maybe_Swap (Value (5 .. 8)));
      -- Interestingly, we can use fixed indexes here (5..8)
      -- regardless of host endianness.
      -- That is because on a little endian machine not only are
      -- the bytes in reverse sequence, but also the numbering of
      -- bytes is reversed. ("two wrongs make one right")
   end Reg2Int;

   package Byte_IO is new Ada.Text_IO.Modular_IO (Byte);
   RegVar : RegType;
   IntVar : Integer_32;

begin

   RegVar := (1 .. 7 => 0, 8 => 1);   -- one
   IntVar := Reg2Int (RegVar) + 1;    -- two
   RegVar := Int2Reg (IntVar);
   for I in 1 .. 8 loop
      -- output should be (0,0,0,0,0,0,0,2)
      Ada.Text_IO.Put (' ');
      Byte_IO.Put (RegVar (I), Base => 16);
   end loop;
   Ada.Text_IO.New_Line;

   RegVar := (1 .. 8 => 16#FF#);      -- minus one
   IntVar := Reg2Int (RegVar) - 1;    -- minus two
   RegVar := Int2Reg (IntVar);
   for I in 1 .. 8 loop
      -- output should be (FF,FF,FF,FF,FF,FF,FF,FE)
      Ada.Text_IO.Put (' ');
      Byte_IO.Put (RegVar (I), Base => 16);
   end loop;
   Ada.Text_IO.New_Line;

end RegTest;



Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2000-02-22  0:00 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-02-17  0:00 Type conversion / computing problem Andreas
2000-02-17  0:00 ` Robert A Duff
2000-02-22  0:00   ` Oliver Kellogg
  -- strict thread matches above, loose matches on Subject: below --
2000-02-17  0:00 Andreas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox