Pack Multiple Fields into a 16-bit Control Register

Code

#include <stdio.h>
#include <stdint.h>

#include <stdio.h>
#include <stdint.h>

#define MODE_START_POS      0U
#define SPEED_START_POS     3U
#define STATUS_START_POS    10U

#define MODE_END_POS        2U
#define SPEED_END_POS       7U
#define STATUS_END_POS      15U

#define POS_MASK(val)       ((1 << (val + 1)) - 1)

// Define macros here
#define SET_MODE(val)       (uint16_t)((val & POS_MASK(MODE_END_POS)) << MODE_START_POS)
#define SET_SPEED(val)      (uint16_t)((val & POS_MASK(SPEED_END_POS)) << SPEED_START_POS)
#define SET_STATUS(val)     (uint16_t)((val & POS_MASK(STATUS_END_POS)) << STATUS_START_POS)

uint16_t pack_register(uint8_t mode, uint8_t speed, uint8_t status) 
{
    uint16_t reg_val = 0;
    reg_val |= SET_MODE(mode);
    reg_val |= SET_SPEED(speed);
    reg_val |= SET_STATUS(status);
    return reg_val;
}

int main() 
{
    uint8_t mode, speed, status;
    scanf("%hhu %hhu %hhu", &mode, &speed, &status);

    uint16_t reg = pack_register(mode, speed, status);
    printf("%u", reg);
    return 0;
}

Solving Approach

This C program demonstrates Bit Packing, a common technique used in firmware development and communication protocols (like CAN bus) to store multiple distinct values within a single 16-bit register. This is highly memory-efficient for hardware-level programming.

1. Register Memory Layout

The code packs three separate values into one uint16_t (2-byte) variable. The layout is defined by the start and end positions:

Field

Bit Range

Width

Purpose

Mode

0 to 23 bitsLow-level configuration state.

Speed

3 to 75 bitsCurrent speed or velocity value.

Empty

8 to 92 bitsReserved / Unused (will be 0).

Status

10 to 156 bitsHigh-level system status flags.

2. Core Logic Components

A. The Masking Macro (POS_MASK)

To prevent one value from "bleeding" into the next field, the code uses a mask.

 

Mask = (1 << (end_pos + 1)) - 1

 

This formula creates a string of binary 1s from bit 0 up to the specified end position. For example, a mask for MODE_END_POS (2) results in binary 111 (decimal 7), ensuring only the first 3 bits of the input are used.

B. Shifting and Packing

The program follows a three-step process for each data field:

  1. Masking: The input value is "cleaned" using the & (AND) operator so that only the allowed bits remain.

  2. Shifting: The cleaned value is moved to its correct starting bit position using the << (Left Shift) operator.

  3. Merging: The shifted value is combined into the final register using the | (OR) operator. This "stamps" the bits into the register without overwriting the fields already placed there.

3. Technical Advantages

  • Memory Efficiency: Instead of using three separate bytes (24 bits) to store these variables, they are compressed into a single 16-bit word.

  • Hardware Compatibility: This structure mimics how hardware registers are physically mapped in microcontrollers (like those used in BMS or motor controllers).

  • Speed: Bitwise operations are performed directly by the CPU in a single clock cycle, making this much faster than higher-level data structures.

4. Implementation Note

The use of uint16_t and uint8_t from <stdint.h> ensures that the code behaves consistently across different computer architectures, which is critical for DEV/FW (Firmware) environments where bit-exactness is mandatory.

Upvote
Downvote
Loading...

Input

3 10 12

Expected Output

12371