我在Ada做一个Z80模拟器。 我正在实施JR(Jump relative)系列,但我对我的代码不满意:
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;
它似乎有效,但我发现转换的类型太多了。 你有什么建议吗?
谢谢,
奥利弗。
答案 0 :(得分:6)
你可以看看
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;
但它取决于你需要发生什么 - 例如 - 地址为0而D就是16#80
(上面的代码返回16#ff82#
)。
答案 1 :(得分:1)
如果两个整数类型非常密切相关,至少形成一定的观点,如果它们只在值的子集中有所不同而不是函数,则考虑子类型。
我怀疑从概念的角度来看,选择子类型可能会使问题变得模糊。所以,如果我可以推测,使用你关于那些整数的目的的知识来发展名称,如Offset
(猜测)将通过传达他们的目的来增加名称的价值:他们的意思,而不仅仅是他们有多少比特,或者他们是否签名。也许这会软化类型转换的体验,因为那时参数“成为”所谓类型=概念的对象。运行时(或编译时)效果将是相同的。
在C语言中,类型别名也是XintNN_t的可能性;别名甚至可能包括int
- 如果这是可取的。
答案 2 :(得分:1)
由于Ada专注于类型安全,因此以下两种类型定义不能直接兼容,如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
类型作为计算的基本类型。例如,return Int8 (Integer (N) - 256);
过程中的语句Two_Сomplement
可以简化为return Int8 (N - 256);
。
作为旁注,您还可以使用Interfaces
库来确保类型的正确大小。此外,该库还具有便捷的操作,例如Shift_Left
,Shift_Right
等。
答案 3 :(得分:1)
我怀疑命名的一些改动可能有助于解决问题。
你可以用这个:
Subtype Address is UInt16;
Function "+"( Location : Address; Offset: Int8 ) return Address is
(if Offset < 0 then Location - UInt16(ABS Offset)
else Location + UInt16(Offset) );
这将允许您将Jr
重新表述为:
-- Relative jump
function Jr (Location : Address; D: UInt8) return UInt16 is
Offset : Constant Int8 := Two_Complement(D) + 2;
begin
return Location + Offset;
end Jr;