• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
rogue_distribute_value(uint64_t source,const struct rogue_rangelist * rangelist,size_t dest_size,uint8_t dest_bytes[dest_size])49 bool 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