
Hi Everyone, please share your comments/interest in a library that would ease writing hardware abstraction layers (HAL's) for complex devices (like large ASIC/FPGA). Here's the description: 1. Let's assume that we've got a memory mapped IO device, controlled via its registers. Each register is divided into few bitfields. Each bitfield controls separate functionality and has its properties, like: read/write/special access, numeral/enumerated value type, value signedness, valid value range(s) etc. All these are typically listed in device's specification: +----------------+--------------+ |Register offset |Register name | +----------------+--------------+ |0x12FE |CONTROL_REG1 | +----------------+--------------+ +--------------+--------------+-------+-----------+------------+ |Bits occupied |Bitfield name |Access |Signedness |Value range | +--------------+--------------+-------+-----------+------------+ |31:25 |TEMPERATURE |RA |SIGNED |- | +--------------+--------------+-------+-----------+------------+ |24:1 |FAN_RPM |WA |UNSIGNED |0:6000 | +--------------+--------------+-------+-----------+------------+ |0:0 |ENABLE |RWA |UNSIGNED |0:1 | +--------------+--------------+-------+-----------+------------+ Note: RA: Read Access, WA: Write Access, RWA: Read/Write Access 2. Let's assume that there's a whole family of these ASICs (subsequent generations/revisions). Each new revision differs from previous one only in few details. The point is that we may have few thousand bitfields per ASIC plus revision changes. Coding such amount of information "by hand" is obviously error-prone. Using text processing (perl/python) to translate the specification to code may obfuscate it's nice tabular format (and may miss features/optimisation offered by metaprogramming). 3. Our goal is to create an abstract interface (HAL). Its implementations would "talk to" corresponding bitfields via inner (intermediate) interface. The purpose of that intermediate code would be to: - present bitfield's name exactly "as is in specification", - extract bitfield's value from its register in a typed, endiannes-correct manner, - enforce correct usage (like forbidding writing read-only fields), - provide value validation, - provide value conversion (enumeration-to-numeral etc.), - provide array-style access if needed, - provide debugging features, - and few more cherries on top. The key point is to have most of this code generated from the specification using only simple regexp (to the form required by proposed library). 4. Code snippet (using specification from point 1) - simple and simplified: Let's create an interface with one member function "operate". Implementation of this function will "talk to" bitfields of CONTROL_REG1 through get<BITFIELD> and set<BITFIELD> functions. These functions (and few other utilities) are being generated by the proposed library, using provided metadata. // Definition of HAL interface --------------------------- namespace some_subsystem { namespace driver { class some_controller { public: virtual bool operate() = 0; }; }} // Definition of bitfields (metadata) -------------------- // Concrete device definition enclosed in a dedicated namespace namespace some_subsystem { namespace driver { namespace asic_ver_123 { // Legend: // BOOST_HAL_DEF_REGISTER_BEG(REGISTER_OFFSET, REGISTER_NAME) // BOOST_HAL_DEF_FIELD(MSBIT, LSBIT, BITFIELD_NAME, ACCESS, SIGNEDNESS, VALIDATOR) // BOOST_HAL_DEF_REGISTER_END() BOOST_HAL_DEF_REGISTER_BEG(0x12FE, CONTROL_REG1) // Register definition BOOST_HAL_DEF_FIELD(30, 25, TEMPERATURE, RA, SIGNED, CTP_ESC(no_check)) // CTP_ESC meant for commas escaping BOOST_HAL_DEF_FIELD(24, 1, FAN_RPM, WA, UNSIGNED, CTP_ESC(range<0, 6000>)) BOOST_HAL_DEF_FIELD(0, 0, ENABLE, WA, UNSIGNED, CTP_ESC(range<0, 1>)) BOOST_HAL_DEF_REGISTER_END() }}} // Definition of HAL implementation ---------------------- namespace some_subsystem { namespace driver { namespace asic_ver_123 { class some_controller_impl : public some_controller { public: virtual bool operate() { bool result = false; // Suitable bitfield type is deduced from its definition (but can be manually overridden) // In this case it will be signed char or bigger (CONTROL_REG1::TEMPERATURE = 6 bits) suitable<CONTROL_REG1::TEMPERATURE>::type temperature = 0; // Library automatically generates the bitfield's getter // which reads the register, masks & shifts unrelated bits, // performs (optional) value conversion and (mandatory) cast. // Debugging/logging also possible result = get<CONTROL_REG1::TEMPERATURE>(temperature); // Pass "temperature" by reference // This would not compile, CONTROL_REG1::TEMPERATURE is read-only // result |= set<CONTROL_REG1::TEMPERATURE>(temperature); // Compile error if(true == result && temperature > 20) { // Library automatically generates the bitfield's setter // which performs read-modify-write with value validation result |= set<CONTROL_REG1::FAN_RPM>(1000); result |= set<CONTROL_REG1::ENABLE>(true); // This would return "false" (7000 is an invalid value for FAN_RPM) // result |= set<CONTROL_REG1::FAN_RPM>(7000); } else { result |= set<CONTROL_REG1::FAN_RPM>(0); result |= set<CONTROL_REG1::ENABLE>(false); } return result; } }; }}} // End of snippet ---------------------------------------------- This snippet shows the very basic functionality, anyway please share your opinions if the idea is catchy and suitable for boost! Best regards, -- Szymon Gutaj