Types Ada中Z80仿真器中的类型转换过多
我正在用Ada做一个Z80模拟器。 我正在实现JR(跳跃相关)系列,但我对我的代码不满意: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);
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标准库中的typeInteger
,而不是您自己的类型(最好指定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;