#include <stdio.h>
//PLL --
// 2 <= NF <= 513
// 2 <= NR <= 33
// NO, 1, 2, 2, 4
// 100M < FCO=FIN*NF/NR=clk*NO < 200M, (120M < FCO preferred)
// 1.6M < FIN/NR=clk*NO/NF < 15M
template<unsigned int a, unsigned int b>
struct algo_max
{
enum{ v = (a < b ? b : a) };
};
template<unsigned int a, unsigned int b>
struct algo_min
{
enum{ v = (a < b ? a : b) };
};
template<unsigned int a, unsigned int b>
struct algo_abs
{
enum{ v = (a < b ? b - a : a - b) };
};
template
<
unsigned int clk_bak,
unsigned int NO_bak,
unsigned int NF_bak,
unsigned int NR_bak,
unsigned int FCO,
unsigned int NO,
unsigned int fin,
unsigned int clk,
unsigned int NF,
unsigned int NF_max,
bool loop
>
struct clk2pll_NO_NF
{
enum{ NR = (FCO == 0 ? 0 : fin*NF/(FCO?FCO:1)) };
enum{ clk_temp_new = ((NR == 0 || NO == 0) ? 0 : fin*NF/(NR?NR:1)/(NO?NO:1)) };
enum{ better =
(NR >= 2 && NR <= 33)
&& (unsigned int)algo_abs<clk_temp_new, clk>::v < (unsigned int)algo_abs<clk_bak, clk>::v };
enum{ clk_new1 = (better ? clk_temp_new : clk_bak) };
enum{ NO_new1 = (better ? NO : NO_bak) };
enum{ NF_new1 = (better ? NF : NF_bak) };
enum{ NR_new1 = (better ? NR : NR_bak) };
typedef clk2pll_NO_NF<clk_new1, NO_new1, NF_new1, NR_new1, FCO, NO, fin, clk,
NF+1, NF_max, (NF <= NF_max)> type;
enum{ clk_new = type::clk_new };
enum{ NO_new = type::NO_new };
enum{ NF_new = type::NF_new };
enum{ NR_new = type::NR_new };
};
template
<
unsigned int clk_bak,
unsigned int NO_bak,
unsigned int NF_bak,
unsigned int NR_bak,
unsigned int FCO,
unsigned int NO,
unsigned int fin,
unsigned int clk,
unsigned int NF,
unsigned int NF_max
>
struct clk2pll_NO_NF<clk_bak, NO_bak, NF_bak, NR_bak, FCO, NO, fin, clk, NF, NF_max, false>
{
enum{ clk_new = clk_bak };
enum{ NO_new = NO_bak };
enum{ NF_new = NF_bak };
enum{ NR_new = NR_bak };
};
template
<
unsigned int clk_bak,
unsigned int NO_bak,
unsigned int NF_bak,
unsigned int NR_bak,
unsigned int fin,
unsigned int clk,
unsigned int NO,
unsigned int NO_min,
unsigned int NO_max,
unsigned int direction,
bool loop
>
struct clk2pll_NO
{
enum{
FCO = clk*NO,
NF_max = algo_min<FCO/1600000, 513>::v,
NF_min = algo_max<FCO/15000000, 2>::v };
typedef clk2pll_NO_NF<clk_bak, NO_bak, NF_bak, NR_bak, FCO, NO, fin, clk,
NF_min, NF_max, (NF_min <= NF_max)> type;
enum{ clk_new1 = type::clk_new };
enum{ NO_new1 = type::NO_new };
enum{ NF_new1 = type::NF_new };
enum{ NR_new1 = type::NR_new };
typedef clk2pll_NO<clk_new1, NO_new1, NF_new1, NR_new1,
fin, clk, NO+direction, NO_min, NO_max, direction,
(NO+direction >= NO_min && NO+direction <= NO_max)> type_next;
enum{ clk_new = type_next::clk_new };
enum{ NO_new = type_next::NO_new };
enum{ NF_new = type_next::NF_new };
enum{ NR_new = type_next::NR_new };
};
template
<
unsigned int clk_bak,
unsigned int NO_bak,
unsigned int NF_bak,
unsigned int NR_bak,
unsigned int fin,
unsigned int clk,
unsigned int NO_min,
unsigned int NO_max,
unsigned int direction,
bool loop
>
struct clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak, fin, clk, 3, NO_min, NO_max, direction, loop>
{
enum{ NO = 3 };
typedef clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak,
fin, clk, NO+direction, NO_min, NO_max, direction,
(NO+direction >= NO_min && NO+direction <= NO_max)> type_next;
enum{ clk_new = type_next::clk_new };
enum{ NO_new = type_next::NO_new };
enum{ NF_new = type_next::NF_new };
enum{ NR_new = type_next::NR_new };
};
template
<
unsigned int clk_bak,
unsigned int NO_bak,
unsigned int NF_bak,
unsigned int NR_bak,
unsigned int fin,
unsigned int clk,
unsigned int NO,
unsigned int NO_min,
unsigned int NO_max,
unsigned int direction
>
struct clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak, fin, clk, NO, NO_min, NO_max, direction, false>
{
enum{ clk_new = clk_bak };
enum{ NO_new = NO_bak };
enum{ NF_new = NF_bak };
enum{ NR_new = NR_bak };
};
template
<
unsigned int clk_bak,
unsigned int NO_bak,
unsigned int NF_bak,
unsigned int NR_bak,
unsigned int fin,
unsigned int clk,
unsigned int NO_min,
unsigned int NO_max,
unsigned int direction
>
struct clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak, fin, clk, 3, NO_min, NO_max, direction, false>
{
enum{ clk_new = clk_bak };
enum{ NO_new = NO_bak };
enum{ NF_new = NF_bak };
enum{ NR_new = NR_bak };
};
template<unsigned int fin, unsigned int clk>
struct clk2pll
{
enum{
NO_min = algo_max<1, (100000000+clk-1)/(clk?clk:1)>::v,
NO_max = algo_min<4, 200000000/(clk?clk:1)>::v,
NO_pre = algo_max<NO_min, 120000000/(clk?clk:1)>::v };
typedef clk2pll_NO<0, 0, 0, 0, fin, clk, NO_pre, NO_min, NO_max, +1, (NO_pre >= NO_min && NO_pre <= NO_max)> type0;
typedef clk2pll_NO<
type0::clk_new, type0::NO_new, type0::NF_new, type0::NR_new,
fin, clk, NO_pre, NO_min, NO_max, -1, (NO_pre >= NO_min && NO_pre <= NO_max)> type;
enum
{
OUT_DV = (type::NO_new == 1 ? 0 :
type::NO_new == 2 ? 1 :
type::NO_new == 4 ? 3 :
0),
IN_DV = type::NR_new - 2,
FB_DV = type::NF_new - 2
};
enum
{
PLLCON = (NO_min > NO_max || type::clk_new == 0 ? 0 : (OUT_DV << 14) + (IN_DV << 9) + FB_DV),
output_clock = (NO_min > NO_max ? 0 : type::clk_new)
};
};
template<unsigned int clk>
struct clk2pll<0, clk>
{
enum {
PLLCON = 0,
output_clock = 0
};
};
template<unsigned int fin>
struct clk2pll<fin, 0>
{
enum
{
PLLCON = 0,
output_clock = 0
};
};
int main()
{
typedef clk2pll<12000000, 48000000> clk_t;
printf("PLLCON = 0x%08x, output clock = %d\n",
clk_t::PLLCON,
clk_t::output_clock);
return 0;
}