1/* 2 * Copyright © 2022 Imagination Technologies Ltd. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include <assert.h> 25#include <inttypes.h> 26#include <stdbool.h> 27#include <stddef.h> 28#include <stdint.h> 29 30#include "rogue_util.h" 31#include "util/macros.h" 32 33/** 34 * \file rogue_util.c 35 * 36 * \brief Contains compiler utility and helper functions. 37 */ 38 39/** 40 * \brief Splits and distributes value "source" across "dest_bytes" according to 41 * the ranges specified (from MSB to LSB). 42 * 43 * \param[in] source The source value to be distributed. 44 * \param[in] rangelist The rangelist describing how to distribute "source". 45 * \param[in] dest_size The size of the destination in bytes. 46 * \param[in] dest_bytes The destination byte array. 47 * \return false if invalid inputs were provided, else true. 48 */ 49bool rogue_distribute_value(uint64_t source, 50 const struct rogue_rangelist *rangelist, 51 size_t dest_size, 52 uint8_t dest_bytes[dest_size]) 53{ 54 size_t total_bits_left = 0U; 55 56 /* Check that "value" is actually representable in "total_bits" bits. */ 57 total_bits_left = rogue_rangelist_bits(rangelist); 58 assert(util_last_bit64(source) <= total_bits_left && 59 "Value cannot be represented."); 60 61 /* Iterate over each range. */ 62 for (size_t u = 0U; u < rangelist->num_ranges; ++u) { 63 struct rogue_bitrange *range = &rangelist->ranges[u]; 64 65 size_t dest_bit = range->start; 66 size_t bits_left = range->num; 67 size_t bytes_covered = rogue_bytes_spilled(range) + 1; 68 size_t base_byte = rogue_byte_index(range, dest_size); 69 70 /* Iterate over each byte covered by the current range. */ 71 for (size_t b = 0U; b < bytes_covered; ++b) { 72 size_t max_bits = rogue_max_bits(dest_bit); 73 size_t bits_to_place = MIN2(bits_left, max_bits); 74 size_t dest_byte_bit = dest_bit % 8; 75 size_t source_bit = total_bits_left - 1; 76 77 /* Mask and shuffle the source value so that it'll fit into the 78 * correct place in the destination byte: 79 */ 80 81 /* Extract bits. */ 82 uint64_t value_masked = 83 (source & BITMASK64_N(source_bit, bits_to_place)); 84 /* Shift all the way right. */ 85 value_masked >>= (1 + source_bit - bits_to_place); 86 /* Shift left to the correct position. */ 87 value_masked <<= (1 + dest_byte_bit - bits_to_place); 88 /* Place value into byte. */ 89 dest_bytes[base_byte + b] |= (value_masked & 0xff); 90 91 dest_bit -= max_bits; 92 bits_left -= bits_to_place; 93 total_bits_left -= bits_to_place; 94 } 95 } 96 97 return true; 98} 99