Product Family: DACS, SCORE, TADS
Target CPU: Any
Language: Ada
Host: Any
When one is first learning the Ada
language, there is a noticeable absence of the
common bit operations; and, or, not, xor. Having
designed and developed embedded microprocessor
applications for several years, I found the lack
of those operators quite distressing. In this
article, I will discuss a generic implementation
of a bit operations package.
Consider the following hardware
register definition:
There are two ways to represent
each of these bits. Since the bits are really discrete
values, one could represent them thusly:
Type StatusReg_t Is
Record
TimeOut_Error : Boolean;
Xfer_Shift_Empty : Boolean;
Xfer_Hold_Empty : Boolean;
Break_Detect_Error : Boolean;
Framing_Error : Boolean;
Parity_Error : Boolean;
Overrun_Error : Boolean;
Data_Ready : Boolean;
End Record;
For StatusReg_t Use
Record
TimeOut_Error at 0 range 7..7;
Xfer_Shift_Empty at 0 range 6..6;
Xfer_Hold_Empty at 0 range 5..5;
Break_Detect_Error at 0 range 4..4;
Framing_Error at 0 range 3..3;
Parity_Error at 0 range 2..2;
Overrun_Error at 0 range 1..1;
Data_Ready at 0 range 0..0;
End Record;
For StatusReg_t'Size Use 8;
UART_StatusReg : StatusReg_t;
For UART_StatusReg Use At ... ; -- dependent upon System.Address definition
If ( UART_StatusReg.TimeOut_Error Or Else
UART_StatusReg.Break_Detect_Error Or Else
UART_StatusReg.Framing_Error Or Else
UART_StatusReg.Parity_Error Or Else
UART_StatusReg.Overrun_Error )
Then
-- Perform error processing
...
End If;
Or, if the code is being translated
from another language, it might make more expedient to
define the error codes (and register definition) more
like this:
Type Byte Is Range 0..2**8-1;
For Byte'Size Use 8;
Type StatusReg_t Is
(
Data_Ready,
Overrun_Error,
Parity_Error,
Framing_Error,
Break_Detect_Error,
Xfer_Hold_Reg_Empty,
Xfer_Shift_Reg_Empty,
Timeout_Error
);
For StatusReg_t Use
(
Data_Ready => 16#01#,
Overrun_Error => 16#02#,
Parity_Error => 16#04#,
Framing_Error => 16#08#,
Break_Detect_Error => 16#10#,
Xfer_Hold_Reg_Empty => 16#20#,
Xfer_Shift_Reg_Empty => 16#40#,
Timeout_Error => 16#80#
);
For StatusReg_t'Size Use Byte'Size;
Using a bit operations package, one
could check for errors this way:
Function Check_Status Is
Package Byte_BitOps Is New Bit_Operations( Item_t => Byte );
Function "Or"( L, R : In Byte ) Return Byte Renames Byte_BitOps."Or";
Function "And"( L, R : In Byte ) Return Byte Renames Byte_BitOps."And";
Function ToByte Is New Unchecked_Conversion( StatusReg_t, Byte );
UART_Error : Byte := ToByte( Timeout_Error ) Or
ToByte( Break_Detect_Error ) Or
ToByte( Framing_Error ) Or
ToByte( Parity_Error ) Or
ToByte( Overrun_Error );
UART_StatusReg : Byte;
For UART_StatusReg Use At ... ; -- dependent upon address specification
Begin -- Check_Status
If ( ( UART_StatusReg and UART_Error ) /= 0 )
Then
-- An error has occurred, handle the error condition
...
End If;
End Check_Status;
While the code in each example
provides equivalent functionality, there are clearly
reasons to code using one method or another. While there
are arguments both for and against each coding style, the
particular style used is often dictated by a coding
standards manual.
For those who would like to use the bit
masking approach, a generic Bit_Operations package is
provided.
--###############################################
--(c)Copyright 1999, DDC-I, Incorporated
--All Rights Reserved
--
--This code remains the property of DDC-I. It may be distributed freely
--as long as this copyright notice remains with the code.
--
--This code is supplied without warranty.
--###############################################
--File: bitOps.ads
--
--Description:
-- This file contains the generic package
Bit_Operations. This package
-- is designed to work with all integer types,
regardless of size.
--
--Disclaimer:
-- This package was written to be extremely
portable, though perhaps not
-- as fast as if the functions were implemented in
assembly language.
--
--Revision History:
-- 1.0 rmg Wed Dec 15 22:31:37 1999
-- Original Coding
--################################################
generic
type Item_t is private;
package Bit_Operations is
function "and"( L, R : in Item_t )
return Item_t;
function "or" ( L, R : in Item_t )
return Item_t;
function "xor"( L, R : in Item_t )
return Item_t;
function "not"( L : in Item_t ) return
Item_t;
end Bit_Operations;
with System, Unchecked_Conversion;
package body Bit_Operations Is
-- Definition of this type is completely
dependent upon the size attribute
-- of the type used to instantiate this generic
package
type BitArray_t is array( 1 .. Item_t'size ) of
boolean;
pragma pack ( BitArray_t );
function toBool is new Unchecked_Conversion(
Item_t, BitArray_t );
function toItem is new Unchecked_Conversion(
BitArray_t, Item_t );
-- In the four functions below, the code uses the
address attribute of
-- an instance of the variable passed into the
functions. This is done
-- on local variables so that should be no
problem with the implementation
-- of the function parameters
-- The algorithm is actually very simple, almost
brute force. The code
-- loops through each bit, performing the
indicated operation for the
-- corresponding bit in each parameter, storing
the result for later
-- return to the caller
function "and"( L, R : in Item_t )
return Item_t is
Begin -- "and"
return
( toItem( toBool( L ) and toBool( R ) ) );
end "and";
function "or" (
L, R : in Item_t ) return Item_t is
begin --
"or"
return
( toItem( toBool( L ) or toBool( R ) ) );
end "or";
function "xor"(
L, R : in Item_t ) return Item_t is
begin --
"xor"
return
( toItem( toBool( L ) or toBool( R ) ) );
end "xor";
function "not"( L
: In Item_t ) return Item_t is
begin --
"not"
Customer Quote:
"You have talented and dedicated people working for you. They are superlative. DRS appreciates their efforts and I personally am most grateful to be working with such an excellent group."