Types Ada中Z80仿真器中的类型转换过多

Types Ada中Z80仿真器中的类型转换过多,types,ada,z80,Types,Ada,Z80,我正在用Ada做一个Z80模拟器。 我正在实现JR(跳跃相关)系列,但我对我的代码不满意: 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);

我正在用Ada做一个Z80模拟器。 我正在实现JR(跳跃相关)系列,但我对我的代码不满意:

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;
带有Ada.Text\u IO;
主要程序是
UInt16型为mod 2**16;
UInt8型为mod 2**8;
Int8类型的范围为-128。。127;
包UInt16_IO是新的Ada.Text_IO.Modular_IO(UInt16);
函数2_补码(N:UInt8)返回Int8为
开始
如果N Jr(地址,16#F1#),Base=>16);--获得16#676#,这很好!
端干管;
这似乎有效,但我发现类型转换太多了。 你有什么建议吗

谢谢


奥利维尔。

< P>在两个整数类型非常密切相关的情况下,至少从某个角度来看,如果它们在值子集中只存在差异而不起作用,则考虑子类型。 不过,我怀疑,从概念的角度来看,选择子类型可能会使事情变得模糊。因此,如果我可以推测的话,利用你对这些整数的用途的了解来发展像
Offset
(猜测)这样的名称将通过传达它们的用途来增加名称的价值:它们的意思,而不仅仅是它们有多少位,或者它们是否有符号。也许这也软化了类型转换的体验,因为参数“变成”了所谓类型=概念的对象。运行时(或编译时)效果将是相同的

在C语言中,xintnut也可以使用类型别名;如果需要,别名甚至可能包括
int
-ness

函数Jr(地址:UInt16;D:UInt8)返回UInt16为
偏移量:常数Uint16
:=Uint16(D)+(如果D>=16#80#那么16#ff00#否则为0);
开始
返回地址+偏移量+2;
结束Jr;

但这取决于当地址为0,D为,比如说,
16#80
(上面的代码返回
16#ff82#
)时需要执行的操作。

因为Ada关注类型安全,所以以下两种类型定义在编译器看来并不直接兼容:

type UInt8 is mod 2 ** 8;
type UInt_8 is mod 2 ** 8;
这就是为什么在同一表达式中使用它们时需要进行类型转换。解决此问题的一种方法是定义一个公共类型。比如说,

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;
这样,您就不需要太多的转换,因为编译器将使用
Int32
类型作为计算的基本类型。例如,语句
返回Int8(整数(N)-256)Two_Сcomplement
程序中的code>可以简化为
返回Int8(N-256)


作为旁注,您还可以使用
接口
库来确保类型的正确大小。此外,该库还提供了方便的操作,如
Shift\u Left
Shift\u Right
等。

我怀疑命名上的一点改动可能会有所帮助

你可以用这个:

Subtype Address is UInt16;

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

带:返回地址+UInt16(两个补码(D)+2);我有一个约束错误,这是正常的,因为两个补码可以返回负数。“太多”:因为我有C/C++的背景,我试图编写好的Ada!我没有注意到它返回int8。旁注:如果您使用Ada标准库中的type
Integer
,而不是您自己的类型(最好指定range和
'Size
),那么前一种类型很可能是16位类型。对于Janus/Ada,它是,因此尝试从
UInt16
转换可能会引起范围限制错误。如果将
UInt8
作为有符号
Int32
的子类型,则不会得到模运算
UInt8'(255)+1
将是256,而不是0,您可能会得到CE,这取决于您分配给它的内容。OP没有
uint8
任何地方,我想你的意思是
UInt16
接口
建议是一个很好的建议。实际上,在这种情况下,模块化算法将不可用。另一方面,我不认为在这段代码中使用模运算会有任何好处。相反,如果减去两个无符号整数
UInt8'(125)-130
,则结果将环绕,不适合该类型,并且编译器将无法“看到”这一点。因此,也将提出行政长官。我认为,如果没有可用的模运算,并且在您的示例中,
UInt8'(255)+1
,编译器将至少给出一个关于结果的警告(或一个错误,如果配置)。我将查看
接口
包。本例中的要点是,模运算是Z80 MPU在JR指令中所做的,这就是模拟器所需要的。类型安全性有助于吸引人们对角落案例的注意,比如地址可能从16到0-这已经很长时间了,但我认为Z80确实像Simon建议的那样,可以包装。很好!对于地址0的情况,我需要查阅Z80手册,或者在真实的手册上进行一些测试。我很确定我们有模效应,我同意!但是要找到好的“域名”来提高抽象级别并不容易,因为Z80域仿真非常技术化,包含大量的位和字节。我提供的代码不是真正的代码。我简化了它,把重点放在我的问题上。在真实的一个中,我有:子类型Register8是UInt8;子类型寄存器16为UInt16;子类型地址16为UInt16;等等
-- Relative jump
function Jr (Location : Address; D: UInt8) return UInt16 is
    Offset : Constant Int8 := Two_Complement(D) + 2;
begin
    return Location + Offset;
end Jr;