Too many conversion types in Z80 emulator in Ada

I am using the Z80 emulator in Ada. I am implementing the JR (Jump relative) family, but I am not satisfied with my code:

with Ada.Text_IO;

procedure main is
    type UInt16 is mod 2 ** 16;
    type UInt8  is mod 2 **  8;
    type Int8   is range -128 .. 127;

    package UInt16_IO is new Ada.Text_IO.Modular_IO (UInt16);

    function Two_Complement(N : UInt8) return Int8 is
    begin
        if N <= 127 then
            return Int8 (N);
        end if;
        return Int8 (Integer (N) - 256);
    end Two_Complement;

    -- Relative jump
    function Jr (Address : UInt16; D: UInt8) return UInt16 is
    begin
        return UInt16 (Integer (Address) + Integer (Two_Complement (D) + 2));
    end Jr;

    Address : UInt16;
begin
    Address := 16#683#;
    UInt16_IO.Put (Item => Jr (Address, 16#F1#), Base => 16); -- Get    16#676# which is good !
end main;

      

Seems to work, but I believe there are too many types of conversions. Do you have any advice?

Thank,

Olivier salad.

+3


source to share


4 answers


You can watch

function Jr (Address : UInt16; D: UInt8) return UInt16 is
   Offset : constant Uint16
     := Uint16 (D) + (if D >= 16#80# then 16#ff00# else 0);
begin
   return Address + Offset + 2;
end Jr;

      



but it rather depends on what you want when - for example - Address is 0 and D is, say 16#80

(the above code returns 16#ff82#

).

+6


source


In case two integer types are very closely related, at least form a definite point of view if they only differ in a subset of values ​​but are not functions, consider subtypes.

I suspect that the choice of subtypes can blur the questions, however, from a conceptual point of view. So if I can speculate using your knowledge of the purpose of these integers to evolve names like Offset

(guessing), the value of the names will increase by conveying their purpose: what they mean, not just how many bits they have, or whether they are signed. Perhaps this also softens the type conversion experience, because then the parameters "become" objects of so-called types = concepts. The runtime (or compile-time) effects will be the same.



In C terms, a type alias is also a feature for XintNN_t; the alias can even include int

-ness if desired.

+1


source


Because Ada focuses on type safety, the following two type definitions are not directly compatible, as seen by the Ada compiler:

type UInt8 is mod 2 ** 8;
type UInt_8 is mod 2 ** 8;

      

This is why type conversion is necessary when used in a single expression. One way to solve this problem is to define a generic type. For example,

type Int32 is range -2 ** 31 .. 2 ** 31 - 1;

subtype UInt8 is Int32 range       0 .. 2 ** 8 - 1;
subtype  Int8 is Int32 range -2 ** 7 .. 2 ** 7 - 1;

      

Then you won't need as many conversions as the compiler will use the type Int32

as the base type for the computation. For example, a statement return Int8 (Integer (N) - 256);

in a procedure Two_omplement

can be simplified to return Int8 (N - 256);

.

As a side note, you can also use the library Interfaces

to ensure the correct sizes for the types. In addition, the library has convenient operations such as Shift_Left

, Shift_Right

etc.

+1


source


I suspect a slight change in the naming might help with this.

You can use this:

Subtype Address is UInt16;

Function "+"( Location : Address; Offset: Int8 ) return Address is
  (if Offset < 0 then Location - UInt16(ABS Offset)
   else Location + UInt16(Offset) );

      

This will allow you to reformulate Jr

as follows:

-- Relative jump
function Jr (Location : Address; D: UInt8) return UInt16 is
    Offset : Constant Int8 := Two_Complement(D) + 2;
begin
    return Location + Offset;
end Jr;

      

+1


source







All Articles