<hardware>

<hardware>

[added with TR18015]


dynamic_address · hw_base · platform_traits · register_access · register_buffer · register_traits · static_address


Include the added header <hardware> so that you can write low-level I/O hardware drivers in C++ that are easier to port to different architectures.

Note that the use of this header does not require any additions to the C++ language, as none are mandated by TR18015.

#include <iohw.h>

namespace std {
    namespace hardware {
class hw_base
    {   // define hardware address type
public:
    enum access_mode
        {   // access modes
        random,
        read,
        read_write,
        write
        };
    enum device_bus
        {   // device register widths
        device8,
        device16,
        device32,
        device64
        };
    enum byte_order
        {   // endianness
        msb_low,
        msb_high
        };
    enum processor_bus
        {   // processor bus widths
        bus8,
        bus16,
        bus32,
        bus64
        };
    enum data_bus
        {   // type name for data bus
        };
    enum io_bus
        {   // type name for I/O bus
        };
    enum address_kind
        {   // addressing model
        is_static,
        is_dynamic
        };
    typedef ::ioreg address_type;  // HARDWARE DEPENDENT
    };

        // TEMPLATE CLASS static_address
template<hw_base::address_type Val>
    class static_address
    {   // specialization for value of type hw_base::address_type
public:
    enum
        {   // define value from template parameter
        value_ = Val
        };
    hw_base::address_type value() const
        {   // get value of this static address
        return (Val);
        }
    };

        // CLASS dynamic_address
class dynamic_address
    {   // store dynamic address
public:
    dynamic_address(hw_base::address_type address);
        :    value_(address)
        {   // construct from address
        }

    hw_base::address_type value() const
        {   // get value of stored address
        return (value_);
        }

    hw_base::address_type value_;
    };

        // CLASS platform_traits
class platform_traits
    {   // default platform traits (ALL CONTENTS OPTIONAL)
public:
    typedef hw_base::address_type address_holder;
    typedef hw_base::address_type processor_bus;
    enum
        {   // platform traits
        address_mode,
        processor_endianness,
        processor_bus_width
        };
    };

        // CLASS register_traits
class register_traits
    {   // default register traits (ALL CONTENTS OPTIONAL)
public:
    typedef unsigned int value_type;
    typedef hw_base::address_type address_holder;
    enum
        {   // platform traits
        address_mode,
        access_mode,
        endianness,
        device_bus_width
        };
    };

        // TEMPLATE CLASS register_access
template<class Reg_traits = register_traits,
    class Platform_traits = platform_traits>
    class register_access
    {   // access wrapper for a hardware I/O register
    typedef typename Platform_traits::address_holder Plat_t;
    typedef typename Reg_traits::address_holder Reg_t;

public:
    typedef typename Reg_traits::value_type value_type;

    register_access();
    register_access(const Plat_t& plat_addr);
    register_access(const Reg_t& reg_addr,
        const Plat_t& plat_addr);

    // access operators
    operator value_type() const;
    void operator=(value_type val);
    void operator|=(value_type val);
    void operator&=(value_type val);
    void operator^=(value_type val);

    // access functions
    value_type read() const;
    void write(value_type val);
    void or_with(value_type val);
    void and_with(value_type val);
    void xor_with(value_type val);
    };

        // TEMPLATE CLASS register_buffer
template<class Reg_traits = register_traits,
    class Platform_traits = platform_traits>
    class register_buffer
    {   // access wrapper for a hardware I/O register
    typedef typename Platform_traits::address_holder Plat_t;
    typedef typename Reg_traits::address_holder Reg_t;

public:
    typedef register_access<Reg_traits, Platform_traits> ref_type;
    typedef typename Reg_traits::value_type value_type;

    register_buffer();
    register_buffer(const Plat_t& plat_addr);
    register_buffer(const Reg_t& reg_addr,
        const Plat_t& plat_addr);

    // access operators
    ref_type operator[](ioindex_t idx) const;

    // access functions
    ref_type get_buffer_element(ioindex_t idx) const;
    };
    }    // namespace hardware
}    // namespace std

The header <hardware> defines a number of classes and templates. You should view this header as a prototype for defining the C++ interface to the atomic operations needed to express a low-level I/O hardware driver. It supplements the C header <iohw.h>. The facilities in this header are structured around a few basic concepts:

  • Class access_mode supplies the enumeration constants needed to describes the properties of I/O addresses. The member type address_type is used in other classes as the type of I/O addresses.
  • Class platform_traits supplies the enumeration constants needed to describes the properties of an I/O bus in general. The member type address_holder is used in other classes as the type of I/O addresses. Class register_traits performs a similar role for specific ports on an I/O bus.
  • Template class static_address wraps an I/O address whose value is known at translation time, while class dynamic_address waps one that might nit be known until program execution.
  • Class register_access supplies the member functions that call actual drivers to perform I/O operations. Similarly, class register_buffer supplies register_access objects for different elements of a hardware buffer.

In this implementation, all operations are performed by calling one of the five low-level functions (defined in <iohw.h>):

    iordbuf(_IOHW_NAME, idx)
    iowrbuf(_IOHW_NAME, idx, val)
    ioorbuf(_IOHW_NAME, idx, val)
    ioandbuf(_IOHW_NAME, idx, val)
    ioxorbuf(_IOHW_NAME, idx, val)

If the macro _IOHW_NAME is not defined when the header <hardware> is first included, the macro is defined as hardware. Further, the code assumes that all I/O occurs within a flat address space, where the effective port address is simply the sum of the platform address, the register address, and the index into a specific buffer. So you can write code such as:

#define KBD         0xffe0  // base address of keyboard ports
#define KBD_STATUS  0       // first of two adjacent ports
#define KBD_DATA    1       // second of two adjacent ports
#define KBD_DONE    0x80    // DONE status bit

extern unsigned int hardware_brd(ioindex_t idx);  // actual driver

typedef std::hardware::register_buffer<> buffer_t;

buffer_t::value_type getkbd()
    {   // read keyboard when ready
	buffer_t status(KBD, KBD_STATUS);
	buffer_t data(KBD, KBD_DATA);

    while ((status.read() & KBD_DONE) == 0)
        ;   // wait until character is present
    return (data);  // read character and clear DONE
    }

All actual driver calls will be to the function (or macro) hardware_brd.


See also the Table of Contents and the Index.

Copyright © 1992-2006 by P.J. Plauger. All rights reserved.

Last modified: 2013-12-21

comments powered by Disqus