我正在使用具有位带的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;
答案 0 :(得分:3)
从你所在的位置开始,最简单的方法可能是一个功能:
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;
声明当前范围持续时间的简写形式。因为它只是一个重命名,所以没有执行惩罚,当然,如果你把它保存在你使用它的地方,你不必搜索到远处找到它的定义......
答案 1 :(得分:2)
为了好玩,我尝试将我发现here的错误代码翻译成Ada,遵循@BrianDrummond的想法。
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#
)。