[英]how to make constant function in Ada?
我正在使用具有位带的ARM系统。 这涉及到计算地址,以及定义要计算其地址的对象。 我想定义一个函数来计算这些地址,但是我无法真正找到绕过该语言的方法。 我能想到的最好的方法是将参数输入到计算中的通用程序包。 问题之一是,我必须(嗯,也许您可以纠正我,我是一个初学者)在2个单独的语句中使用它,一个用于定义实例化的包,另一个用于使用它。 那么有没有那么复杂的方法呢? 而且也不太冗长吗? 我觉得我正在用不必要的东西涂抹文件。
到目前为止,这是我自带的:
generic
register_base : Natural;
bit_number : Natural;
package PeriphBitBand is
address: constant System.Address := System'To_Address(Peripheral_Alias_Base+ (register_base - Peripheral_Base)*32 + bit_number*4);
end PeriphBitBand;
和一种用法:
generic
RCC_ENABLE_REGISTER_Base : Natural;
RCCBit : Natural;
package STM32F4.GenericPeripheral is
RCC_ENABLE : Boolean with Atomic, size=>32;
private
package add is new PeriphBitBand(RCC_ENABLE_REGISTER_Base, RCCBit);
for RCC_ENABLE'Address use add.address;
end STM32F4.GenericPeripheral;
从您所在的位置开始,最简单的方法可能是一个函数:
with Whatever_Declares_Addresses;
function reg_bit_to_address (register_base,bit_number : Natural)
return System.Address is
begin
return System'To_Address (Whatever_Declares_Addresses.Peripheral_Alias_Base +
(register_base - Peripheral_Base) * 32 +
bit_number * 4);
end reg_bit_to_address;
...
RCC_ENABLE : Boolean with Atomic, size=>32;
for RCC_ENABLE'Address use reg_bit_to_address (RCC_ENABLE_REGISTER_Base, RCCBit);
在声明RCC_Enable时(紧随其后)评估函数调用时,其结果是恒定的,至少直到RCC_Enable超出范围为止。
但是,最好将RCC_Enable_Register
声明为一条记录,它的组成部分之一是一个名为RCC_Enable
或只是Enable
的布尔值,因为可以将其寻址为RCC_Enable_Register.Enable
。 有用于定义记录中每个组件的地址,布局和大小的标准语法。
由于合格的表达式(如RCC_Enable_Register.Enable
会变得冗长,因此可以使用“重命名”将其简化,例如
RCC_Enable : Boolean renames RCC_Enable_Register.Enable;
在当前作用域的持续时间内声明一个简写形式。 因为只是重命名,所以没有执行代价,当然,如果将其保留在使用位置本地,则不必费劲寻找它的定义...
为了好玩,我尝试按照@BrianDrummond的想法将在这里找到的错误代码转换为Ada。
C代码是
#include <stdio.h>
#define BITBAND_SRAM_REF 0x20000000
#define BITBAND_SRAM_BASE 0x22000000
// Convert SRAM address
#define BITBAND_SRAM(a,b) \
((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4)))
#define BITBAND_PERI_REF 0x40000000
#define BITBAND_PERI_BASE 0x42000000
// Convert PERI address
#define BITBAND_PERI(a,b) \
((BITBAND_PERI_BASE + (a-BITBAND_PERI_REF)*32 + (b*4)))
#define MAILBOX 0x20004000
#define TIMER 0x40004000
// Mailbox bit 0
#define MBX_B0 *((volatile unsigned int *)(BITBAND_SRAM(MAILBOX,0)))
// Mailbox bit 7
#define MBX_B7 *((volatile unsigned int *)(BITBAND_SRAM(MAILBOX,7)))
// Timer bit 0
#define TIMER_B0 *((volatile unsigned char *)(BITBAND_PERI(TIMER,0)))
// Timer bit 7
#define TIMER_B7 *((volatile unsigned char *)(BITBAND_PERI(TIMER,7)))
int main(void){
printf("%x\n", &MBX_B0);
return 0;
}
我的(部分)Ada是
private with System.Storage_Elements;
package Bitbanding is
MBX_B0 : Boolean with Atomic, Size => 32;
private
subtype Bit_Number is Integer range 0 .. 15;
-- Register is the address of the register we are interested in.
-- Register_Base is the start of the memory mapped to registers.
-- Bit is the bit number within the register.
-- Alias_Base is the start of the memory area where each
-- 32-bit word is mapped to one bit of the actual registers.
-- The result is the address to which Register/Bit_Number is mapped.
function To_Address
(Register : Natural;
Register_Base : Natural;
Bit : Bit_Number;
Alias_Base : Natural) return System.Address
is (System.Storage_Elements.To_Address
(System.Storage_Elements.Integer_Address
(Alias_Base
+ (Register - Register_Base) * 32
+ Bit * 4)));
-- These are the names in the ARM example; they are not good.
BITBAND_SRAM_REF : constant := 16#2000_0000#;
BITBAND_SRAM_BASE : constant := 16#2200_0000#;
MAILBOX : constant := 16#2000_4000#;
for MBX_B0'Address use To_Address (Register => MAILBOX,
Register_Base => BITBAND_SRAM_REF,
Bit => 0,
Alias_Base => BITBAND_SRAM_BASE);
end Bitbanding;
连同测试
with Ada.Text_IO;
with Bitbanding;
with System.Storage_Elements;
procedure Bitbanding_Test is
package Address_IO
is new Ada.Text_IO.Modular_IO (System.Storage_Elements.Integer_Address);
begin
Address_IO.Put
(System.Storage_Elements.To_Integer (Bitbanding.MBX_B0'Address),
Base => 16);
Ada.Text_IO.New_Line;
end Bitbanding_Test;
给出与C相同的数值结果( 16#22080000#
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.