summaryrefslogtreecommitdiffstats
path: root/src/import/generic/memory/lib/utils/conversions.H
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/generic/memory/lib/utils/conversions.H')
-rw-r--r--src/import/generic/memory/lib/utils/conversions.H337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/import/generic/memory/lib/utils/conversions.H b/src/import/generic/memory/lib/utils/conversions.H
new file mode 100644
index 000000000..efbb53a47
--- /dev/null
+++ b/src/import/generic/memory/lib/utils/conversions.H
@@ -0,0 +1,337 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/generic/memory/lib/utils/conversions.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file conversions.H
+/// @brief Functions to convert units
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_CONVERSIONS_H_
+#define _MSS_CONVERSIONS_H_
+
+#include <vector>
+#include <fapi2.H>
+#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
+#include <generic/memory/lib/utils/find.H>
+
+///
+/// @brief Dereferences pointer of the vector's underlying data
+// and casts it to uint8_t[Y] that FAPI_ATTR_SET is expecting by deduction
+/// @param[in] X is the input vector
+/// @param[in] Y is the size of the vector
+/// @warn compiler doesn't like the use of vector method size() for the second param
+///
+#define UINT8_VECTOR_TO_1D_ARRAY(X, Y)\
+ reinterpret_cast<uint8_t(&)[Y]>(*X.data())
+
+///
+/// @brief Dereferences pointer of the vector's underlying data
+// and casts it to uint16_t[Y] that FAPI_ATTR_SET is expecting by deduction
+/// @param[in] X is the input vector
+/// @param[in] Y is the size of the vector
+/// @warn compiler doesn't like the use of vector method size() for the second param
+///
+#define UINT16_VECTOR_TO_1D_ARRAY(X, Y)\
+ reinterpret_cast<uint16_t(&)[Y]>(*X.data())
+
+///
+/// @brief Dereferences pointer of the vector's underlying data
+// and casts it to uint32_t[Y] that FAPI_ATTR_SET is expecting by deduction
+/// @param[in] X is the input vector
+/// @param[in] Y is the size of the vector
+/// @warn compiler doesn't like the use of vector method size() for the second param
+///
+#define UINT32_VECTOR_TO_1D_ARRAY(X, Y)\
+ reinterpret_cast<uint32_t(&)[Y]>(*X.data())
+
+
+// Mutiplication factor to go from clocks to simcycles.
+// Is this just 2400 speed or does this hold for all? BRS
+static const uint64_t SIM_CYCLES_PER_CYCLE = 8;
+
+namespace mss
+{
+
+namespace dram_freq
+{
+//
+// DRAM clock and frequency information
+//
+static const std::vector<std::pair<uint64_t, uint64_t>> FREQ_TO_CLOCK_PERIOD =
+{
+ {DIMM_SPEED_1600, 1250}, // DDR4
+ {DIMM_SPEED_1866, 1071}, // DDR4
+ {DIMM_SPEED_2133, 937}, // DDR4
+ {DIMM_SPEED_2400, 833}, // DDR4
+ {DIMM_SPEED_2666, 750}, // DDR4
+ {DIMM_SPEED_2933, 682}, // DDR4
+ {DIMM_SPEED_3200, 625}, // DDR4/5
+ {DIMM_SPEED_3600, 555}, // DDR5
+ {DIMM_SPEED_4000, 500}, // DDR5
+ {DIMM_SPEED_4400, 454}, // DDR5
+ {DIMM_SPEED_4800, 416}, // DDR5
+};
+}
+
+///
+/// @brief Return the number of picoseconds
+/// @tparam T input type
+/// @tparam OT output type
+/// @param[in] i_speed_grade input in MegaTransfers per second (MT/s)
+/// @param[out] o_tCK_in_ps
+/// @return FAPI2_RC_SUCCESS if okay
+///
+template<typename T, typename OT>
+inline fapi2::ReturnCode freq_to_ps(const T i_speed_grade, OT& o_tCK_in_ps )
+{
+ // We need to have at least two bytes of data, due to the sizes of the frequencies and clock periods
+ constexpr size_t MIN_BYTE_SIZE = 2;
+ static_assert(sizeof(T) >= MIN_BYTE_SIZE && sizeof(OT) >= MIN_BYTE_SIZE,
+ "Input and output must be at least 2 bytes in length");
+
+ // Temporary variables to help with the conversion
+ const uint64_t l_input = static_cast<uint64_t>(i_speed_grade);
+ uint64_t l_output = 0;
+
+ FAPI_ASSERT(find_value_from_key(dram_freq::FREQ_TO_CLOCK_PERIOD, l_input, l_output),
+ fapi2::MSS_INVALID_FREQUENCY()
+ .set_FREQ(l_input),
+ "Frequency %u does not have an associated clock period", l_input);
+
+ // Cast the output type
+ o_tCK_in_ps = static_cast<OT>(l_output);
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return the number in MT/s
+/// @tparam T input type
+/// @tparam OT output type
+/// @param[in] i_time_in_ps time in picoseconds
+/// @param[out] o_speed_grade transfer rate in MT/s
+/// @return FAPI2_RC_SUCCESS if okay
+///
+template<typename T, typename OT>
+fapi2::ReturnCode ps_to_freq(const T i_time_in_ps, OT& o_speed_grade)
+{
+ // We need to have at least two bytes of data, due to the sizes of the frequencies and clock periods
+ constexpr size_t MIN_BYTE_SIZE = 2;
+ static_assert(sizeof(T) >= MIN_BYTE_SIZE && sizeof(OT) >= MIN_BYTE_SIZE,
+ "Input and output must be at least 2 bytes in length");
+
+ // Temporary variables to help with the conversion
+ const uint64_t l_input = static_cast<uint64_t>(i_time_in_ps);
+ uint64_t l_output = 0;
+
+ FAPI_ASSERT(find_key_from_value(dram_freq::FREQ_TO_CLOCK_PERIOD, l_input, l_output),
+ fapi2::MSS_INVALID_CLOCK_PERIOD()
+ .set_CLOCK_PERIOD(l_input),
+ "Clock period %u does not have an associated frequency", l_input);
+
+ // Cast the output type
+ o_speed_grade = static_cast<OT>(l_output);
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+
+}
+
+///
+/// @brief Translate from cycles to sim cycles
+/// @param[in] i_cycles the cycles to translate
+/// @return uint64_t, the number of sim cycles.
+///
+inline uint64_t cycles_to_simcycles( const uint64_t i_cycles )
+{
+ // Is this always the case or do we need the freq to really figure this out?
+ return i_cycles * SIM_CYCLES_PER_CYCLE;
+}
+
+///
+/// @brief Return the number of cycles contained in a count of picoseconds
+/// @tparam T clock period input type
+/// @tparam OT the output type, derrived from the parameters
+/// @param[in] i_clock_period clock period in PS
+/// @param[in] i_ps the number of picoseconds to convert
+/// @return the number of cycles
+///
+template< typename T, typename OT >
+inline OT ps_to_cycles(const T i_clock_period, const OT i_ps)
+{
+ // Casts the clock period to be in OT type to avoid any weird math issues
+ const auto l_divisor = static_cast<OT>(i_clock_period);
+
+ const OT l_rounder = (i_ps < 0) ? -1 : 1;
+
+ // Ensure we don't divide by 0
+ const OT l_quotient = i_ps / ((i_clock_period == 0) ? l_rounder : l_divisor);
+ const OT l_remainder = i_ps % ((i_clock_period == 0) ? 1 : l_divisor);
+
+ // Make sure we add a cycle if there wasn't an even number of cycles in the input
+ FAPI_INF("converting %llups to %llu cycles", i_ps, l_quotient + (l_remainder == 0 ? 0 : l_rounder));
+
+ return l_quotient + (l_remainder == 0 ? 0 : l_rounder);
+}
+
+///
+/// @brief Return the number of ps contained in a count of cycles
+/// @param[in] i_clock_period
+/// @param[in] i_cycles the number of cycles to convert
+/// @return uint64_t, the number of picoseconds
+///
+inline uint64_t cycles_to_ps(const uint64_t i_clock_period, const uint64_t i_cycles)
+{
+ const auto l_ps = i_cycles * i_clock_period;
+ FAPI_INF("converting %llu cycles to %llups", i_cycles, l_ps );
+ return l_ps;
+}
+
+///
+/// @brief Return the number of cycles contained in a count of microseconds
+/// @param[in] i_clock_period the clock period in PS
+/// @param[in] i_us the number of microseconds to convert
+/// @return uint64_t, the number of cycles
+///
+inline uint64_t us_to_cycles(const uint64_t i_clock_period, const uint64_t i_us)
+{
+ return ps_to_cycles(i_clock_period, i_us * CONVERT_PS_IN_A_US);
+}
+
+///
+/// @brief Return the number of cycles contained in a count of nanoseconds
+/// @param[in] i_clock_period the clock period in PS
+/// @param[in] i_ps the number of nanoseconds to convert
+/// @return uint64_t, the number of cycles
+///
+inline uint64_t ns_to_cycles(const uint64_t i_clock_period, const uint64_t i_ns)
+{
+ return ps_to_cycles(i_clock_period, i_ns * CONVERT_PS_IN_A_NS);
+}
+
+///
+/// @brief Return the number of microseconds contained in a count of cycles
+/// @tparam D the time conversion (NS_IN_PS, etc)
+/// @param[in] i_clock_period the clock period in PS
+/// @param[in] i_cycles the number of cycles to convert
+/// @return uint64_t, the number of microseconds
+///
+template< uint64_t D >
+inline uint64_t cycles_to_time(const uint64_t i_clock_period, const uint64_t i_cycles)
+{
+ // Hoping the compiler figures out how to do these together.
+ const auto l_dividend = cycles_to_ps(i_clock_period, i_cycles);
+ constexpr uint64_t DIVISOR = ((D == 0) ? 1 : D);
+ const uint64_t l_quotient = l_dividend / DIVISOR;
+ const uint64_t l_remainder = l_dividend % DIVISOR;
+
+ // Make sure we add time if there wasn't an even number of cycles
+ return l_quotient + (l_remainder == 0 ? 0 : 1);
+}
+
+///
+/// @brief Return the number of nanoseconds contained in a count of cycles
+/// @tparam T the target type
+/// @tparam MC memory controller type
+/// @param[in] i_clock_period the clock period in PS
+/// @param[in] i_cycles the number of cycles to convert
+/// @return uint64_t, the number of nanoseconds
+///
+inline uint64_t cycles_to_ns(const uint64_t i_clock_period, const uint64_t i_cycles)
+{
+ const uint64_t l_ns = cycles_to_time<CONVERT_PS_IN_A_NS>(i_clock_period, i_cycles);
+ FAPI_INF("converting %llu cycles to %lluns", i_cycles, l_ns);
+
+ return l_ns;
+}
+
+///
+/// @brief Return the number of microseconds contained in a count of cycles
+/// @param[in] i_clock_period the clock period in PS
+/// @param[in] i_cycles the number of cycles to convert
+/// @return uint64_t, the number of microseconds
+///
+inline uint64_t cycles_to_us(const uint64_t i_clock_period, const uint64_t i_cycles)
+{
+ const uint64_t l_us = cycles_to_time<CONVERT_PS_IN_A_US>(i_clock_period, i_cycles);
+ FAPI_INF("converting %llu cycles to %lluus", i_cycles, l_us);
+
+ return l_us;
+}
+
+///
+/// @brief Convert nanoseconds to picoseconds
+/// @tparam T input and output type
+/// @param[in] i_time_in_ns time in nanoseconds
+/// @return time in picoseconds
+///
+template<typename T>
+inline T ns_to_ps(const T i_time_in_ns)
+{
+ return i_time_in_ns * CONVERT_PS_IN_A_NS;
+}
+
+///
+/// @brief Convert nanoseconds to picoseconds
+/// @tparam T input and output type
+/// @param[in] i_time_in_ps time in picoseconds
+/// @return time in nanoseconds
+/// @note rounds up
+///
+template<typename T>
+inline T ps_to_ns(const T i_time_in_ps)
+{
+ T remainder = i_time_in_ps % CONVERT_PS_IN_A_NS;
+ T l_time_in_ns = i_time_in_ps / CONVERT_PS_IN_A_NS;
+
+ // Round up if remainder isn't even
+ return l_time_in_ns + ( remainder == 0 ? 0 : 1 );
+}
+
+///
+/// @brief Return the maximum of two values *in clocks*, the first in clocks the second in ns
+/// @param[in] i_clock_period the clock period in PS
+/// @param[in] i_clocks a value in clocks
+/// @param[in] i_time a value in nanoseconds
+/// @return max( iclocks nCK, i_time ) in clocks
+///
+inline uint64_t max_ck_ns(const uint64_t i_clock_period, const uint64_t i_clocks, const uint64_t i_time)
+{
+ return std::max( i_clocks, ns_to_cycles(i_clock_period, i_time) );
+}
+
+} // mss namespace
+
+#endif
OpenPOWER on IntegriCloud