diff --git a/himbaechel/uarch/gatemate/bitstream.cc b/himbaechel/uarch/gatemate/bitstream.cc index 77137715..f2dbb711 100644 --- a/himbaechel/uarch/gatemate/bitstream.cc +++ b/himbaechel/uarch/gatemate/bitstream.cc @@ -138,6 +138,17 @@ struct BitstreamBackend cc.configs[0].add_word(stringf("GLBOUT.GLB%d_EN",l.z), int_to_bitvector(1,1)); } break; + case id_PLL.index: + { + Loc l = ctx->getBelLocation(cell.second->bel); + cc.configs[0].add_word(stringf("PLL%d.CLK_OUT_EN",l.z-4), int_to_bitvector(1,1)); + cc.configs[0].add_word(stringf("PLL%d.PLL_EN",l.z-4), int_to_bitvector(1,1)); + cc.configs[0].add_word(stringf("PLL%d.PLL_RST",l.z-4), int_to_bitvector(1,1)); + for (auto &p : params) { + cc.configs[0].add_word(stringf("PLL%d.%s", l.z-4, p.first.c_str(ctx)), p.second.as_bits()); + } + } + break; default: log_error("Unhandled cell %s of type %s\n", cell.second.get()->name.c_str(ctx), cell.second->type.c_str(ctx)); diff --git a/himbaechel/uarch/gatemate/constids.inc b/himbaechel/uarch/gatemate/constids.inc index 56ff3115..508d5c1a 100644 --- a/himbaechel/uarch/gatemate/constids.inc +++ b/himbaechel/uarch/gatemate/constids.inc @@ -134,3 +134,30 @@ X(D2) X(D3) X(S0) X(S1) + +X(CC_PLL) +X(CC_PLL_ADV) +X(PLL) +X(CLK_REF) +X(USR_CLK_REF) +X(USR_SEL_A_B) +X(CLK_FEEDBACK) +X(USR_LOCKED_STDY_RST) +X(CLK0) +X(CLK90) +X(CLK180) +X(CLK270) +X(CLK_REF_OUT) +X(USR_PLL_LOCKED_STDY) +X(USR_PLL_LOCKED) +X(REF_CLK) +X(OUT_CLK) +X(PERF_MD) +X(LOCK_REQ) +X(CLK270_DOUB) +X(CLK180_DOUB) +X(LOW_JITTER) +X(CI_FILTER_CONST) +X(CP_FILTER_CONST) +X(PLL_CFG_A) +X(PLL_CFG_B) diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc index 4b10ee13..87bf3faf 100644 --- a/himbaechel/uarch/gatemate/pack.cc +++ b/himbaechel/uarch/gatemate/pack.cc @@ -17,6 +17,8 @@ * */ +#include + #include "pack.h" #define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc" @@ -468,6 +470,94 @@ void GateMatePacker::pack_bufg() } } +template double double_or_default(const dict &ct, const KeyType &key, double def = 0) +{ + auto found = ct.find(key); + if (found == ct.end()) + return def; + else { + if (found->second.is_string) { + try { + return std::stod(found->second.as_string()); + } catch (std::invalid_argument &e) { + log_error("Expecting numeric value but got '%s'.\n", found->second.as_string().c_str()); + } + } else + return double(found->second.as_int64()); + } +}; + +void GateMatePacker::pack_pll() +{ + log_info("Packing PLLss..\n"); + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (!ci.type.in(id_CC_PLL)) + continue; + + disconnect_if_gnd(&ci, id_CLK_REF); + disconnect_if_gnd(&ci, id_USR_CLK_REF); + disconnect_if_gnd(&ci, id_CLK_FEEDBACK); + disconnect_if_gnd(&ci, id_USR_LOCKED_STDY_RST); + + ci.params[id_LOCK_REQ] = Property(int_or_default(ci.params, id_LOCK_REQ, 1),1); + ci.params[id_CLK180_DOUB] = Property(int_or_default(ci.params, id_CLK180_DOUB, 0),1); + ci.params[id_CLK270_DOUB] = Property(int_or_default(ci.params, id_CLK270_DOUB, 0),1); + std::string mode = str_or_default(ci.params, id_PERF_MD, "SPEED"); + boost::algorithm::to_upper(mode); + int perf_md; + if (mode == "LOWPOWER") perf_md = 1; + else if (mode == "ECONOMY") perf_md = 2; + else if (mode == "SPEED") perf_md = 3; + else log_error("Unknown PERF_MD parameter value '%s' for cell %s.\n", mode.c_str(), ci.name.c_str(ctx)); + + + double ref_clk = double_or_default(ci.params, id_REF_CLK, 0.0); + if (ref_clk <= 0 || ref_clk > 125) + log_error("REF_CLK parameter is out of range (0,125.00].\n"); + + double max_freq = 0.0; + switch(perf_md) { + case 1: max_freq = 250.00; break; + case 2: max_freq = 312.50; break; + case 3: max_freq = 416.75; break; + } + + double out_clk = double_or_default(ci.params, id_OUT_CLK, 0.0); + if (out_clk <= 0 || out_clk > max_freq) + log_error("OUT_CLK parameter is out of range (0,%.2lf].\n", max_freq); + + // For 10 MHz - > 25 MHz + ci.params[ctx->id("CFG_A.AO_SW")] = Property(0b01000,5); + ci.params[ctx->id("CFG_A.CI_FILTER_CONST")] = Property(0b00010,5); + ci.params[ctx->id("CFG_A.COARSE_TUNE")] = Property(0b100,3); + ci.params[ctx->id("CFG_A.CP_FILTER_CONST")] = Property(0b00100,5); + ci.params[ctx->id("CFG_A.EN_COARSE_TUNE")] = Property(0b1,1); + ci.params[ctx->id("CFG_A.FAST_LOCK")] = Property(0b1,1); + ci.params[ctx->id("CFG_A.FILTER_SHIFT")] = Property(0b10,2); + ci.params[ctx->id("CFG_A.FINE_TUNE")] = Property(0b00011001000,11); + ci.params[ctx->id("CFG_A.K")] = Property(0b000000000001,12); + ci.params[ctx->id("CFG_A.M1")] = Property(0b000010,6); + ci.params[ctx->id("CFG_A.M2")] = Property(0b0000001001,10); + ci.params[ctx->id("CFG_A.N1")] = Property(0b001001,6); + ci.params[ctx->id("CFG_A.N2")] = Property(0b0000001010,10); + ci.params[ctx->id("CFG_A.PDIV0_MUX")] = Property(0b1,1); + ci.params[ctx->id("CFG_A.PDIV1_SEL")] = Property(0b1,1); + ci.params[ctx->id("CFG_A.SAR_LIMIT")] = Property(0b010,3); + + // Remove all not propagated parameters + ci.unsetParam(id_PERF_MD); + ci.unsetParam(id_REF_CLK); + ci.unsetParam(id_OUT_CLK); + ci.unsetParam(id_LOW_JITTER); + ci.unsetParam(id_CI_FILTER_CONST); + ci.unsetParam(id_CP_FILTER_CONST); + //ci.unsetParam(id_PLL_CFG_A); + //ci.unsetParam(id_PLL_CFG_B); + + ci.type = id_PLL; + } +} void GateMatePacker::pack_constants() { log_info("Packing constants..\n"); @@ -517,6 +607,7 @@ void GateMateImpl::pack() GateMatePacker packer(ctx, this); packer.pack_constants(); packer.pack_io(); + packer.pack_pll(); packer.pack_bufg(); packer.pack_cpe(); packer.remove_constants(); diff --git a/himbaechel/uarch/gatemate/pack.h b/himbaechel/uarch/gatemate/pack.h index d981d8ae..bf08399b 100644 --- a/himbaechel/uarch/gatemate/pack.h +++ b/himbaechel/uarch/gatemate/pack.h @@ -31,6 +31,7 @@ struct GateMatePacker void pack_io(); void pack_cpe(); void pack_bufg(); + void pack_pll(); void pack_constants(); void disconnect_if_gnd(CellInfo *cell, IdString input);