xilinx: use specify blocks in place of abc9_{arrival,required}
authorEddie Hung <eddie@fpgeh.com>
Tue, 11 Feb 2020 22:22:43 +0000 (14:22 -0800)
committerEddie Hung <eddie@fpgeh.com>
Thu, 27 Feb 2020 18:17:29 +0000 (10:17 -0800)
README.md
passes/techmap/abc9_ops.cc
techlibs/xilinx/cells_sim.v

index 9c15fe3d975df4c53a497132f34697462aeb2a3f..8cd347497c6504b8c4f07be5c7b8220c90d6c2b7 100644 (file)
--- a/README.md
+++ b/README.md
@@ -364,25 +364,14 @@ Verilog Attributes and non-standard features
   it as the external-facing pin of an I/O pad, and prevents ``iopadmap``
   from inserting another pad cell on it.
 
-- The module attribute ``abc9_box_id`` specifies a positive integer linking a
-  blackbox or whitebox definition to a corresponding entry in a `abc9`
-  box-file.
+- The module attribute ``abc9_box`` is a boolean specifying a blackbox or
+  whitebox definition for use by `abc9`.
 
 - The port attribute ``abc9_carry`` marks the carry-in (if an input port) and
   carry-out (if output port) ports of a box. This information is necessary for
   `abc9` to preserve the integrity of carry-chains. Specifying this attribute
   onto a bus port will affect only its most significant bit.
 
-- The output port attribute ``abc9_arrival`` specifies an integer, or a string
-  of space-separated integers to be used as the arrival time of this blackbox
-  port. It can be used, for example, to specify the clk-to-Q delay of a flip-
-  flop output for consideration during `abc9` techmapping.
-
-- The input port attribute ``abc9_required`` specifies an integer, or a string
-  of space-separated integers to be used as the required time of this blackbox
-  port. It can be used, for example, to specify the setup-time of a flip-flop
-  input for consideration during `abc9` techmapping.
-
 - The module attribute ``abc9_flop`` is a boolean marking the module as a
   flip-flop. This allows `abc9` to analyse its contents in order to perform
   sequential synthesis.
index bbbbc45d02a1fe4c380f46dbcba1ec8e1b905f54..9abe6af9fdb0b085092e225d25c80c5790be13e5 100644 (file)
@@ -70,54 +70,6 @@ void check(RTLIL::Design *design)
                                        carry_out = port_name;
                                }
                        }
-
-                       auto it = w->attributes.find("\\abc9_arrival");
-                       if (it != w->attributes.end()) {
-                               int count = 0;
-                               if (it->second.flags == 0) {
-                                       if (it->second.as_int() < 0)
-                                               log_error("%s.%s has negative arrival value %d!\n", log_id(m), log_id(port_name),
-                                                               it->second.as_int());
-                                       count++;
-                               }
-                               else
-                                       for (const auto &tok : split_tokens(it->second.decode_string())) {
-                                               if (tok.find_first_not_of("0123456789") != std::string::npos)
-                                                       log_error("%s.%s has non-integer arrival value '%s'!\n", log_id(m), log_id(port_name),
-                                                                       tok.c_str());
-                                               if (atoi(tok.c_str()) < 0)
-                                                       log_error("%s.%s has negative arrival value %s!\n", log_id(m), log_id(port_name),
-                                                                       tok.c_str());
-                                               count++;
-                                       }
-                               if (count > 1 && count != GetSize(w))
-                                       log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(m), log_id(port_name),
-                                                       GetSize(w), log_signal(it->second), count);
-                       }
-
-                       it = w->attributes.find("\\abc9_required");
-                       if (it != w->attributes.end()) {
-                               int count = 0;
-                               if (it->second.flags == 0) {
-                                       if (it->second.as_int() < 0)
-                                               log_error("%s.%s has negative required value %d!\n", log_id(m), log_id(port_name),
-                                                               it->second.as_int());
-                                       count++;
-                               }
-                               else
-                                       for (const auto &tok : split_tokens(it->second.decode_string())) {
-                                               if (tok.find_first_not_of("0123456789") != std::string::npos)
-                                                       log_error("%s.%s has non-integer required value '%s'!\n", log_id(m), log_id(port_name),
-                                                                       tok.c_str());
-                                               if (atoi(tok.c_str()) < 0)
-                                                       log_error("%s.%s has negative required value %s!\n", log_id(m), log_id(port_name),
-                                                                       tok.c_str());
-                                               count++;
-                                       }
-                               if (count > 1 && count != GetSize(w))
-                                       log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(m), log_id(port_name),
-                                                       GetSize(w), log_signal(it->second), count);
-                       }
                }
 
                if (carry_in != IdString() && carry_out == IdString())
