如何在Ada中不断发挥作用?

时间:2014-10-11 14:02:56

标签: arm 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;

2 个答案:

答案 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#)。