diff options
Diffstat (limited to 'ice40')
-rw-r--r-- | ice40/arch.cc | 80 | ||||
-rw-r--r-- | ice40/arch.h | 12 | ||||
-rw-r--r-- | ice40/arch_pybindings.cc | 4 | ||||
-rw-r--r-- | ice40/pack.cc | 11 |
4 files changed, 85 insertions, 22 deletions
diff --git a/ice40/arch.cc b/ice40/arch.cc index b5e20566..2a9e167b 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -856,8 +856,9 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort } // Get the port class, also setting clockPort to associated clock if applicable -TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const +TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const { + clockInfoCount = 0; if (cell->type == id_ICESTORM_LC) { if (port == id_CLK) return TMG_CLOCK_INPUT; @@ -870,18 +871,15 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id if (cell->lcInfo.inputCount == 0) return TMG_IGNORE; if (cell->lcInfo.dffEnable) { - clockPort = id_CLK; + clockInfoCount = 1; return TMG_REGISTER_OUTPUT; - } - else + } else return TMG_COMB_OUTPUT; - } - else { + } else { if (cell->lcInfo.dffEnable) { - clockPort = id_CLK; + clockInfoCount = 1; return TMG_REGISTER_INPUT; - } - else + } else return TMG_COMB_INPUT; } } else if (cell->type == id_ICESTORM_RAM) { @@ -889,23 +887,22 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id if (port == id_RCLK || port == id_WCLK) return TMG_CLOCK_INPUT; - if (port.str(this)[0] == 'R') - clockPort = id_RCLK; - else - clockPort = id_WCLK; + clockInfoCount = 1; if (cell->ports.at(port).type == PORT_OUT) return TMG_REGISTER_OUTPUT; else return TMG_REGISTER_INPUT; } else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) { - clockPort = id_CLK; - if (port == id_CLK) + if (port == id_CLK || port == id_CLOCK) return TMG_CLOCK_INPUT; - else if (cell->ports.at(port).type == PORT_OUT) - return TMG_REGISTER_OUTPUT; - else - return TMG_REGISTER_INPUT; + else { + clockInfoCount = 1; + if (cell->ports.at(port).type == PORT_OUT) + return TMG_REGISTER_OUTPUT; + else + return TMG_REGISTER_INPUT; + } } else if (cell->type == id_SB_IO) { if (port == id_D_IN_0 || port == id_D_IN_1) return TMG_STARTPOINT; @@ -934,6 +931,51 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); } +TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const +{ + TimingClockingInfo info; + if (cell->type == id_ICESTORM_LC) { + info.clock_port = id_CLK; + info.edge = cell->lcInfo.negClk ? FALLING_EDGE : RISING_EDGE; + if (port == id_O) { + bool has_clktoq = getCellDelay(cell, id_CLK, id_O, info.clockToQ); + NPNR_ASSERT(has_clktoq); + } else { + info.setup.delay = 100; + info.hold.delay = 0; + } + } else if (cell->type == id_ICESTORM_RAM) { + if (port.str(this)[0] == 'R') { + info.clock_port = id_RCLK; + info.edge = bool_or_default(cell->params, id("NEG_CLK_R")) ? FALLING_EDGE : RISING_EDGE; + } else { + info.clock_port = id_WCLK; + info.edge = bool_or_default(cell->params, id("NEG_CLK_W")) ? FALLING_EDGE : RISING_EDGE; + } + if (cell->ports.at(port).type == PORT_OUT) { + bool has_clktoq = getCellDelay(cell, info.clock_port, port, info.clockToQ); + NPNR_ASSERT(has_clktoq); + } else { + info.setup.delay = 100; + info.hold.delay = 0; + } + } else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) { + info.clock_port = cell->type == id_ICESTORM_SPRAM ? id_CLOCK : id_CLK; + info.edge = RISING_EDGE; + if (cell->ports.at(port).type == PORT_OUT) { + bool has_clktoq = getCellDelay(cell, info.clock_port, port, info.clockToQ); + if (!has_clktoq) + info.clockToQ.delay = 100; + } else { + info.setup.delay = 100; + info.hold.delay = 0; + } + } else { + NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo"); + } + return info; +} + bool Arch::isGlobalNet(const NetInfo *net) const { if (net == nullptr) diff --git a/ice40/arch.h b/ice40/arch.h index f7d31b0e..836dc46e 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -796,6 +796,12 @@ struct Arch : BaseCtx delay_t getDelayEpsilon() const { return 20; } delay_t getRipupDelayPenalty() const { return 200; } float getDelayNS(delay_t v) const { return v * 0.001; } + DelayInfo getDelayFromNS(float ns) const + { + DelayInfo del; + del.delay = delay_t(ns * 1000); + return del; + } uint32_t getDelayChecksum(delay_t v) const { return v; } bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; @@ -819,8 +825,10 @@ struct Arch : BaseCtx // Get the delay through a cell from one port to another, returning false // if no path exists bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; - // Get the port class, also setting clockDomain if applicable - TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockDomain) const; + // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port + TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; + // Get the TimingClockingInfo of a port + TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index f1639ba6..3fafb1f6 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -140,6 +140,10 @@ void arch_wrap_python() "cells"); readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls, "nets"); + + fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>, + pass_through<float>>::def_wrap(ctx_cls, "addClock"); + WRAP_RANGE(Bel, conv_to_str<BelId>); WRAP_RANGE(Wire, conv_to_str<WireId>); WRAP_RANGE(AllPip, conv_to_str<PipId>); diff --git a/ice40/pack.cc b/ice40/pack.cc index edd12f92..7a27d505 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -462,7 +462,8 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port) static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic) { - log_info("promoting %s%s%s%s\n", net->name.c_str(ctx), is_reset ? " [reset]" : "", is_cen ? " [cen]" : "", is_logic ? " [logic]" : ""); + log_info("promoting %s%s%s%s\n", net->name.c_str(ctx), is_reset ? " [reset]" : "", is_cen ? " [cen]" : "", + is_logic ? " [logic]" : ""); std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); std::unique_ptr<CellInfo> gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name); @@ -489,6 +490,14 @@ static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen } } net->users = keep_users; + + if (net->clkconstr) { + glbnet->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint()); + glbnet->clkconstr->low = net->clkconstr->low; + glbnet->clkconstr->high = net->clkconstr->high; + glbnet->clkconstr->period = net->clkconstr->period; + } + ctx->nets[glbnet->name] = std::move(glbnet); ctx->cells[gb->name] = std::move(gb); } |