@@ -428,16 +380,15 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
 
 void prep_delays(RTLIL::Design *design)
 {
-       pool<Module*> flops;
+       // Derive and collect all blackbox modules, and collect all blackbox instantiations
+       pool<Module*> derived;
        std::vector<Cell*> cells;
-       dict<IdString,dict<IdString,std::vector<int>>> requireds_cache;
        for (auto module : design->selected_modules()) {
                if (module->processes.size() > 0) {
                        log("Skipping module %s as it contains processes.\n", log_id(module));
                        continue;
                }
 
-               cells.clear();
                for (auto cell : module->cells()) {
                        if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
                                continue;
@@ -447,119 +398,186 @@ void prep_delays(RTLIL::Design *design)
                                continue;
                        if (!inst_module->get_blackbox_attribute())
                                continue;
-                       if (inst_module->get_bool_attribute(ID(abc9_flop))) {
-                               IdString derived_type = inst_module->derive(design, cell->parameters);
-                               inst_module = design->module(derived_type);
-                               log_assert(inst_module);
-                               flops.insert(inst_module);
-                               continue; // because all flop required times
-                                         //   will be captured in the flop box
-                       }
                        if (inst_module->attributes.count(ID(abc9_box)))
                                continue;
+                       IdString derived_type = inst_module->derive(design, cell->parameters);
+                       inst_module = design->module(derived_type);
+                       log_assert(inst_module);
+                       derived.insert(inst_module);
+
                        cells.emplace_back(cell);
                }
+       }
 
-               for (auto cell : cells) {
-                       RTLIL::Module* inst_module = module->design->module(cell->type);
-                       log_assert(inst_module);
-                       auto &cell_requireds = requireds_cache[cell->type];
-                       for (auto &conn : cell->connections_) {
-                               auto port_wire = inst_module->wire(conn.first);
-                               if (!port_wire->port_input)
-                                       continue;
+       // Transform all $specify3 and $specrule to abc9_{arrival,required} attributes
+       std::vector<Module*> flops;
+       dict<SigBit, int> arrivals, requireds;
+       pool<Wire*> ports;
+       std::stringstream ss;
+       for (auto module : derived) {
+               if (module->get_bool_attribute(ID(abc9_flop)))
+                       flops.push_back(module);
 
-                               auto r = cell_requireds.insert(conn.first);
-                               auto &requireds = r.first->second;
-                               if (r.second) {
-                                       auto it = port_wire->attributes.find("\\abc9_required");
-                                       if (it == port_wire->attributes.end())
-                                               continue;
-                                       if (it->second.flags == 0) {
-                                               int delay = it->second.as_int();
-                                               requireds.emplace_back(delay);
-                                       }
-                                       else
-                                               for (const auto &tok : split_tokens(it->second.decode_string())) {
-                                                       int delay = atoi(tok.c_str());
-                                                       requireds.push_back(delay);
-                                               }
+               arrivals.clear();
+               requireds.clear();
+               for (auto cell : module->cells()) {
+                       if (cell->type == ID($specify3)) {
+                               auto src = cell->getPort(ID(SRC));
+                               auto dat = cell->getPort(ID(DAT));
+                               auto dst = cell->getPort(ID(DST));
+                               for (const auto &c : src.chunks())
+                                       if (!c.wire->port_input)
+                                               log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
+                               for (const auto &c : dat.chunks())
+                                       if (!c.wire->port_input)
+                                               log_error("Module '%s' contains specify cell '%s' where DAT '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dat));
+                               for (const auto &c : dst.chunks())
+                                       if (!c.wire->port_output)
+                                               log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
+                               if (!cell->getParam(ID(EDGE_EN)).as_bool())
+                                       continue;
+                               int rise_max = cell->getParam(ID(T_RISE_MAX)).as_int();
+                               int fall_max = cell->getParam(ID(T_FALL_MAX)).as_int();
+                               int max = std::max(rise_max,fall_max);
+                               if (max < 0) {
+                                       log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
+                                       continue;
                                }
-
-                               if (requireds.empty())
+                               for (auto d : dst)
+                                       arrivals[d] = std::max(arrivals[d], max);
+                       }
+                       else if (cell->type == ID($specrule)) {
+                               auto type = cell->getParam(ID(TYPE)).decode_string();
+                               if (type != "$setup" && type != "$setuphold")
+                                       continue;
+                               auto src = cell->getPort(ID(SRC));
+                               auto dst = cell->getPort(ID(DST));
+                               for (const auto &c : src.chunks())
+                                       if (!c.wire->port_input)
+                                               log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
+                               for (const auto &c : dst.chunks())
+                                       if (!c.wire->port_input)
+                                               log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
+                               int setup = cell->getParam(ID(T_LIMIT)).as_int();
+                               if (setup < 0) {
+                                       log_warning("Module '%s' contains specify cell '%s' with T_LIMIT < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
                                        continue;
+                               }
+                               for (const auto &s : src)
+                                       requireds[s] = std::max(requireds[s], setup);
+                       }
+               }
 
-                               SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
-                               auto it = requireds.begin();
-                               for (int i = 0; i < GetSize(conn.second); ++i) {
-#ifndef NDEBUG
-                                       if (ys_debug(1)) {
-                                               static std::set<std::pair<IdString,IdString>> seen;
-                                               if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), requireds[i]);
-                                       }
-#endif
-                                       auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY));
-                                       box->setPort(ID(I), conn.second[i]);
-                                       box->setPort(ID(O), O[i]);
-                                       box->setParam(ID(DELAY), *it);
-                                       if (requireds.size() > 1)
-                                               it++;
-                                       conn.second[i] = O[i];
+               if (arrivals.empty() && requireds.empty())
+                       continue;
+
+               ports.clear();
+               for (const auto &i : arrivals)
+                       ports.insert(i.first.wire);
+               for (auto wire : ports) {
+                       log_assert(wire->port_output);
+                       ss.str("");
+                       if (GetSize(wire) == 1)
+                               wire->attributes[ID(abc9_arrival)] = arrivals.at(SigBit(wire,0));
+                       else {
+                               bool first = true;
+                               for (auto b : SigSpec(wire)) {
+                                       if (first)
+                                               first = false;
+                                       else
+                                               ss << " ";
+                                       auto it = arrivals.find(b);
+                                       if (it == arrivals.end())
+                                               ss << "0";
+                                       else
+                                               ss << it->second;
                                }
+                               wire->attributes[ID(abc9_arrival)] = ss.str();
                        }
                }
-       }
 
-       int abc9_box_id = design->scratchpad_get_int("abc9_ops.box_id");
-       std::stringstream ss;
-       for (auto flop_module : flops) {
-               int num_inputs = 0, num_outputs = 0;
-               for (auto port_name : flop_module->ports) {
-                       auto wire = flop_module->wire(port_name);
-                       log_assert(GetSize(wire) == 1);
-                       if (wire->port_input) num_inputs++;
-                       if (wire->port_output) num_outputs++;
+               ports.clear();
+               for (const auto &i : requireds)
+                       ports.insert(i.first.wire);
+               for (auto wire : ports) {
+                       log_assert(wire->port_input);
+                       ss.str("");
+                       if (GetSize(wire) == 1)
+                               wire->attributes[ID(abc9_required)] = requireds.at(SigBit(wire,0));
+                       else {
+                               bool first = true;
+                               for (auto b : SigSpec(wire)) {
+                                       if (first)
+                                               first = false;
+                                       else
+                                               ss << " ";
+                                       auto it = requireds.find(b);
+                                       if (it == requireds.end())
+                                               ss << "0";
+                                       else
+                                               ss << it->second;
+                               }
+                               wire->attributes[ID(abc9_required)] = ss.str();
+                       }
                }
-               log_assert(num_outputs == 1);
+       }
 
-               auto r = flop_module->attributes.insert(ID(abc9_box_id));
-               if (r.second)
-                       r.first->second = ++abc9_box_id;
+       // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
+       //   with (* abc9_required *) attributes
+       dict<IdString,dict<IdString,std::vector<int>>> requireds_cache;
+       for (auto cell : cells) {
+               auto module = cell->module;
+               RTLIL::Module* inst_module = module->design->module(cell->type);
+               log_assert(inst_module);
+               IdString derived_type = inst_module->derive(design, cell->parameters);
+               inst_module = design->module(derived_type);
+               log_assert(inst_module);
+
+               auto &cell_requireds = requireds_cache[cell->type];
+               for (auto &conn : cell->connections_) {
+                       auto port_wire = inst_module->wire(conn.first);
+                       if (!port_wire->port_input)
+                               continue;
 
-               ss << log_id(flop_module) << " " << r.first->second.as_int();
-               ss << " " << (flop_module->get_bool_attribute(ID::whitebox) ? "1" : "0");
-               ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
+                       auto r = cell_requireds.insert(conn.first);
+                       auto &requireds = r.first->second;
+                       if (r.second) {
+                               auto it = port_wire->attributes.find("\\abc9_required");
+                               if (it == port_wire->attributes.end())
+                                       continue;
+                               if (it->second.flags == 0) {
+                                       int delay = it->second.as_int();
+                                       requireds.emplace_back(delay);
+                               }
+                               else
+                                       for (const auto &tok : split_tokens(it->second.decode_string())) {
+                                               int delay = atoi(tok.c_str());
+                                               requireds.push_back(delay);
+                                       }
+                       }
 
-               ss << "#";
-               bool first = true;
-               for (auto port_name : flop_module->ports) {
-                       auto wire = flop_module->wire(port_name);
-                       if (!wire->port_input)
+                       if (requireds.empty())
                                continue;
-                       if (first)
-                               first = false;
-                       else
-                               ss << " ";
-                       ss << log_id(wire);
-               }
-               ss << " abc9_ff.Q" << std::endl;
 
-               first = true;
-               for (auto port_name : flop_module->ports) {
-                       auto wire = flop_module->wire(port_name);
-                       if (!wire->port_input)
-                               continue;
-                       if (first)
-                               first = false;
-                       else
-                               ss << " ";
-                       ss << wire->attributes.at("\\abc9_required", 0).as_int();
+                       SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
+                       auto it = requireds.begin();
+                       for (int i = 0; i < GetSize(conn.second); ++i) {
+#ifndef NDEBUG
+                               if (ys_debug(1)) {
+                                       static std::set<std::pair<IdString,IdString>> seen;
+                                       if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), requireds[i]);
+                               }
+#endif
+                               auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY));
+                               box->setPort(ID(I), conn.second[i]);
+                               box->setPort(ID(O), O[i]);
+                               box->setParam(ID(DELAY), *it);
+                               if (requireds.size() > 1)
+                                       it++;
+                               conn.second[i] = O[i];
+                       }
                }
-               // Last input is 'abc9_ff.Q'
-               ss << " 0" << std::endl << std::endl;
        }
-       design->scratchpad_set_string("abc9_ops.box_library.flops", ss.str());
-       design->scratchpad_set_int("abc9_ops.box_id", abc9_box_id);
 }
 
 void prep_lut(RTLIL::Design *design, int maxlut)
@@ -587,7 +605,10 @@ void prep_lut(RTLIL::Design *design, int maxlut)
                                log_assert(o == d);
                        int rise_max = cell->getParam(ID(T_RISE_MAX)).as_int();
                        int fall_max = cell->getParam(ID(T_FALL_MAX)).as_int();
-                       specify.push_back(std::max(rise_max,fall_max));
+                       int max = std::max(rise_max,fall_max);
+                       if (max < 0)
+                               log_error("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0.\n", log_id(module), log_id(cell));
+                       specify.push_back(max);
                }
                if (maxlut && GetSize(specify) > maxlut)
                        continue;
@@ -618,10 +639,57 @@ void write_lut(RTLIL::Module *module, const std::string &dst) {
 void prep_box(RTLIL::Design *design)
 {
        std::stringstream ss;
-       ss << design->scratchpad_get_string("abc9_ops.box_library.flops", ss.str());
-
-       int abc9_box_id = design->scratchpad_get_int("abc9_ops.box_id");
+       int abc9_box_id = 1;
+       dict<IdString,std::vector<IdString>> box_ports;
        for (auto module : design->modules()) {
+               if (module->get_bool_attribute(ID(abc9_flop))) {
+                       int num_inputs = 0, num_outputs = 0;
+                       for (auto port_name : module->ports) {
+                               auto wire = module->wire(port_name);
+                               log_assert(GetSize(wire) == 1);
+                               if (wire->port_input) num_inputs++;
+                               if (wire->port_output) num_outputs++;
+                       }
+                       log_assert(num_outputs == 1);
+
+                       auto r = module->attributes.insert(ID(abc9_box_id));
+                       if (r.second)
+                               r.first->second = abc9_box_id++;
+
+                       ss << log_id(module) << " " << r.first->second.as_int();
+                       ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
+                       ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
+
+                       ss << "#";
+                       bool first = true;
+                       for (auto port_name : module->ports) {
+                               auto wire = module->wire(port_name);
+                               if (!wire->port_input)
+                                       continue;
+                               if (first)
+                                       first = false;
+                               else
+                                       ss << " ";
+                               ss << log_id(wire);
+                       }
+                       ss << " abc9_ff.Q" << std::endl;
+
+                       first = true;
+                       for (auto port_name : module->ports) {
+                               auto wire = module->wire(port_name);
+                               if (!wire->port_input)
+                                       continue;
+                               if (first)
+                                       first = false;
+                               else
+                                       ss << " ";
+                               ss << wire->attributes.at("\\abc9_required", 0).as_int();
+                       }
+                       // Last input is 'abc9_ff.Q'
+                       ss << " 0" << std::endl << std::endl;
+                       continue;
+               }
+
                auto it = module->attributes.find(ID(abc9_box));
                if (it == module->attributes.end())
                        continue;
@@ -631,7 +699,33 @@ void prep_box(RTLIL::Design *design)
                dict<std::pair<SigBit,SigBit>, std::string> table;
                std::vector<SigBit> inputs;
                std::vector<SigBit> outputs;
-               for (auto port_name : module->ports) {
+
+               auto r = box_ports.insert(module->name);
+               if (r.second) {
+                       // Make carry in the last PI, and carry out the last PO
+                       //   since ABC requires it this way
+                       IdString carry_in, carry_out;
+                       for (const auto &port_name : module->ports) {
+                               auto w = module->wire(port_name);
+                               log_assert(w);
+                               if (w->get_bool_attribute("\\abc9_carry")) {
+                                       log_assert(w->port_input != w->port_output);
+                                       if (w->port_input)
+                                               carry_in = port_name;
+                                       else if (w->port_output)
+                                               carry_out = port_name;
+                               }
+                               else
+                                       r.first->second.push_back(port_name);
+                       }
+
+                       if (carry_in != IdString()) {
+                               r.first->second.push_back(carry_in);
+                               r.first->second.push_back(carry_out);
+                       }
+               }
+
+               for (auto port_name : r.first->second) {
                        auto wire = module->wire(port_name);
                        if (wire->port_input)
                                for (int i = 0; i < GetSize(wire); i++)
@@ -654,17 +748,29 @@ void prep_box(RTLIL::Design *design)
                        int rise_max = cell->getParam(ID(T_RISE_MAX)).as_int();
                        int fall_max = cell->getParam(ID(T_FALL_MAX)).as_int();
                        int max = std::max(rise_max,fall_max);
-                       for (auto s : src)
-                               for (auto d : dst) {
-                                       auto r = table.insert(std::make_pair(s,d));
+                       if (max < 0)
+                               log_error("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0.\n", log_id(module), log_id(cell));
+                       if (cell->getParam(ID(FULL)).as_bool()) {
+                               for (auto s : src)
+                                       for (auto d : dst) {
+                                               auto r = table.insert(std::make_pair(s,d));
+                                               log_assert(r.second);
+                                               r.first->second = std::to_string(max);
+                                       }
+                       }
+                       else {
+                               log_assert(GetSize(src) == GetSize(dst));
+                               for (auto i = 0; i < GetSize(src); i++) {
+                                       auto r = table.insert(std::make_pair(src[i],dst[i]));
                                        log_assert(r.second);
                                        r.first->second = std::to_string(max);
                                }
+                       }
                }
-               auto r = module->attributes.insert(ID(abc9_box_id));
-               log_assert(r.second);
-               r.first->second = ++abc9_box_id;
+               auto r2 = module->attributes.insert(ID(abc9_box_id));
+               log_assert(r2.second);
                ss << log_id(module) << " " << abc9_box_id;
+               r2.first->second = abc9_box_id++;
                ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
                ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
                bool first = true;
@@ -700,17 +806,17 @@ void prep_box(RTLIL::Design *design)
                ss << std::endl;
        }
 
+       // ABC expects at least one box
+       if (ss.tellp() == 0)
+               ss << "(dummy) 1 0 0 0";
+
        design->scratchpad_set_string("abc9_ops.box_library", ss.str());
-       design->scratchpad_set_int("abc9_ops.box_id", abc9_box_id);
 }
 
 void write_box(RTLIL::Module *module, const std::string &dst) {
        std::ofstream ofs(dst);
        log_assert(ofs.is_open());
        ofs << module->design->scratchpad_get_string("abc9_ops.box_library");
-       // ABC expects at least one box
-       if (ofs.tellp() == 0)
-               ofs << "(dummy) 1 0 0 0";
        ofs.close();
 }
 
index 1318389f0e7cd32f2c320735aed0f83c0b2fe092..f9d837e4cda1505bbb8a2240f664ca7d02056d38 100644 (file)
@@ -477,18 +477,14 @@ endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDRE (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  (* abc9_required=109 *)
   input CE,
   (* invertible_pin = "IS_D_INVERTED" *)
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D,
   (* invertible_pin = "IS_R_INVERTED" *)
-  (* abc9_required=404 *)
   input R
 );
   parameter [0:0] INIT = 1'b0;
@@ -496,44 +492,58 @@ module FDRE (
   parameter [0:0] IS_D_INVERTED = 1'b0;
   parameter [0:0] IS_R_INVERTED = 1'b0;
   initial Q <= INIT;
-  generate case (|IS_C_INVERTED)
+  generate
+  case (|IS_C_INVERTED)
     1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
     1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
-  endcase endgenerate
+  endcase
+  if (!IS_C_INVERTED)
+    specify
+      if (CE) (posedge C => (Q : D)) = 303;
+      //$setup(D , posedge C, -46); // Negative times not currently supported
+      $setup(CE, posedge C, 109);
+      $setup(R , posedge C, 404);
+    endspecify
+  else
+    specify
+      if (CE) (negedge C => (Q : D)) = 303;
+      //if (CE) $setup(D , negedge C, -46); // Negative times not currently supported
+      $setup(CE, negedge C, 109);
+      $setup(R , negedge C, 404);
+    endspecify
+  endgenerate
 endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDRE_1 (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   input C,
-  (* abc9_required=109 *)
   input CE,
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D,
-  (* abc9_required=404 *)
   input R
 );
   parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
   always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
+  specify
+    if (CE) (negedge C => (Q : D)) = 303;
+    //if (CE) $setup(D , negedge C, -46); // Negative times not currently supported
+    $setup(CE, negedge C, 109);
+    $setup(R , negedge C, 404);
+  endspecify
 endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDSE (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  (* abc9_required=109 *)
   input CE,
   (* invertible_pin = "IS_D_INVERTED" *)
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D,
   (* invertible_pin = "IS_S_INVERTED" *)
-  (* abc9_required=404 *)
   input S
 );
   parameter [0:0] INIT = 1'b1;
@@ -541,28 +551,46 @@ module FDSE (
   parameter [0:0] IS_D_INVERTED = 1'b0;
   parameter [0:0] IS_S_INVERTED = 1'b0;
   initial Q <= INIT;
-  generate case (|IS_C_INVERTED)
+  generate
+  case (|IS_C_INVERTED)
     1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
     1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-  endcase endgenerate
+  endcase
+  if (!IS_C_INVERTED)
+    specify
+      if (CE) (posedge C => (Q : D)) = 303;
+      //if (CE) $setup(D , posedge C, -46); // Negative times not currently supported
+      $setup(CE, posedge C, 109);
+      $setup(S , posedge C, 404);
+    endspecify
+  else
+    specify
+        if (CE) (negedge C => (Q : D)) = 303;
+        //if (CE) $setup(D , negedge C, -46); // Negative times not currently supported
+        $setup(CE, negedge C, 109);
+        $setup(S , negedge C, 404);
+    endspecify
+  endgenerate
 endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDSE_1 (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   input C,
-  (* abc9_required=109 *)
   input CE,
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D,
-  (* abc9_required=404 *)
   input S
 );
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
   always @(negedge C) if (S) Q <= 1'b1; else if (CE) Q <= D;
+  specify
+    if (CE) (negedge C => (Q : D)) = 303;
+    //if (CE) $setup(D , negedge C, -46); // Negative times not currently supported
+    $setup(CE, negedge C, 109);
+    $setup(S , negedge C, 404);
+  endspecify
 endmodule
 
 module FDRSE (
@@ -571,7 +599,6 @@ module FDRSE (
   (* invertible_pin = "IS_C_INVERTED" *)
   input C,
   (* invertible_pin = "IS_CE_INVERTED" *)
-  (* abc9_required=109 *)
   input CE,
   (* invertible_pin = "IS_D_INVERTED" *)
   input D,
@@ -603,18 +630,14 @@ endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDCE (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  (* abc9_required=109 *)
   input CE,
   (* invertible_pin = "IS_CLR_INVERTED" *)
-  (* abc9_required=764 *)
   input CLR,
   (* invertible_pin = "IS_D_INVERTED" *)
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D
 );
   parameter [0:0] INIT = 1'b0;
@@ -622,46 +645,60 @@ module FDCE (
   parameter [0:0] IS_D_INVERTED = 1'b0;
   parameter [0:0] IS_CLR_INVERTED = 1'b0;
   initial Q <= INIT;
-  generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED})
+  generate
+  case ({|IS_C_INVERTED, |IS_CLR_INVERTED})
     2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
     2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
     2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
     2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
-  endcase endgenerate
+  endcase
+  if (!IS_C_INVERTED)
+    specify
+      if (CE) (posedge C => (Q : D)) = 303;
+      //if (CE) $setup(D  , posedge C, -46); // Negative times not currently supported
+      $setup(CE , posedge C, 109);
+      $setup(CLR, posedge C, 764);
+    endspecify
+  else
+    specify
+        if (CE) (negedge C => (Q : D)) = 303;
+        //if (CE) $setup(D  , negedge C, -46); // Negative times not currently supported
+        $setup(CE , negedge C, 109);
+        $setup(CLR, negedge C, 764);
+    endspecify
+ endgenerate
 endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDCE_1 (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   input C,
-  (* abc9_required=109 *)
   input CE,
-  (* abc9_required=764 *)
   input CLR,
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D
 );
   parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
+  specify
+    if (CE) (negedge C => (Q : D)) = 303;
+    //if (CE) $setup(D  , negedge C, -46); // Negative times not currently supported
+    $setup(CE , negedge C, 109);
+    $setup(CLR, negedge C, 764);
+  endspecify
 endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDPE (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  (* abc9_required=109 *)
   input CE,
   (* invertible_pin = "IS_D_INVERTED" *)
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D,
   (* invertible_pin = "IS_PRE_INVERTED" *)
-  (* abc9_required=764 *)
   input PRE
 );
   parameter [0:0] INIT = 1'b1;
@@ -674,25 +711,42 @@ module FDPE (
     2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
     2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
     2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-  endcase endgenerate
+  endcase
+  if (!IS_C_INVERTED)
+    specify
+      if (CE) (posedge C => (Q : D)) = 303;
+      //if (CE) $setup(D  , posedge C, -46); // Negative times not currently supported
+      $setup(CE , posedge C, 109);
+      $setup(PRE, posedge C, 764);
+    endspecify
+  else
+    specify
+        if (CE) (negedge C => (Q : D)) = 303;
+        //if (CE) $setup(D  , negedge C, -46); // Negative times not currently supported
+        $setup(CE , negedge C, 109);
+        $setup(PRE, negedge C, 764);
+    endspecify
+  endgenerate
 endmodule
 
 (* abc9_flop, lib_whitebox *)
 module FDPE_1 (
-  (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   input C,
-  (* abc9_required=109 *)
   input CE,
-  //(* abc9_required=-46 *) // Negative required times not currently supported
   input D,
-  (* abc9_required=764 *)
   input PRE
 );
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
   always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
+  specify
+    if (CE) (negedge C => (Q : D)) = 303;
+    //if (CE) $setup(D  , negedge C, -46); // Negative times not currently supported
+    $setup(CE , negedge C, 109);
+    $setup(PRE, negedge C, 764);
+  endspecify
 endmodule
 
 module FDCPE (
@@ -1303,33 +1357,13 @@ module RAM16X1D_1 (
 endmodule
 
 module RAM32X1D (
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
-  (* abc9_arrival=1153 *)
   output DPO, SPO,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
-  (* abc9_required=453 *)
   input  D,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_WCLK_INVERTED" *)
   input  WCLK,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
-  (* abc9_required=654 *)
   input  WE,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
-  (* abc9_required=245 *)
-  input  A0,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798
-  (* abc9_required=208 *)
-  input  A1,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
-  (* abc9_required=147 *)
-  input  A2,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
-  (* abc9_required=68 *)
-  input  A3,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
-  (* abc9_required=66 *)
-  input  A4,
+  input  A0, A1, A2, A3, A4,
   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
 );
   parameter INIT = 32'h0;
@@ -1341,35 +1375,61 @@ module RAM32X1D (
   assign DPO = mem[dpra];
   wire clk = WCLK ^ IS_WCLK_INVERTED;
   always @(posedge clk) if (WE) mem[a] <= D;
+  generate
+    if (!IS_WCLK_INVERTED)
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+        if (WE) (posedge WCLK => (SPO : D)) = 1153;
+        if (WE) (posedge WCLK => (DPO : D)) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(D , posedge WCLK, 453);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, posedge WCLK, 654);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
+        $setup(A0, posedge WCLK, 245);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L798
+        $setup(A1, posedge WCLK, 208);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
+        $setup(A2, posedge WCLK, 147);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
+        $setup(A3, posedge WCLK, 68);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
+        $setup(A4, posedge WCLK, 66);
+      endspecify
+    else
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+        if (WE) (negedge WCLK => (SPO : D)) = 1153;
+        if (WE) (negedge WCLK => (DPO : D)) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(D , negedge WCLK, 453);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, negedge WCLK, 654);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
+        $setup(A0, negedge WCLK, 245);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L798
+        $setup(A1, negedge WCLK, 208);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
+        $setup(A2, negedge WCLK, 147);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
+        $setup(A3, negedge WCLK, 68);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
+        $setup(A4, negedge WCLK, 66);
+      endspecify
+  endgenerate
 endmodule
 
 module RAM32X1D_1 (
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
-  (* abc9_arrival=1153 *)
   output DPO, SPO,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
-  (* abc9_required=453 *)
   input  D,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_WCLK_INVERTED" *)
   input  WCLK,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
-  (* abc9_required=654 *)
   input  WE,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
-  (* abc9_required=245 *)
   input  A0,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798
-  (* abc9_required=208 *)
   input  A1,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
-  (* abc9_required=147 *)
   input  A2,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
-  (* abc9_required=68 *)
   input  A3,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
-  (* abc9_required=66 *)
   input  A4,
   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
 );
@@ -1382,39 +1442,35 @@ module RAM32X1D_1 (
   assign DPO = mem[dpra];
   wire clk = WCLK ^ IS_WCLK_INVERTED;
   always @(negedge clk) if (WE) mem[a] <= D;
+  specify
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+    if (WE) (negedge WCLK => (SPO : D)) = 1153;
+    if (WE) (negedge WCLK => (DPO : D)) = 1153;
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+    $setup(D , negedge WCLK, 453);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+    $setup(WE, negedge WCLK, 654);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
+    $setup(A0, negedge WCLK, 245);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L798
+    $setup(A1, negedge WCLK, 208);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
+    $setup(A2, negedge WCLK, 147);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
+    $setup(A3, negedge WCLK, 68);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
+    $setup(A4, negedge WCLK, 66);
+  endspecify
 endmodule
 
 module RAM64X1D (
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
-  (* abc9_arrival=1153 *)
   output DPO, SPO,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
-  (* abc9_required=453 *)
   input  D,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_WCLK_INVERTED" *)
   input  WCLK,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
-  (* abc9_required=654 *)
   input  WE,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
-  (* abc9_required=362 *)
-  input  A0,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
-  (* abc9_required=245 *)
-  input  A1,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
-  (* abc9_required=208 *)
-  input  A2,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
-  (* abc9_required=147 *)
-  input  A3,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
-  (* abc9_required=68 *)
-  input  A4,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
-  (* abc9_required=66 *)
-  input  A5,
+  input  A0, A1, A2, A3, A4, A5,
   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
 );
   parameter INIT = 64'h0;
@@ -1426,39 +1482,62 @@ module RAM64X1D (
   assign DPO = mem[dpra];
   wire clk = WCLK ^ IS_WCLK_INVERTED;
   always @(posedge clk) if (WE) mem[a] <= D;
+  generate
+    if (!IS_WCLK_INVERTED)
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+        if (WE) (posedge WCLK => (SPO : D)) = 1153;
+        if (WE) (posedge WCLK => (DPO : D)) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(D , posedge WCLK, 453);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, posedge WCLK, 654);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
+        $setup(A0, posedge WCLK, 362);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
+        $setup(A1, posedge WCLK, 245);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
+        $setup(A2, posedge WCLK, 208);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
+        $setup(A3, posedge WCLK, 147);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
+        $setup(A4, posedge WCLK, 68);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
+        $setup(A5, posedge WCLK, 66);
+      endspecify
+    else
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+        if (WE) (negedge WCLK => (SPO : D)) = 1153;
+        if (WE) (negedge WCLK => (DPO : D)) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(D , negedge WCLK, 453);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, negedge WCLK, 654);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
+        $setup(A0, negedge WCLK, 362);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
+        $setup(A1, negedge WCLK, 245);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
+        $setup(A2, negedge WCLK, 208);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
+        $setup(A3, negedge WCLK, 147);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
+        $setup(A4, negedge WCLK, 68);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
+        $setup(A5, negedge WCLK, 66);
+      endspecify
+  endgenerate
 endmodule
 
 module RAM64X1D_1 (
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
-  (* abc9_arrival=1153 *)
   output DPO, SPO,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
-  (* abc9_required=453 *)
   input  D,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_WCLK_INVERTED" *)
   input  WCLK,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
-  (* abc9_required=654 *)
   input  WE,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
-  (* abc9_required=362 *)
-  input  A0,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
-  (* abc9_required=245 *)
-  input  A1,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
-  (* abc9_required=208 *)
-  input  A2,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
-  (* abc9_required=147 *)
-  input  A3,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
-  (* abc9_required=68 *)
-  input  A4,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
-  (* abc9_required=66 *)
-  input  A5,
+  input  A0, A1, A2, A3, A4, A5,
   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
 );
   parameter INIT = 64'h0;
@@ -1470,21 +1549,35 @@ module RAM64X1D_1 (
   assign DPO = mem[dpra];
   wire clk = WCLK ^ IS_WCLK_INVERTED;
   always @(negedge clk) if (WE) mem[a] <= D;
+  specify
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+    if (WE) (negedge WCLK => (SPO : D)) = 1153;
+    if (WE) (negedge WCLK => (DPO : D)) = 1153;
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+    $setup(D , negedge WCLK, 453);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+    $setup(WE, negedge WCLK, 654);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
+    $setup(A0, negedge WCLK, 362);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
+    $setup(A1, negedge WCLK, 245);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
+    $setup(A2, negedge WCLK, 208);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
+    $setup(A3, negedge WCLK, 147);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
+    $setup(A4, negedge WCLK, 68);
+    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
+    $setup(A5, negedge WCLK, 66);
+  endspecify
 endmodule
 
 module RAM128X1D (
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
-  //   plus 208ps to cross MUXF7
-  (* abc9_arrival=1359 *)
   output       DPO, SPO,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
-  (* abc9_required=453 *)
   input        D,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_WCLK_INVERTED" *)
   input        WCLK,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
-  (* abc9_required=654 *)
   input        WE,
   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-830
   (* abc9_required="616 362 245 208 147 68 66" *)
@@ -1498,6 +1591,46 @@ module RAM128X1D (
   assign DPO = mem[DPRA];
   wire clk = WCLK ^ IS_WCLK_INVERTED;
   always @(posedge clk) if (WE) mem[A] <= D;
+  generate
+    if (!IS_WCLK_INVERTED)
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+        //   plus 208ps to cross MUXF7
+        if (WE) (posedge WCLK => (SPO : D)) = 1359;
+        if (WE) (posedge WCLK => (DPO : D)) = 1359;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(D , posedge WCLK, 453);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, posedge WCLK, 654);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-830
+        $setup(A[0], posedge WCLK, 616);
+        $setup(A[1], posedge WCLK, 362);
+        $setup(A[2], posedge WCLK, 245);
+        $setup(A[3], posedge WCLK, 208);
+        $setup(A[4], posedge WCLK, 147);
+        $setup(A[5], posedge WCLK, 68);
+        $setup(A[6], posedge WCLK, 66);
+      endspecify
+    else
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+        //   plus 208ps to cross MUXF7
+        if (WE) (negedge WCLK => (SPO : D)) = 1359;
+        if (WE) (negedge WCLK => (DPO : D)) = 1359;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(D , negedge WCLK, 453);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, negedge WCLK, 654);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-830
+        $setup(A[0], negedge WCLK, 616);
+        $setup(A[1], negedge WCLK, 362);
+        $setup(A[2], negedge WCLK, 245);
+        $setup(A[3], negedge WCLK, 208);
+        $setup(A[4], negedge WCLK, 147);
+        $setup(A[5], negedge WCLK, 68);
+        $setup(A[6], negedge WCLK, 66);
+      endspecify
+  endgenerate
 endmodule
 
 module RAM256X1D (
@@ -1521,43 +1654,19 @@ endmodule
 // Multi port.
 
 module RAM32M (
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
-  (* abc9_arrival="1153 1188" *)
   output [1:0] DOA,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925
-  (* abc9_arrival="1161 1187" *)
   output [1:0] DOB,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993
-  (* abc9_arrival="1158 1180" *)
   output [1:0] DOC,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061
-  (* abc9_arrival="1163 1190" *)
   output [1:0] DOD,
   input  [4:0] ADDRA, ADDRB, ADDRC,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792-L802
-  (* abc9_required="245 208 147 68 66" *)
   input  [4:0] ADDRD,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
-  (* abc9_required="453 384" *)
   input  [1:0] DIA,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
-  (* abc9_required="461 354" *)
   input  [1:0] DIB,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
-  (* abc9_required="457 375" *)
   input  [1:0] DIC,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
-  (* abc9_required="310 334" *)
   input  [1:0] DID,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_WCLK_INVERTED" *)
   input        WCLK,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
-  (* abc9_required=654 *)
   input        WE
 );
   parameter [63:0] INIT_A = 64'h0000000000000000;
@@ -1581,6 +1690,87 @@ module RAM32M (
       mem_c[2*ADDRD+:2] <= DIC;
       mem_d[2*ADDRD+:2] <= DID;
     end
+  generate
+    if (!IS_WCLK_INVERTED)
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
+        if (WE) (posedge WCLK => (DOA[0] : DIA[0])) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
+        if (WE) (posedge WCLK => (DOA[1] : DIA[1])) = 1188;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
+        if (WE) (posedge WCLK => (DOB[0] : DIB[0])) = 1161;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925
+        if (WE) (posedge WCLK => (DOB[1] : DIB[1])) = 1187;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993
+        if (WE) (posedge WCLK => (DOC[0] : DIC[0])) = 1158;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
+        if (WE) (posedge WCLK => (DOC[1] : DIC[1])) = 1180;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
+        if (WE) (posedge WCLK => (DOD[0] : DID[0])) = 1163;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061
+        if (WE) (posedge WCLK => (DOD[1] : DID[1])) = 1190;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(ADDRD[0], posedge WCLK, 245);
+        $setup(ADDRD[1], posedge WCLK, 208);
+        $setup(ADDRD[2], posedge WCLK, 147);
+        $setup(ADDRD[3], posedge WCLK, 68);
+        $setup(ADDRD[4], posedge WCLK, 66);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
+        $setup(DIA[0], posedge WCLK, 453);
+        $setup(DIA[1], posedge WCLK, 384);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
+        $setup(DIB[0], posedge WCLK, 461);
+        $setup(DIB[1], posedge WCLK, 354);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
+        $setup(DIC[0], posedge WCLK, 457);
+        $setup(DIC[1], posedge WCLK, 375);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
+        $setup(DID[0], posedge WCLK, 310);
+        $setup(DID[1], posedge WCLK, 334);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, posedge WCLK, 654);
+      endspecify
+    else
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
+        if (WE) (negedge WCLK => (DOA[0] : DIA[0])) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
+        if (WE) (negedge WCLK => (DOA[1] : DIA[1])) = 1188;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
+        if (WE) (negedge WCLK => (DOB[0] : DIB[0])) = 1161;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925
+        if (WE) (negedge WCLK => (DOB[1] : DIB[1])) = 1187;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993
+        if (WE) (negedge WCLK => (DOC[0] : DIC[0])) = 1158;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
+        if (WE) (negedge WCLK => (DOC[1] : DIC[1])) = 1180;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
+        if (WE) (negedge WCLK => (DOD[0] : DID[0])) = 1163;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061
+        if (WE) (negedge WCLK => (DOD[1] : DID[1])) = 1190;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+        $setup(ADDRD[0], negedge WCLK, 245);
+        $setup(ADDRD[1], negedge WCLK, 208);
+        $setup(ADDRD[2], negedge WCLK, 147);
+        $setup(ADDRD[3], negedge WCLK, 68);
+        $setup(ADDRD[4], negedge WCLK, 66);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
+        $setup(DIA[0], negedge WCLK, 453);
+        $setup(DIA[1], negedge WCLK, 384);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
+        $setup(DIB[0], negedge WCLK, 461);
+        $setup(DIB[1], negedge WCLK, 354);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
+        $setup(DIC[0], negedge WCLK, 457);
+        $setup(DIC[1], negedge WCLK, 375);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
+        $setup(DID[0], negedge WCLK, 310);
+        $setup(DID[1], negedge WCLK, 334);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, posedge WCLK, 654);
+      endspecify
+  endgenerate
+
 endmodule
 
 module RAM32M16 (
@@ -1653,39 +1843,19 @@ module RAM32M16 (
 endmodule
 
 module RAM64M (
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
-  (* abc9_arrival=1153 *)
   output       DOA,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
-  (* abc9_arrival=1161 *)
   output       DOB,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
-  (* abc9_arrival=1158 *)
   output       DOC,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
-  (* abc9_arrival=1163 *)
   output       DOD,
   input  [5:0] ADDRA, ADDRB, ADDRC,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-L830
-  (* abc9_required="362 245 208 147 68 66" *)
   input  [5:0] ADDRD,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
-  (* abc9_required=384 *)
   input        DIA,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
-  (* abc9_required=354 *)
   input        DIB,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
-  (* abc9_required=375 *)
   input        DIC,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
-  (* abc9_required=310 *)
   input        DID,
   (* clkbuf_sink *)
   (* invertible_pin = "IS_WCLK_INVERTED" *)
   input        WCLK,
-  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
-  (* abc9_required=654 *)
   input        WE
 );
   parameter [63:0] INIT_A = 64'h0000000000000000;
@@ -1709,6 +1879,64 @@ module RAM64M (
       mem_c[ADDRD] <= DIC;
       mem_d[ADDRD] <= DID;
     end
+  generate
+    if (!IS_WCLK_INVERTED)
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
+        if (WE) (posedge WCLK => (DOA : DIA)) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
+        if (WE) (posedge WCLK => (DOB : DIB)) = 1161;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
+        if (WE) (posedge WCLK => (DOC : DIC)) = 1158;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
+        if (WE) (posedge WCLK => (DOD : DID)) = 1163;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-L830
+        $setup(ADDRD[0], posedge WCLK, 362);
+        $setup(ADDRD[1], posedge WCLK, 245);
+        $setup(ADDRD[2], posedge WCLK, 208);
+        $setup(ADDRD[3], posedge WCLK, 147);
+        $setup(ADDRD[4], posedge WCLK, 68);
+        $setup(ADDRD[5], posedge WCLK, 66);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
+        $setup(DIA, posedge WCLK, 384);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
+        $setup(DIB, posedge WCLK, 354);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
+        $setup(DIC, posedge WCLK, 375);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
+        $setup(DID, posedge WCLK, 310);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, posedge WCLK, 654);
+      endspecify
+    else
+      specify
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
+        if (WE) (negedge WCLK => (DOA : DIA)) = 1153;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
+        if (WE) (negedge WCLK => (DOB : DIB)) = 1161;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
+        if (WE) (negedge WCLK => (DOC : DIC)) = 1158;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
+        if (WE) (negedge WCLK => (DOD : DID)) = 1163;
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-L830
+        $setup(ADDRD[0], negedge WCLK, 362);
+        $setup(ADDRD[1], negedge WCLK, 245);
+        $setup(ADDRD[2], negedge WCLK, 208);
+        $setup(ADDRD[3], negedge WCLK, 147);
+        $setup(ADDRD[4], negedge WCLK, 68);
+        $setup(ADDRD[5], negedge WCLK, 66);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
+        $setup(DIA, negedge WCLK, 384);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
+        $setup(DIB, negedge WCLK, 354);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
+        $setup(DIC, negedge WCLK, 375);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
+        $setup(DID, negedge WCLK, 310);
+        // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+        $setup(WE, negedge WCLK, 654);
+      endspecify
+  endgenerate
 endmodule
 
 module RAM64M8 (