Merge branch 'master' into mmicko/anlogic

This commit is contained in:
Miodrag Milanović 2019-10-18 10:53:56 +02:00 committed by GitHub
commit 66fca65b58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
136 changed files with 2736 additions and 906 deletions

View File

@ -708,6 +708,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/various && bash run-test.sh +cd tests/various && bash run-test.sh
+cd tests/sat && bash run-test.sh +cd tests/sat && bash run-test.sh
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT) +cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
+cd tests/svtypes && bash run-test.sh $(SEEDOPT)
+cd tests/proc && bash run-test.sh +cd tests/proc && bash run-test.sh
+cd tests/opt && bash run-test.sh +cd tests/opt && bash run-test.sh
+cd tests/aiger && bash run-test.sh $(ABCOPT) +cd tests/aiger && bash run-test.sh $(ABCOPT)
@ -715,6 +716,8 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/ice40 && bash run-test.sh $(SEEDOPT) +cd tests/ice40 && bash run-test.sh $(SEEDOPT)
+cd tests/rpc && bash run-test.sh +cd tests/rpc && bash run-test.sh
+cd tests/anlogic && bash run-test.sh $(SEEDOPT) +cd tests/anlogic && bash run-test.sh $(SEEDOPT)
+cd tests/ecp5 && bash run-test.sh $(SEEDOPT)
+cd tests/xilinx && bash run-test.sh $(SEEDOPT)
@echo "" @echo ""
@echo " Passed \"make test\"." @echo " Passed \"make test\"."
@echo "" @echo ""

View File

@ -510,6 +510,8 @@ from SystemVerilog:
into a design with ``read_verilog``, all its packages are available to into a design with ``read_verilog``, all its packages are available to
SystemVerilog files being read into the same design afterwards. SystemVerilog files being read into the same design afterwards.
- typedefs are supported (including inside packages)
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether - SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
ports are inputs or outputs are supported. ports are inputs or outputs are supported.

View File

@ -203,7 +203,7 @@ struct XAigerWriter
// box ordering, but not individual AIG cells // box ordering, but not individual AIG cells
dict<SigBit, pool<IdString>> bit_drivers, bit_users; dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort; TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
bool abc_box_seen = false; bool abc9_box_seen = false;
for (auto cell : module->selected_cells()) { for (auto cell : module->selected_cells()) {
if (cell->type == "$_NOT_") if (cell->type == "$_NOT_")
@ -242,8 +242,8 @@ struct XAigerWriter
log_assert(!holes_mode); log_assert(!holes_mode);
RTLIL::Module* inst_module = module->design->module(cell->type); RTLIL::Module* inst_module = module->design->module(cell->type);
if (inst_module && inst_module->attributes.count("\\abc_box_id")) { if (inst_module && inst_module->attributes.count("\\abc9_box_id")) {
abc_box_seen = true; abc9_box_seen = true;
if (!holes_mode) { if (!holes_mode) {
toposort.node(cell->name); toposort.node(cell->name);
@ -291,10 +291,10 @@ struct XAigerWriter
if (is_output) { if (is_output) {
int arrival = 0; int arrival = 0;
if (port_wire) { if (port_wire) {
auto it = port_wire->attributes.find("\\abc_arrival"); auto it = port_wire->attributes.find("\\abc9_arrival");
if (it != port_wire->attributes.end()) { if (it != port_wire->attributes.end()) {
if (it->second.flags != 0) if (it->second.flags != 0)
log_error("Attribute 'abc_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
arrival = it->second.as_int(); arrival = it->second.as_int();
} }
} }
@ -318,7 +318,7 @@ struct XAigerWriter
//log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
} }
if (abc_box_seen) { if (abc9_box_seen) {
for (auto &it : bit_users) for (auto &it : bit_users)
if (bit_drivers.count(it.first)) if (bit_drivers.count(it.first))
for (auto driver_cell : bit_drivers.at(it.first)) for (auto driver_cell : bit_drivers.at(it.first))
@ -347,7 +347,7 @@ struct XAigerWriter
log_assert(cell); log_assert(cell);
RTLIL::Module* box_module = module->design->module(cell->type); RTLIL::Module* box_module = module->design->module(cell->type);
if (!box_module || !box_module->attributes.count("\\abc_box_id")) if (!box_module || !box_module->attributes.count("\\abc9_box_id"))
continue; continue;
bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */);
@ -398,7 +398,7 @@ struct XAigerWriter
else { else {
Wire *wire = module->addWire(NEW_ID, GetSize(w)); Wire *wire = module->addWire(NEW_ID, GetSize(w));
if (blackbox) if (blackbox)
wire->set_bool_attribute(ID(abc_padding)); wire->set_bool_attribute(ID(abc9_padding));
rhs = wire; rhs = wire;
cell->setPort(port_name, rhs); cell->setPort(port_name, rhs);
} }
@ -666,7 +666,7 @@ struct XAigerWriter
write_h_buffer(box_inputs); write_h_buffer(box_inputs);
write_h_buffer(box_outputs); write_h_buffer(box_outputs);
write_h_buffer(box_module->attributes.at("\\abc_box_id").as_int()); write_h_buffer(box_module->attributes.at("\\abc9_box_id").as_int());
write_h_buffer(box_count++); write_h_buffer(box_count++);
} }

View File

@ -740,22 +740,22 @@ void AigerReader::post_process()
log_assert(box_module); log_assert(box_module);
if (seen_boxes.insert(cell->type).second) { if (seen_boxes.insert(cell->type).second) {
auto it = box_module->attributes.find("\\abc_carry"); auto it = box_module->attributes.find("\\abc9_carry");
if (it != box_module->attributes.end()) { if (it != box_module->attributes.end()) {
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
auto carry_in_out = it->second.decode_string(); auto carry_in_out = it->second.decode_string();
auto pos = carry_in_out.find(','); auto pos = carry_in_out.find(',');
if (pos == std::string::npos) if (pos == std::string::npos)
log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type)); log_error("'abc9_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos)); auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
carry_in = box_module->wire(carry_in_name); carry_in = box_module->wire(carry_in_name);
if (!carry_in || !carry_in->port_input) if (!carry_in || !carry_in->port_input)
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str()); log_error("'abc9_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str());
auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1)); auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
carry_out = box_module->wire(carry_out_name); carry_out = box_module->wire(carry_out_name);
if (!carry_out || !carry_out->port_output) if (!carry_out || !carry_out->port_output)
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str()); log_error("'abc9_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str());
auto &ports = box_module->ports; auto &ports = box_module->ports;
for (auto jt = ports.begin(); jt != ports.end(); ) { for (auto jt = ports.begin(); jt != ports.end(); ) {

View File

@ -164,6 +164,8 @@ std::string AST::type2str(AstNodeType type)
X(AST_MODPORT) X(AST_MODPORT)
X(AST_MODPORTMEMBER) X(AST_MODPORTMEMBER)
X(AST_PACKAGE) X(AST_PACKAGE)
X(AST_WIRETYPE)
X(AST_TYPEDEF)
#undef X #undef X
default: default:
log_abort(); log_abort();
@ -206,6 +208,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
was_checked = false; was_checked = false;
range_valid = false; range_valid = false;
range_swapped = false; range_swapped = false;
is_custom_type = false;
port_id = 0; port_id = 0;
range_left = -1; range_left = -1;
range_right = 0; range_right = 0;

View File

@ -148,7 +148,10 @@ namespace AST
AST_INTERFACEPORTTYPE, AST_INTERFACEPORTTYPE,
AST_MODPORT, AST_MODPORT,
AST_MODPORTMEMBER, AST_MODPORTMEMBER,
AST_PACKAGE AST_PACKAGE,
AST_WIRETYPE,
AST_TYPEDEF
}; };
// convert an node type to a string (e.g. for debug output) // convert an node type to a string (e.g. for debug output)
@ -174,7 +177,7 @@ namespace AST
// node content - most of it is unused in most node types // node content - most of it is unused in most node types
std::string str; std::string str;
std::vector<RTLIL::State> bits; std::vector<RTLIL::State> bits;
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized; bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized, is_custom_type;
int port_id, range_left, range_right; int port_id, range_left, range_right;
uint32_t integer; uint32_t integer;
double realvalue; double realvalue;

View File

@ -863,6 +863,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_PACKAGE: case AST_PACKAGE:
case AST_MODPORT: case AST_MODPORT:
case AST_MODPORTMEMBER: case AST_MODPORTMEMBER:
case AST_TYPEDEF:
break; break;
case AST_INTERFACEPORT: { case AST_INTERFACEPORT: {
// If a port in a module with unknown type is found, mark it with the attribute 'is_interface' // If a port in a module with unknown type is found, mark it with the attribute 'is_interface'

View File

@ -318,7 +318,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
} }
// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.) // activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX) if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF)
const_fold = true; const_fold = true;
if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM))
const_fold = true; const_fold = true;
@ -336,6 +336,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::map<std::string, AstNode*> this_wire_scope; std::map<std::string, AstNode*> this_wire_scope;
for (size_t i = 0; i < children.size(); i++) { for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i]; AstNode *node = children[i];
if (node->type == AST_WIRE) { if (node->type == AST_WIRE) {
if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
for (auto c : node->children[0]->children) { for (auto c : node->children[0]->children) {
@ -405,14 +406,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
this_wire_scope[node->str] = node; this_wire_scope[node->str] = node;
} }
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL) { node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL ||
node->type == AST_TYPEDEF) {
backup_scope[node->str] = current_scope[node->str]; backup_scope[node->str] = current_scope[node->str];
current_scope[node->str] = node; current_scope[node->str] = node;
} }
} }
for (size_t i = 0; i < children.size(); i++) { for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i]; AstNode *node = children[i];
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY) if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF)
while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM))
did_something = true; did_something = true;
} }
@ -780,6 +782,99 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
delete_children(); delete_children();
} }
// resolve typedefs
if (type == AST_TYPEDEF) {
log_assert(children.size() == 1);
log_assert(children[0]->type == AST_WIRE || children[0]->type == AST_MEMORY);
while(children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param))
did_something = true;
log_assert(!children[0]->is_custom_type);
}
// resolve types of wires
if (type == AST_WIRE || type == AST_MEMORY) {
if (is_custom_type) {
log_assert(children.size() >= 1);
log_assert(children[0]->type == AST_WIRETYPE);
if (!current_scope.count(children[0]->str))
log_file_error(filename, linenum, "Unknown identifier `%s' used as type name\n", children[0]->str.c_str());
AstNode *resolved_type = current_scope.at(children[0]->str);
if (resolved_type->type != AST_TYPEDEF)
log_file_error(filename, linenum, "`%s' does not name a type\n", children[0]->str.c_str());
log_assert(resolved_type->children.size() == 1);
AstNode *templ = resolved_type->children[0];
// Remove type reference
delete children[0];
children.erase(children.begin());
// Ensure typedef itself is fully simplified
while(templ->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
if (type == AST_WIRE)
type = templ->type;
is_reg = templ->is_reg;
is_logic = templ->is_logic;
is_signed = templ->is_signed;
is_string = templ->is_string;
is_custom_type = templ->is_custom_type;
range_valid = templ->range_valid;
range_swapped = templ->range_swapped;
range_left = templ->range_left;
range_right = templ->range_right;
// Insert clones children from template at beginning
for (int i = 0; i < GetSize(templ->children); i++)
children.insert(children.begin() + i, templ->children[i]->clone());
if (type == AST_MEMORY && GetSize(children) == 1) {
// Single-bit memories must have [0:0] range
AstNode *rng = new AstNode(AST_RANGE);
rng->children.push_back(AstNode::mkconst_int(0, true));
rng->children.push_back(AstNode::mkconst_int(0, true));
children.insert(children.begin(), rng);
}
did_something = true;
}
log_assert(!is_custom_type);
}
// resolve types of parameters
if (type == AST_LOCALPARAM || type == AST_PARAMETER) {
if (is_custom_type) {
log_assert(children.size() == 2);
log_assert(children[1]->type == AST_WIRETYPE);
if (!current_scope.count(children[1]->str))
log_file_error(filename, linenum, "Unknown identifier `%s' used as type name\n", children[1]->str.c_str());
AstNode *resolved_type = current_scope.at(children[1]->str);
if (resolved_type->type != AST_TYPEDEF)
log_file_error(filename, linenum, "`%s' does not name a type\n", children[1]->str.c_str());
log_assert(resolved_type->children.size() == 1);
AstNode *templ = resolved_type->children[0];
delete children[1];
children.pop_back();
// Ensure typedef itself is fully simplified
while(templ->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
if (templ->type == AST_MEMORY)
log_file_error(filename, linenum, "unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str());
is_signed = templ->is_signed;
is_string = templ->is_string;
is_custom_type = templ->is_custom_type;
range_valid = templ->range_valid;
range_swapped = templ->range_swapped;
range_left = templ->range_left;
range_right = templ->range_right;
for (auto template_child : templ->children)
children.push_back(template_child->clone());
did_something = true;
}
log_assert(!is_custom_type);
}
// resolve constant prefixes // resolve constant prefixes
if (type == AST_PREFIX) { if (type == AST_PREFIX) {
if (children[0]->type != AST_CONSTANT) { if (children[0]->type != AST_CONSTANT) {
@ -1194,7 +1289,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_BLOCK && str.empty()) if (type == AST_BLOCK && str.empty())
{ {
for (size_t i = 0; i < children.size(); i++) for (size_t i = 0; i < children.size(); i++)
if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF)
log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n"); log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n");
} }
@ -1206,7 +1301,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> new_children; std::vector<AstNode*> new_children;
for (size_t i = 0; i < children.size(); i++) for (size_t i = 0; i < children.size(); i++)
if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) { if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) {
children[i]->simplify(false, false, false, stage, -1, false, false); children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]); current_ast_mod->children.push_back(children[i]);
current_scope[children[i]->str] = children[i]; current_scope[children[i]->str] = children[i];
@ -2906,7 +3001,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
} }
} }
if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE) && name_map.count(str) > 0)
str = name_map[str]; str = name_map[str];
std::map<std::string, std::string> backup_name_map; std::map<std::string, std::string> backup_name_map;
@ -2914,7 +3009,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
for (size_t i = 0; i < children.size(); i++) { for (size_t i = 0; i < children.size(); i++) {
AstNode *child = children[i]; AstNode *child = children[i];
if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM ||
child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL) { child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF) {
if (backup_name_map.size() == 0) if (backup_name_map.size() == 0)
backup_name_map = name_map; backup_name_map = name_map;
std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix; std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
@ -2945,6 +3040,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
child->expand_genblock(index_var, prefix, name_map); child->expand_genblock(index_var, prefix, name_map);
} }
if (backup_name_map.size() > 0) if (backup_name_map.size() > 0)
name_map.swap(backup_name_map); name_map.swap(backup_name_map);
} }
@ -2998,6 +3094,9 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
uint32_t children_flags = 0; uint32_t children_flags = 0;
int lhs_children_counter = 0; int lhs_children_counter = 0;
if (type == AST_TYPEDEF)
return; // don't touch content of typedefs
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
{ {
// mark all memories that are used in a complex expression on the left side of an assignment // mark all memories that are used in a complex expression on the left side of an assignment
@ -3155,6 +3254,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
if (type == AST_FUNCTION || type == AST_TASK) if (type == AST_FUNCTION || type == AST_TASK)
return false; return false;
if (type == AST_TYPEDEF)
return false;
if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast)) if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
{ {
log_assert(children[0]->type == AST_CONSTANT); log_assert(children[0]->type == AST_CONSTANT);

View File

@ -174,6 +174,12 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
if (module == nullptr) if (module == nullptr)
goto error; goto error;
if (!strcmp(cmd, ".blackbox"))
{
module->attributes["\\blackbox"] = RTLIL::Const(1);
continue;
}
if (!strcmp(cmd, ".end")) if (!strcmp(cmd, ".end"))
{ {
for (auto &wp : wideports_cache) for (auto &wp : wideports_cache)
@ -280,7 +286,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
goto error_with_reason; goto error_with_reason;
} }
module->rename(lastcell, p); module->rename(lastcell, RTLIL::escape_id(p));
continue; continue;
} }

View File

@ -28,14 +28,13 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
extern char **environ;
#endif #endif
#include "libs/json11/json11.hpp" #include "libs/json11/json11.hpp"
#include "libs/sha1/sha1.h" #include "libs/sha1/sha1.h"
#include "kernel/yosys.h" #include "kernel/yosys.h"
extern char **environ;
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
#if defined(_WIN32) #if defined(_WIN32)
@ -238,6 +237,11 @@ struct RpcModule : RTLIL::Module {
#if defined(_WIN32) #if defined(_WIN32)
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
struct HandleRpcServer : RpcServer { struct HandleRpcServer : RpcServer {
HANDLE hsend, hrecv; HANDLE hsend, hrecv;

View File

@ -155,7 +155,7 @@ struct specify_rise_fall {
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id %type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id
%type <boolean> opt_signed opt_property unique_case_attr %type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr %type <al> attr case_attr
@ -206,6 +206,7 @@ design:
task_func_decl design | task_func_decl design |
param_decl design | param_decl design |
localparam_decl design | localparam_decl design |
typedef_decl design |
package design | package design |
interface design | interface design |
/* empty */; /* empty */;
@ -290,6 +291,9 @@ hierarchical_id:
$$ = $1; $$ = $1;
}; };
hierarchical_type_id:
'(' hierarchical_id ')' { $$ = $2; };
module: module:
attr TOK_MODULE TOK_ID { attr TOK_MODULE TOK_ID {
do_not_require_port_stubs = false; do_not_require_port_stubs = false;
@ -324,13 +328,13 @@ single_module_para:
astbuf1 = new AstNode(AST_PARAMETER); astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
append_attr(astbuf1, $1); append_attr(astbuf1, $1);
} param_signed param_integer param_range single_param_decl | } param_type single_param_decl |
attr TOK_LOCALPARAM { attr TOK_LOCALPARAM {
if (astbuf1) delete astbuf1; if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_LOCALPARAM); astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
append_attr(astbuf1, $1); append_attr(astbuf1, $1);
} param_signed param_integer param_range single_param_decl | } param_type single_param_decl |
single_param_decl; single_param_decl;
module_args_opt: module_args_opt:
@ -426,6 +430,7 @@ package_body:
package_body package_body_stmt |; package_body package_body_stmt |;
package_body_stmt: package_body_stmt:
typedef_decl |
localparam_decl; localparam_decl;
interface: interface:
@ -452,7 +457,7 @@ interface_body:
interface_body interface_body_stmt |; interface_body interface_body_stmt |;
interface_body_stmt: interface_body_stmt:
param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt | param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
modport_stmt; modport_stmt;
non_opt_delay: non_opt_delay:
@ -475,8 +480,14 @@ wire_type:
}; };
wire_type_token_list: wire_type_token_list:
wire_type_token | wire_type_token_list wire_type_token | wire_type_token |
wire_type_token_io ; wire_type_token_list wire_type_token |
wire_type_token_io |
hierarchical_type_id {
astbuf3->is_custom_type = true;
astbuf3->children.push_back(new AstNode(AST_WIRETYPE));
astbuf3->children.back()->str = *$1;
};
wire_type_token_io: wire_type_token_io:
TOK_INPUT { TOK_INPUT {
@ -591,7 +602,7 @@ module_body:
/* empty */; /* empty */;
module_body_stmt: module_body_stmt:
task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl: checker_decl:
@ -1149,12 +1160,20 @@ param_range:
} }
}; };
param_type:
param_signed param_integer param_real param_range |
hierarchical_type_id {
astbuf1->is_custom_type = true;
astbuf1->children.push_back(new AstNode(AST_WIRETYPE));
astbuf1->children.back()->str = *$1;
};
param_decl: param_decl:
attr TOK_PARAMETER { attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER); astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
append_attr(astbuf1, $1); append_attr(astbuf1, $1);
} param_signed param_integer param_real param_range param_decl_list ';' { } param_type param_decl_list ';' {
delete astbuf1; delete astbuf1;
}; };
@ -1163,7 +1182,7 @@ localparam_decl:
astbuf1 = new AstNode(AST_LOCALPARAM); astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
append_attr(astbuf1, $1); append_attr(astbuf1, $1);
} param_signed param_integer param_real param_range param_decl_list ';' { } param_type param_decl_list ';' {
delete astbuf1; delete astbuf1;
}; };
@ -1327,7 +1346,7 @@ wire_name:
if ($2 != NULL) { if ($2 != NULL) {
if (node->is_input || node->is_output) if (node->is_input || node->is_output)
frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions."); frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions.");
if (!astbuf2) { if (!astbuf2 && !node->is_custom_type) {
AstNode *rng = new AstNode(AST_RANGE); AstNode *rng = new AstNode(AST_RANGE);
rng->children.push_back(AstNode::mkconst_int(0, true)); rng->children.push_back(AstNode::mkconst_int(0, true));
rng->children.push_back(AstNode::mkconst_int(0, true)); rng->children.push_back(AstNode::mkconst_int(0, true));
@ -1377,6 +1396,45 @@ assign_expr:
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3)); ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3));
}; };
typedef_decl:
TOK_TYPEDEF wire_type range TOK_ID range_or_multirange ';' {
astbuf1 = $2;
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions.");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true));
}
}
if (astbuf2 && astbuf2->children.size() != 2)
frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
if (astbuf2)
astbuf1->children.push_back(astbuf2);
if ($5 != NULL) {
if (!astbuf2) {
AstNode *rng = new AstNode(AST_RANGE);
rng->children.push_back(AstNode::mkconst_int(0, true));
rng->children.push_back(AstNode::mkconst_int(0, true));
astbuf1->children.push_back(rng);
}
astbuf1->type = AST_MEMORY;
auto *rangeNode = $5;
if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) {
// SV array size [n], rewrite as [n-1:0]
rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true));
rangeNode->children.push_back(AstNode::mkconst_int(0, false));
}
astbuf1->children.push_back(rangeNode);
}
ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1));
ast_stack.back()->children.back()->str = *$4;
};
cell_stmt: cell_stmt:
attr TOK_ID { attr TOK_ID {
astbuf1 = new AstNode(AST_CELL); astbuf1 = new AstNode(AST_CELL);
@ -1823,7 +1881,7 @@ simple_behavioral_stmt:
// this production creates the obligatory if-else shift/reduce conflict // this production creates the obligatory if-else shift/reduce conflict
behavioral_stmt: behavioral_stmt:
defattr | assert | wire_decl | param_decl | localparam_decl | defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl |
non_opt_delay behavioral_stmt | non_opt_delay behavioral_stmt |
simple_behavioral_stmt ';' | ';' | simple_behavioral_stmt ';' | ';' |
hierarchical_id attr { hierarchical_id attr {

View File

@ -3554,6 +3554,12 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
if (width_ != other.width_) if (width_ != other.width_)
return false; return false;
// Without this, SigSpec() == SigSpec(State::S0, 0) will fail
// since the RHS will contain one SigChunk of width 0 causing
// the size check below to fail
if (width_ == 0)
return true;
pack(); pack();
other.pack(); other.pack();

View File

@ -609,8 +609,11 @@ struct RTLIL::Const
std::string decode_string() const; std::string decode_string() const;
inline int size() const { return bits.size(); } inline int size() const { return bits.size(); }
inline bool empty() const { return bits.empty(); }
inline RTLIL::State &operator[](int index) { return bits.at(index); } inline RTLIL::State &operator[](int index) { return bits.at(index); }
inline const RTLIL::State &operator[](int index) const { return bits.at(index); } inline const RTLIL::State &operator[](int index) const { return bits.at(index); }
inline decltype(bits)::iterator begin() { return bits.begin(); }
inline decltype(bits)::iterator end() { return bits.end(); }
bool is_fully_zero() const; bool is_fully_zero() const;
bool is_fully_ones() const; bool is_fully_ones() const;

View File

@ -50,6 +50,9 @@ struct EquivOptPass:public ScriptPass
log(" -multiclock\n"); log(" -multiclock\n");
log(" run clk2fflogic before equivalence checking.\n"); log(" run clk2fflogic before equivalence checking.\n");
log("\n"); log("\n");
log(" -async2sync\n");
log(" run async2sync before equivalence checking.\n");
log("\n");
log(" -undef\n"); log(" -undef\n");
log(" enable modelling of undef states during equiv_induct.\n"); log(" enable modelling of undef states during equiv_induct.\n");
log("\n"); log("\n");
@ -59,7 +62,7 @@ struct EquivOptPass:public ScriptPass
} }
std::string command, techmap_opts; std::string command, techmap_opts;
bool assert, undef, multiclock; bool assert, undef, multiclock, async2sync;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -68,6 +71,7 @@ struct EquivOptPass:public ScriptPass
assert = false; assert = false;
undef = false; undef = false;
multiclock = false; multiclock = false;
async2sync = false;
} }
void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
@ -101,6 +105,10 @@ struct EquivOptPass:public ScriptPass
multiclock = true; multiclock = true;
continue; continue;
} }
if (args[argidx] == "-async2sync") {
async2sync = true;
continue;
}
break; break;
} }
@ -120,6 +128,9 @@ struct EquivOptPass:public ScriptPass
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
if (async2sync && multiclock)
log_cmd_error("The '-async2sync' and '-multiclock' options are mutually exclusive!\n");
log_header(design, "Executing EQUIV_OPT pass.\n"); log_header(design, "Executing EQUIV_OPT pass.\n");
log_push(); log_push();
@ -157,8 +168,8 @@ struct EquivOptPass:public ScriptPass
if (check_label("prove")) { if (check_label("prove")) {
if (multiclock || help_mode) if (multiclock || help_mode)
run("clk2fflogic", "(only with -multiclock)"); run("clk2fflogic", "(only with -multiclock)");
if (!multiclock || help_mode) if (async2sync || help_mode)
run("async2sync", "(only without -multiclock)"); run("async2sync", " (only with -async2sync)");
run("equiv_make gold gate equiv"); run("equiv_make gold gate equiv");
if (help_mode) if (help_mode)
run("equiv_induct [-undef] equiv"); run("equiv_induct [-undef] equiv");

140
passes/pmgen/generate.h Normal file
View File

@ -0,0 +1,140 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef PMGEN_GENERATE
#define PMGEN_GENERATE
#define GENERATE_PATTERN(pmclass, pattern) \
generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
void pmtest_addports(Module *module)
{
pool<SigBit> driven_bits, used_bits;
SigMap sigmap(module);
int icnt = 0, ocnt = 0;
for (auto cell : module->cells())
for (auto conn : cell->connections())
{
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
used_bits.insert(bit);
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
driven_bits.insert(bit);
}
for (auto wire : vector<Wire*>(module->wires()))
{
SigSpec ibits, obits;
for (auto bit : sigmap(wire)) {
if (!used_bits.count(bit))
obits.append(bit);
if (!driven_bits.count(bit))
ibits.append(bit);
}
if (!ibits.empty()) {
Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
w->port_input = true;
module->connect(ibits, w);
}
if (!obits.empty()) {
Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
w->port_output = true;
module->connect(w, obits);
}
}
module->fixup_ports();
}
template <class pm>
void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
{
log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
int modcnt = 0;
int maxmodcnt = 100;
int maxsubcnt = 4;
int timeout = 0;
vector<Module*> mods;
while (modcnt < maxmodcnt)
{
int submodcnt = 0, itercnt = 0, cellcnt = 0;
Module *mod = design->addModule(NEW_ID);
while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
{
if (timeout++ > 10000)
log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
pm matcher(mod, mod->cells());
matcher.rng(1);
matcher.rngseed += modcnt;
matcher.rng(1);
matcher.rngseed += submodcnt;
matcher.rng(1);
matcher.rngseed += itercnt;
matcher.rng(1);
matcher.rngseed += cellcnt;
matcher.rng(1);
if (GetSize(mod->cells()) != cellcnt)
{
bool found_match = false;
run(matcher, [&](){ found_match = true; });
cellcnt = GetSize(mod->cells());
if (found_match) {
Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
pmclass, pattern, modcnt++));
log("Creating module %s with %d cells.\n", log_id(m), cellcnt);
mod->cloneInto(m);
pmtest_addports(m);
mods.push_back(m);
submodcnt++;
timeout = 0;
}
}
matcher.generate_mode = true;
run(matcher, [](){});
}
if (submodcnt && maxsubcnt < (1 << 16))
maxsubcnt *= 2;
design->remove(mod);
}
Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern));
log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods));
for (auto mod : mods) {
Cell *c = m->addCell(mod->name, mod->name);
for (auto port : mod->ports) {
Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port)));
c->setPort(port, w);
}
}
pmtest_addports(m);
}
#endif

View File

@ -9,3 +9,7 @@ match lut
index <SigSpec> port(lut, \I1) === port(carry, \I0) index <SigSpec> port(lut, \I1) === port(carry, \I0)
index <SigSpec> port(lut, \I2) === port(carry, \I1) index <SigSpec> port(lut, \I2) === port(carry, \I1)
endmatch endmatch
code
accept;
endcode

View File

@ -24,8 +24,11 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
bool did_something; bool did_something;
dict<SigBit, State> initbits;
pool<SigBit> rminitbits;
#include "passes/pmgen/peepopt_pm.h" #include "passes/pmgen/peepopt_pm.h"
#include "generate.h"
struct PeepoptPass : public Pass { struct PeepoptPass : public Pass {
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
@ -40,27 +43,86 @@ struct PeepoptPass : public Pass {
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
std::string genmode;
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
{ {
// if (args[argidx] == "-singleton") { if (args[argidx] == "-generate" && argidx+1 < args.size()) {
// singleton_mode = true; genmode = args[++argidx];
// continue; continue;
// } }
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto module : design->selected_modules()) { if (!genmode.empty())
{
initbits.clear();
rminitbits.clear();
if (genmode == "shiftmul")
GENERATE_PATTERN(peepopt_pm, shiftmul);
else if (genmode == "muldiv")
GENERATE_PATTERN(peepopt_pm, muldiv);
else if (genmode == "dffmux")
GENERATE_PATTERN(peepopt_pm, dffmux);
else
log_abort();
return;
}
for (auto module : design->selected_modules())
{
did_something = true; did_something = true;
while (did_something) {
while (did_something)
{
did_something = false; did_something = false;
peepopt_pm pm(module, module->selected_cells()); initbits.clear();
rminitbits.clear();
peepopt_pm pm(module);
for (auto w : module->wires()) {
auto it = w->attributes.find(ID(init));
if (it != w->attributes.end()) {
SigSpec sig = pm.sigmap(w);
Const val = it->second;
int len = std::min(GetSize(sig), GetSize(val));
for (int i = 0; i < len; i++) {
if (sig[i].wire == nullptr)
continue;
if (val[i] != State::S0 && val[i] != State::S1)
continue;
initbits[sig[i]] = val[i];
}
}
}
pm.setup(module->selected_cells());
pm.run_shiftmul(); pm.run_shiftmul();
pm.run_muldiv(); pm.run_muldiv();
pm.run_dffmux(); pm.run_dffmux();
for (auto w : module->wires()) {
auto it = w->attributes.find(ID(init));
if (it != w->attributes.end()) {
SigSpec sig = pm.sigmap(w);
Const &val = it->second;
int len = std::min(GetSize(sig), GetSize(val));
for (int i = 0; i < len; i++) {
if (rminitbits.count(sig[i]))
val[i] = State::Sx;
}
}
}
initbits.clear();
rminitbits.clear();
} }
} }
} }

View File

@ -8,21 +8,23 @@ match dff
select GetSize(port(dff, \D)) > 1 select GetSize(port(dff, \D)) > 1
endmatch endmatch
code sigD
sigD = port(dff, \D);
endcode
match rstmux match rstmux
select rstmux->type == $mux select rstmux->type == $mux
select GetSize(port(rstmux, \Y)) > 1 select GetSize(port(rstmux, \Y)) > 1
index <SigSpec> port(rstmux, \Y) === port(dff, \D) index <SigSpec> port(rstmux, \Y) === sigD
choice <IdString> BA {\B, \A} choice <IdString> BA {\B, \A}
select port(rstmux, BA).is_fully_const() select port(rstmux, BA).is_fully_const()
set rstmuxBA BA set rstmuxBA BA
optional semioptional
endmatch endmatch
code sigD code sigD
if (rstmux) if (rstmux)
sigD = port(rstmux, rstmuxBA == \B ? \A : \B); sigD = port(rstmux, rstmuxBA == \B ? \A : \B);
else
sigD = port(dff, \D);
endcode endcode
match cemux match cemux
@ -32,67 +34,111 @@ match cemux
choice <IdString> AB {\A, \B} choice <IdString> AB {\A, \B}
index <SigSpec> port(cemux, AB) === port(dff, \Q) index <SigSpec> port(cemux, AB) === port(dff, \Q)
set cemuxAB AB set cemuxAB AB
semioptional
endmatch endmatch
code code
SigSpec D = port(cemux, cemuxAB == \A ? \B : \A); if (!cemux && !rstmux)
SigSpec Q = port(dff, \Q); reject;
endcode
code
Const rst; Const rst;
SigSpec D;
if (cemux) {
D = port(cemux, cemuxAB == \A ? \B : \A);
if (rstmux) if (rstmux)
rst = port(rstmux, rstmuxBA).as_const(); rst = port(rstmux, rstmuxBA).as_const();
else
rst = Const(State::Sx, GetSize(D));
}
else {
log_assert(rstmux);
D = port(rstmux, rstmuxBA == \B ? \A : \B);
rst = port(rstmux, rstmuxBA).as_const();
}
SigSpec Q = port(dff, \Q);
int width = GetSize(D); int width = GetSize(D);
SigSpec &ceA = cemux->connections_.at(\A); SigSpec dffD = dff->getPort(\D);
SigSpec &ceB = cemux->connections_.at(\B); SigSpec dffQ = dff->getPort(\Q);
SigSpec &ceY = cemux->connections_.at(\Y);
SigSpec &dffD = dff->connections_.at(\D);
SigSpec &dffQ = dff->connections_.at(\Q);
if (D[width-1] == D[width-2]) { Const initval;
did_something = true; for (auto b : Q) {
auto it = initbits.find(b);
SigBit sign = D[width-1]; initval.bits.push_back(it == initbits.end() ? State::Sx : it->second);
bool is_signed = sign.wire;
int i;
for (i = width-1; i >= 2; i--) {
if (!is_signed) {
module->connect(Q[i], sign);
if (D[i-1] != sign || (rst.size() && rst[i-1] != rst[width-1]))
break;
} }
else {
auto cmpx = [=](State lhs, State rhs) {
if (lhs == State::Sx || rhs == State::Sx)
return true;
return lhs == rhs;
};
int i = width-1;
while (i > 1) {
if (D[i] != D[i-1])
break;
if (!cmpx(rst[i], rst[i-1]))
break;
if (!cmpx(initval[i], initval[i-1]))
break;
if (!cmpx(rst[i], initval[i]))
break;
rminitbits.insert(Q[i]);
module->connect(Q[i], Q[i-1]); module->connect(Q[i], Q[i-1]);
if (D[i-2] != sign || (rst.size() && rst[i-1] != rst[width-1])) i--;
break;
} }
} if (i < width-1) {
did_something = true;
ceA.remove(i, width-i); if (cemux) {
ceB.remove(i, width-i); SigSpec ceA = cemux->getPort(\A);
ceY.remove(i, width-i); SigSpec ceB = cemux->getPort(\B);
SigSpec ceY = cemux->getPort(\Y);
ceA.remove(i, width-1-i);
ceB.remove(i, width-1-i);
ceY.remove(i, width-1-i);
cemux->setPort(\A, ceA);
cemux->setPort(\B, ceB);
cemux->setPort(\Y, ceY);
cemux->fixup_parameters(); cemux->fixup_parameters();
dffD.remove(i, width-i); blacklist(cemux);
dffQ.remove(i, width-i);
dff->fixup_parameters();
log("dffcemux pattern in %s: dff=%s, cemux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux), width-i);
accept;
} }
else { if (rstmux) {
SigSpec rstA = rstmux->getPort(\A);
SigSpec rstB = rstmux->getPort(\B);
SigSpec rstY = rstmux->getPort(\Y);
rstA.remove(i, width-1-i);
rstB.remove(i, width-1-i);
rstY.remove(i, width-1-i);
rstmux->setPort(\A, rstA);
rstmux->setPort(\B, rstB);
rstmux->setPort(\Y, rstY);
rstmux->fixup_parameters();
blacklist(rstmux);
}
dffD.remove(i, width-1-i);
dffQ.remove(i, width-1-i);
dff->setPort(\D, dffD);
dff->setPort(\Q, dffQ);
dff->fixup_parameters();
blacklist(dff);
log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux, "n/a"), log_id(rstmux, "n/a"), width-1-i);
width = i+1;
}
if (cemux) {
SigSpec ceA = cemux->getPort(\A);
SigSpec ceB = cemux->getPort(\B);
SigSpec ceY = cemux->getPort(\Y);
int count = 0; int count = 0;
for (int i = width-1; i >= 0; i--) { for (int i = width-1; i >= 0; i--) {
if (D[i].wire) if (D[i].wire)
continue; continue;
Wire *w = Q[i].wire; if (cmpx(rst[i], D[i].data) && cmpx(initval[i], D[i].data)) {
auto it = w->attributes.find(\init);
State init;
if (it != w->attributes.end())
init = it->second[Q[i].offset];
else
init = State::Sx;
if (init == State::Sx || init == D[i].data) {
count++; count++;
rminitbits.insert(Q[i]);
module->connect(Q[i], D[i]); module->connect(Q[i], D[i]);
ceA.remove(i); ceA.remove(i);
ceB.remove(i); ceB.remove(i);
@ -101,13 +147,25 @@ code
dffQ.remove(i); dffQ.remove(i);
} }
} }
if (count > 0) { if (count > 0)
{
did_something = true; did_something = true;
cemux->setPort(\A, ceA);
cemux->setPort(\B, ceB);
cemux->setPort(\Y, ceY);
cemux->fixup_parameters(); cemux->fixup_parameters();
blacklist(cemux);
dff->setPort(\D, dffD);
dff->setPort(\Q, dffQ);
dff->fixup_parameters(); dff->fixup_parameters();
log("dffcemux pattern in %s: dff=%s, cemux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), count); blacklist(dff);
log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), log_id(rstmux, "n/a"), count);
}
} }
if (did_something)
accept; accept;
}
endcode endcode

View File

@ -362,6 +362,7 @@ with open(outfile, "w") as f:
print(" Module *module;", file=f) print(" Module *module;", file=f)
print(" SigMap sigmap;", file=f) print(" SigMap sigmap;", file=f)
print(" std::function<void()> on_accept;", file=f) print(" std::function<void()> on_accept;", file=f)
print(" bool setup_done;", file=f)
print(" bool generate_mode;", file=f) print(" bool generate_mode;", file=f)
print(" int accept_cnt;", file=f) print(" int accept_cnt;", file=f)
print("", file=f) print("", file=f)
@ -477,7 +478,17 @@ with open(outfile, "w") as f:
print("", file=f) print("", file=f)
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(module), generate_mode(false), rngseed(12345678) {", file=f) print(" module(module), sigmap(module), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
print(" setup(cells);", file=f)
print(" }", file=f)
print("", file=f)
print(" {}_pm(Module *module) :".format(prefix), file=f)
print(" module(module), sigmap(module), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
print(" }", file=f)
print("", file=f)
print(" void setup(const vector<Cell*> &cells) {", file=f)
for current_pattern in sorted(patterns.keys()): for current_pattern in sorted(patterns.keys()):
for s, t in sorted(udata_types[current_pattern].items()): for s, t in sorted(udata_types[current_pattern].items()):
if t.endswith("*"): if t.endswith("*"):
@ -485,6 +496,8 @@ with open(outfile, "w") as f:
else: else:
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f) print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
current_pattern = None current_pattern = None
print(" log_assert(!setup_done);", file=f)
print(" setup_done = true;", file=f)
print(" for (auto port : module->ports)", file=f) print(" for (auto port : module->ports)", file=f)
print(" add_siguser(module->wire(port), nullptr);", file=f) print(" add_siguser(module->wire(port), nullptr);", file=f)
print(" for (auto cell : module->cells())", file=f) print(" for (auto cell : module->cells())", file=f)
@ -539,6 +552,7 @@ with open(outfile, "w") as f:
for current_pattern in sorted(patterns.keys()): for current_pattern in sorted(patterns.keys()):
print(" int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f) print(" int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
print(" log_assert(setup_done);", file=f)
print(" accept_cnt = 0;", file=f) print(" accept_cnt = 0;", file=f)
print(" on_accept = on_accept_f;", file=f) print(" on_accept = on_accept_f;", file=f)
print(" rollback = 0;", file=f) print(" rollback = 0;", file=f)

View File

@ -23,13 +23,11 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
// for peepopt_pm
bool did_something;
#include "passes/pmgen/test_pmgen_pm.h" #include "passes/pmgen/test_pmgen_pm.h"
#include "passes/pmgen/ice40_dsp_pm.h" #include "passes/pmgen/ice40_dsp_pm.h"
#include "passes/pmgen/xilinx_srl_pm.h" #include "passes/pmgen/xilinx_srl_pm.h"
#include "passes/pmgen/peepopt_pm.h"
#include "generate.h"
void reduce_chain(test_pmgen_pm &pm) void reduce_chain(test_pmgen_pm &pm)
{ {
@ -118,123 +116,6 @@ void opt_eqpmux(test_pmgen_pm &pm)
log(" -> %s (%s)\n", log_id(c), log_id(c->type)); log(" -> %s (%s)\n", log_id(c), log_id(c->type));
} }
#define GENERATE_PATTERN(pmclass, pattern) \
generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
void pmtest_addports(Module *module)
{
pool<SigBit> driven_bits, used_bits;
SigMap sigmap(module);
int icnt = 0, ocnt = 0;
for (auto cell : module->cells())
for (auto conn : cell->connections())
{
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
used_bits.insert(bit);
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
driven_bits.insert(bit);
}
for (auto wire : vector<Wire*>(module->wires()))
{
SigSpec ibits, obits;
for (auto bit : sigmap(wire)) {
if (!used_bits.count(bit))
obits.append(bit);
if (!driven_bits.count(bit))
ibits.append(bit);
}
if (!ibits.empty()) {
Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
w->port_input = true;
module->connect(ibits, w);
}
if (!obits.empty()) {
Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
w->port_output = true;
module->connect(w, obits);
}
}
module->fixup_ports();
}
template <class pm>
void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
{
log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
int modcnt = 0;
int maxmodcnt = 100;
int maxsubcnt = 4;
int timeout = 0;
vector<Module*> mods;
while (modcnt < maxmodcnt)
{
int submodcnt = 0, itercnt = 0, cellcnt = 0;
Module *mod = design->addModule(NEW_ID);
while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
{
if (timeout++ > 10000)
log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
pm matcher(mod, mod->cells());
matcher.rng(1);
matcher.rngseed += modcnt;
matcher.rng(1);
matcher.rngseed += submodcnt;
matcher.rng(1);
matcher.rngseed += itercnt;
matcher.rng(1);
matcher.rngseed += cellcnt;
matcher.rng(1);
if (GetSize(mod->cells()) != cellcnt)
{
bool found_match = false;
run(matcher, [&](){ found_match = true; });
cellcnt = GetSize(mod->cells());
if (found_match) {
Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
pmclass, pattern, modcnt++));
log("Creating module %s with %d cells.\n", log_id(m), cellcnt);
mod->cloneInto(m);
pmtest_addports(m);
mods.push_back(m);
submodcnt++;
timeout = 0;
}
}
matcher.generate_mode = true;
run(matcher, [](){});
}
if (submodcnt && maxsubcnt < (1 << 16))
maxsubcnt *= 2;
design->remove(mod);
}
Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern));
log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods));
for (auto mod : mods) {
Cell *c = m->addCell(mod->name, mod->name);
for (auto port : mod->ports) {
Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port)));
c->setPort(port, w);
}
}
pmtest_addports(m);
}
struct TestPmgenPass : public Pass { struct TestPmgenPass : public Pass {
TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { } TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE
@ -355,12 +236,6 @@ struct TestPmgenPass : public Pass {
if (pattern == "xilinx_srl.variable") if (pattern == "xilinx_srl.variable")
return GENERATE_PATTERN(xilinx_srl_pm, variable); return GENERATE_PATTERN(xilinx_srl_pm, variable);
if (pattern == "peepopt-muldiv")
return GENERATE_PATTERN(peepopt_pm, muldiv);
if (pattern == "peepopt-shiftmul")
return GENERATE_PATTERN(peepopt_pm, shiftmul);
log_cmd_error("Unknown pattern: %s\n", pattern.c_str()); log_cmd_error("Unknown pattern: %s\n", pattern.c_str());
} }

View File

@ -20,6 +20,7 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include <deque>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
@ -608,8 +609,13 @@ struct XilinxDspPass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto module : design->selected_modules()) { for (auto module : design->selected_modules()) {
// Experimental feature: pack $add/$sub cells with
// (* use_dsp48="simd" *) into DSP48E1's using its
// SIMD feature
xilinx_simd_pack(module, module->selected_cells()); xilinx_simd_pack(module, module->selected_cells());
// Match for all features ([ABDMP][12]?REG, pre-adder,
// post-adder, pattern detector, etc.) except for CREG
{ {
xilinx_dsp_pm pm(module, module->selected_cells()); xilinx_dsp_pm pm(module, module->selected_cells());
pm.run_xilinx_dsp_pack(xilinx_dsp_pack); pm.run_xilinx_dsp_pack(xilinx_dsp_pack);
@ -618,14 +624,17 @@ struct XilinxDspPass : public Pass {
// is no guarantee that the cell ordering corresponds // is no guarantee that the cell ordering corresponds
// to the "expected" case (i.e. the order in which // to the "expected" case (i.e. the order in which
// they appear in the source) thus the possiblity // they appear in the source) thus the possiblity
// existed that a register got packed as CREG into a // existed that a register got packed as a CREG into a
// downstream DSP that should have otherwise been a // downstream DSP that should have otherwise been a
// PREG of an upstream DSP that had not been pattern // PREG of an upstream DSP that had not been visited
// matched yet // yet
{ {
xilinx_dsp_CREG_pm pm(module, module->selected_cells()); xilinx_dsp_CREG_pm pm(module, module->selected_cells());
pm.run_xilinx_dsp_packC(xilinx_dsp_packC); pm.run_xilinx_dsp_packC(xilinx_dsp_packC);
} }
// Lastly, identify and utilise PCOUT -> PCIN,
// ACOUT -> ACIN, and BCOUT-> BCIN dedicated cascade
// chains
{ {
xilinx_dsp_cascade_pm pm(module, module->selected_cells()); xilinx_dsp_cascade_pm pm(module, module->selected_cells());
pm.run_xilinx_dsp_cascade(); pm.run_xilinx_dsp_cascade();

View File

@ -1,3 +1,57 @@
// This file describes the main pattern matcher setup (of three total) that
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc
// At a high level, it works as follows:
// ( 1) Starting from a DSP48E1 cell
// ( 2) Match the driver of the 'A' input to a possible $dff cell (ADREG)
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using a subpattern discussed below)
// If ADREG matched, treat 'A' input as input of ADREG
// ( 3) Match the driver of the 'A' and 'D' inputs for a possible $add cell
// (pre-adder)
// ( 4) If pre-adder was present, find match 'A' input for A2REG
// If pre-adder was not present, move ADREG to A2REG
// If A2REG, then match 'A' input for A1REG
// ( 5) Match 'B' input for B2REG
// If B2REG, then match 'B' input for B1REG
// ( 6) Match 'D' input for DREG
// ( 7) Match 'P' output that exclusively drives an MREG
// ( 8) Match 'P' output that exclusively drives one of two inputs to an $add
// cell (post-adder).
// The other input to the adder is assumed to come in from the 'C' input
// (note: 'P' -> 'C' connections that exist for accumulators are
// recognised in xilinx_dsp.cc).
// ( 9) Match 'P' output that exclusively drives a PREG
// (10) If post-adder and PREG both present, match for a $mux cell driving
// the 'C' input, where one of the $mux's inputs is the PREG output.
// This indicates an accumulator situation, and one where a $mux exists
// to override the accumulated value:
// +--------------------------------+
// | ____ |
// +--| \ |
// |$mux|-+ |
// 'C' ---|____/ | |
// | /-------\ +----+ |
// +----+ +-| post- |___|PREG|---+ 'P'
// |MREG|------ | adder | +----+
// +----+ \-------/
// (11) If PREG present, match for a greater-than-or-equal $ge cell attached
// to the 'P' output where it is compared to a constant that is a
// power-of-2: e.g. `assign overflow = (PREG >= 2**40);`
// In this scenario, the pattern detector functionality of a DSP48E1 can
// to implement this function
// Notes:
// - The intention of this pattern matcher is for it to be compatible with
// DSP48E1 cells inferred from multiply operations by Yosys, as well as for
// user instantiations that may already contain the cells being packed...
// (though the latter is currently untested)
// - Since the $dff-with-optional-clock-enable-or-reset-mux pattern is used
// for each *REG match, it has been factored out into two subpatterns:
// in_dffe and out_dffe located at the bottom of this file.
// - Matching for pattern detector features is currently incomplete. For
// example, matching for underflow as well as overflow detection is
// possible, as would auto-reset, enabling saturated arithmetic, detecting
// custom patterns, etc.
pattern xilinx_dsp_pack pattern xilinx_dsp_pack
state <SigBit> clock state <SigBit> clock
@ -5,12 +59,11 @@ state <SigSpec> sigA sigB sigC sigD sigM sigP
state <IdString> postAddAB postAddMuxAB state <IdString> postAddAB postAddMuxAB
state <bool> ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffDcepol ffMcepol ffPcepol state <bool> ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffDcepol ffMcepol ffPcepol
state <bool> ffArstpol ffADrstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol state <bool> ffArstpol ffADrstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol
state <Cell*> ffAD ffADcemux ffADrstmux ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux state <Cell*> ffAD ffADcemux ffADrstmux ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux
state <Cell*> ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux state <Cell*> ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux
state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
// subpattern // Variables used for subpatterns
state <SigSpec> argQ argD state <SigSpec> argQ argD
state <bool> ffcepol ffrstpol state <bool> ffcepol ffrstpol
state <int> ffoffset state <int> ffoffset
@ -19,6 +72,7 @@ udata <SigBit> dffclock
udata <Cell*> dff dffcemux dffrstmux udata <Cell*> dff dffcemux dffrstmux
udata <bool> dffcepol dffrstpol udata <bool> dffcepol dffrstpol
// (1) Starting from a DSP48E1 cell
match dsp match dsp
select dsp->type.in(\DSP48E1) select dsp->type.in(\DSP48E1)
endmatch endmatch
@ -50,17 +104,21 @@ code sigA sigB sigC sigD sigM clock
sigM.append(P[i]); sigM.append(P[i]);
} }
log_assert(nusers(P.extract_end(i)) <= 1); log_assert(nusers(P.extract_end(i)) <= 1);
// This sigM could have no users if downstream sinks (e.g. $add) is
// narrower than $mul result, for example
if (sigM.empty())
reject;
} }
else else
sigM = P; sigM = P;
// This sigM could have no users if downstream $add
// is narrower than $mul result, for example
if (sigM.empty())
reject;
clock = port(dsp, \CLK, SigBit()); clock = port(dsp, \CLK, SigBit());
endcode endcode
// (2) Match the driver of the 'A' input to a possible $dff cell (ADREG)
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using a subpattern discussed above)
// If matched, treat 'A' input as input of ADREG
code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock
if (param(dsp, \ADREG).as_int() == 0) { if (param(dsp, \ADREG).as_int() == 0) {
argQ = sigA; argQ = sigA;
@ -81,6 +139,8 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock
} }
endcode endcode
// (3) Match the driver of the 'A' and 'D' inputs for a possible $add cell
// (pre-adder)
match preAdd match preAdd
if sigD.empty() || sigD.is_fully_zero() if sigD.empty() || sigD.is_fully_zero()
// Ensure that preAdder not already used // Ensure that preAdder not already used
@ -106,11 +166,12 @@ code sigA sigD
if (preAdd) { if (preAdd) {
sigA = port(preAdd, \A); sigA = port(preAdd, \A);
sigD = port(preAdd, \B); sigD = port(preAdd, \B);
if (GetSize(sigA) < GetSize(sigD))
std::swap(sigA, sigD);
} }
endcode endcode
// (4) If pre-adder was present, find match 'A' input for A2REG
// If pre-adder was not present, move ADREG to A2REG
// Then match 'A' input for A1REG
code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol ffA1 ffA1cemux ffA1rstmux ffA1cepol code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol ffA1 ffA1cemux ffA1rstmux ffA1cepol
// Only search for ffA2 if there was a pre-adder // Only search for ffA2 if there was a pre-adder
// (otherwise ffA2 would have been matched as ffAD) // (otherwise ffA2 would have been matched as ffAD)
@ -173,6 +234,8 @@ ffA1_end: ;
} }
endcode endcode
// (5) Match 'B' input for B2REG
// If B2REG, then match 'B' input for B1REG
code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemux ffB1rstmux ffB1cepol code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemux ffB1rstmux ffB1cepol
if (param(dsp, \BREG).as_int() == 0) { if (param(dsp, \BREG).as_int() == 0) {
argQ = sigB; argQ = sigB;
@ -222,6 +285,7 @@ ffB1_end: ;
} }
endcode endcode
// (6) Match 'D' input for DREG
code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock
if (param(dsp, \DREG).as_int() == 0) { if (param(dsp, \DREG).as_int() == 0) {
argQ = sigD; argQ = sigD;
@ -242,6 +306,7 @@ code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock
} }
endcode endcode
// (7) Match 'P' output that exclusively drives an MREG
code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock
if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) { if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) {
argD = sigM; argD = sigM;
@ -263,6 +328,11 @@ code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock
sigP = sigM; sigP = sigM;
endcode endcode
// (8) Match 'P' output that exclusively drives one of two inputs to an $add
// cell (post-adder).
// The other input to the adder is assumed to come in from the 'C' input
// (note: 'P' -> 'C' connections that exist for accumulators are
// recognised in xilinx_dsp.cc).
match postAdd match postAdd
// Ensure that Z mux is not already used // Ensure that Z mux is not already used
if port(dsp, \OPMODE, SigSpec()).extract(4,3).is_fully_zero() if port(dsp, \OPMODE, SigSpec()).extract(4,3).is_fully_zero()
@ -277,7 +347,9 @@ match postAdd
index <SigBit> port(postAdd, AB)[0] === sigP[0] index <SigBit> port(postAdd, AB)[0] === sigP[0]
filter GetSize(port(postAdd, AB)) >= GetSize(sigP) filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
filter port(postAdd, AB).extract(0, GetSize(sigP)) == sigP filter port(postAdd, AB).extract(0, GetSize(sigP)) == sigP
filter port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(sigP[GetSize(sigP)-1], GetSize(port(postAdd, AB))-GetSize(sigP)) // Check that remainder of AB is a sign-extension
define <bool> AB_SIGNED (param(postAdd, AB == \A ? \A_SIGNED : \B_SIGNED).as_bool())
filter port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(AB_SIGNED ? sigP[GetSize(sigP)-1] : State::S0, GetSize(port(postAdd, AB))-GetSize(sigP))
set postAddAB AB set postAddAB AB
optional optional
endmatch endmatch
@ -289,6 +361,7 @@ code sigC sigP
} }
endcode endcode
// (9) Match 'P' output that exclusively drives a PREG
code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock
if (param(dsp, \PREG).as_int() == 0) { if (param(dsp, \PREG).as_int() == 0) {
int users = 2; int users = 2;
@ -314,6 +387,19 @@ code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock
} }
endcode endcode
// (10) If post-adder and PREG both present, match for a $mux cell driving
// the 'C' input, where one of the $mux's inputs is the PREG output.
// This indicates an accumulator situation, and one where a $mux exists
// to override the accumulated value:
// +--------------------------------+
// | ____ |
// +--| \ |
// |$mux|-+ |
// 'C' ---|____/ | |
// | /-------\ +----+ |
// +----+ +-| post- |___|PREG|---+ 'P'
// |MREG|------ | adder | +----+
// +----+ \-------/
match postAddMux match postAddMux
if postAdd if postAdd
if ffP if ffP
@ -331,6 +417,11 @@ code sigC
sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
endcode endcode
// (11) If PREG present, match for a greater-than-or-equal $ge cell attached to
// the 'P' output where it is compared to a constant that is a power-of-2:
// e.g. `assign overflow = (PREG >= 2**40);`
// In this scenario, the pattern detector functionality of a DSP48E1 can
// to implement this function
match overflow match overflow
if ffP if ffP
if param(dsp, \USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET" if param(dsp, \USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET"
@ -349,22 +440,45 @@ endcode
// ####################### // #######################
// Subpattern for matching against input registers, based on knowledge of the
// 'Q' input. Typically, identifying registers with clock-enable and reset
// capability would be a task would be handled by other Yosys passes such as
// dff2dffe, but since DSP inference happens much before this, these patterns
// have to be manually identified.
// At a high level:
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// one that exclusively drives the 'D' input of the $dff, with one of its
// $mux inputs being fully zero
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
subpattern in_dffe subpattern in_dffe
arg argD argQ clock arg argD argQ clock
code code
dff = nullptr; dff = nullptr;
for (auto c : argQ.chunks()) { for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
if (!c.wire) if (!c.wire)
reject; reject;
// Abandon matches when 'Q' has the keep attribute set
if (c.wire->get_bool_attribute(\keep)) if (c.wire->get_bool_attribute(\keep))
reject; reject;
Const init = c.wire->attributes.at(\init, State::Sx); // Abandon matches when 'Q' has a non-zero init attribute set
if (!init.is_fully_undef() && !init.is_fully_zero()) // (not supported by DSP48E1)
Const init = c.wire->attributes.at(\init, Const());
if (!init.empty())
for (auto b : init.extract(c.offset, c.width))
if (b != State::Sx && b != State::S0)
reject; reject;
} }
endcode endcode
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
match ff match ff
select ff->type.in($dff) select ff->type.in($dff)
// DSP48E1 does not support clock inversion // DSP48E1 does not support clock inversion
@ -377,14 +491,12 @@ match ff
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
set ffoffset offset set ffoffset offset
endmatch endmatch
code argQ argD code argQ argD
{
if (clock != SigBit() && port(ff, \CLK) != clock)
reject;
SigSpec Q = port(ff, \Q); SigSpec Q = port(ff, \Q);
dff = ff; dff = ff;
dffclock = port(ff, \CLK); dffclock = port(ff, \CLK);
@ -396,9 +508,11 @@ code argQ argD
// has two (ff, ffrstmux) users // has two (ff, ffrstmux) users
if (nusers(dffD) > 2) if (nusers(dffD) > 2)
argD = SigSpec(); argD = SigSpec();
}
endcode endcode
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// exclusively drives the 'D' input of the $dff, with one of the $mux
// inputs being fully zero
match ffrstmux match ffrstmux
if !argD.empty() if !argD.empty()
select ffrstmux->type.in($mux) select ffrstmux->type.in($mux)
@ -430,6 +544,10 @@ code argD
dffrstmux = nullptr; dffrstmux = nullptr;
endcode endcode
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
match ffcemux match ffcemux
if !argD.empty() if !argD.empty()
select ffcemux->type.in($mux) select ffcemux->type.in($mux)
@ -454,16 +572,32 @@ endcode
// ####################### // #######################
// Subpattern for matching against output registers, based on knowledge of the
// 'D' input.
// At a high level:
// (1) Starting from an optional $mux cell that implements clock enable
// semantics --- one where the given 'D' argument (partially or fully)
// drives one of its two inputs
// (2) Starting from, or continuing onto, another optional $mux cell that
// implements synchronous reset semantics --- one where the given 'D'
// argument (or the clock enable $mux output) drives one of its two inputs
// and where the other input is fully zero
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
// output of the previous clock enable or reset $mux cells)
subpattern out_dffe subpattern out_dffe
arg argD argQ clock arg argD argQ clock
code code
dff = nullptr; dff = nullptr;
for (auto c : argD.chunks()) for (auto c : argD.chunks())
// Abandon matches when 'D' has the keep attribute set
if (c.wire->get_bool_attribute(\keep)) if (c.wire->get_bool_attribute(\keep))
reject; reject;
endcode endcode
// (1) Starting from an optional $mux cell that implements clock enable
// semantics --- one where the given 'D' argument (partially or fully)
// drives one of its two inputs
match ffcemux match ffcemux
select ffcemux->type.in($mux) select ffcemux->type.in($mux)
// ffcemux output must have two users: ffcemux and ff.D // ffcemux output must have two users: ffcemux and ff.D
@ -502,6 +636,10 @@ code argD argQ
} }
endcode endcode
// (2) Starting from, or continuing onto, another optional $mux cell that
// implements synchronous reset semantics --- one where the given 'D'
// argument (or the clock enable $mux output) drives one of its two inputs
// and where the other input is fully zero
match ffrstmux match ffrstmux
select ffrstmux->type.in($mux) select ffrstmux->type.in($mux)
// ffrstmux output must have two users: ffrstmux and ff.D // ffrstmux output must have two users: ffrstmux and ff.D
@ -540,6 +678,8 @@ code argD argQ
} }
endcode endcode
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
// output of the previous clock enable or reset $mux cells)
match ff match ff
select ff->type.in($dff) select ff->type.in($dff)
// DSP48E1 does not support clock inversion // DSP48E1 does not support clock inversion
@ -556,14 +696,12 @@ match ff
// Check that FF.Q is connected to CE-mux // Check that FF.Q is connected to CE-mux
filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
set ffoffset offset set ffoffset offset
endmatch endmatch
code argQ code argQ
if (ff) {
if (clock != SigBit() && port(ff, \CLK) != clock)
reject;
SigSpec D = port(ff, \D); SigSpec D = port(ff, \D);
SigSpec Q = port(ff, \Q); SigSpec Q = port(ff, \Q);
if (!ffcemux) { if (!ffcemux) {
@ -571,17 +709,17 @@ code argQ
argQ.replace(D, Q); argQ.replace(D, Q);
} }
// Abandon matches when 'Q' has a non-zero init attribute set
// (not supported by DSP48E1)
for (auto c : argQ.chunks()) { for (auto c : argQ.chunks()) {
Const init = c.wire->attributes.at(\init, State::Sx); Const init = c.wire->attributes.at(\init, Const());
if (!init.is_fully_undef() && !init.is_fully_zero()) if (!init.empty())
for (auto b : init.extract(c.offset, c.width))
if (b != State::Sx && b != State::S0)
reject; reject;
} }
dff = ff; dff = ff;
dffQ = argQ; dffQ = argQ;
dffclock = port(ff, \CLK); dffclock = port(ff, \CLK);
}
// No enable/reset mux possible without flop
else if (dffcemux || dffrstmux)
reject;
endcode endcode

View File

@ -1,3 +1,26 @@
// This file describes the second of three pattern matcher setups that
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc
// At a high level, it works as follows:
// (1) Starting from a DSP48E1 cell that (a) doesn't have a CREG already,
// and (b) uses the 'C' port
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using a subpattern discussed below)
// Notes:
// - Running CREG packing after xilinx_dsp_pack is necessary since there is no
// guarantee that the cell ordering corresponds to the "expected" case (i.e.
// the order in which they appear in the source) thus the possiblity existed
// that a register got packed as a CREG into a downstream DSP that should
// have otherwise been a PREG of an upstream DSP that had not been visited
// yet
// - The reason this is separated out from the xilinx_dsp.pmg file is
// for efficiency --- each *.pmg file creates a class of the same basename,
// which when constructed, creates a custom database tailored to the
// pattern(s) contained within. Since the pattern in this file must be
// executed after the pattern contained in xilinx_dsp.pmg, it is necessary
// to reconstruct this database. Separating the two patterns into
// independent files causes two smaller, more specific, databases.
pattern xilinx_dsp_packC pattern xilinx_dsp_packC
udata <std::function<SigSpec(const SigSpec&)>> unextend udata <std::function<SigSpec(const SigSpec&)>> unextend
@ -6,7 +29,7 @@ state <SigSpec> sigC sigP
state <bool> ffCcepol ffCrstpol state <bool> ffCcepol ffCrstpol
state <Cell*> ffC ffCcemux ffCrstmux state <Cell*> ffC ffCcemux ffCrstmux
// subpattern // Variables used for subpatterns
state <SigSpec> argQ argD state <SigSpec> argQ argD
state <bool> ffcepol ffrstpol state <bool> ffcepol ffrstpol
state <int> ffoffset state <int> ffoffset
@ -15,13 +38,15 @@ udata <SigBit> dffclock
udata <Cell*> dff dffcemux dffrstmux udata <Cell*> dff dffcemux dffrstmux
udata <bool> dffcepol dffrstpol udata <bool> dffcepol dffrstpol
// (1) Starting from a DSP48E1 cell that (a) doesn't have a CREG already,
// and (b) uses the 'C' port
match dsp match dsp
select dsp->type.in(\DSP48E1) select dsp->type.in(\DSP48E1)
select param(dsp, \CREG, 1).as_int() == 0 select param(dsp, \CREG, 1).as_int() == 0
select nusers(port(dsp, \C, SigSpec())) > 1 select nusers(port(dsp, \C, SigSpec())) > 1
endmatch endmatch
code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC sigP clock code sigC sigP clock
unextend = [](const SigSpec &sig) { unextend = [](const SigSpec &sig) {
int i; int i;
for (i = GetSize(sig)-1; i > 0; i--) for (i = GetSize(sig)-1; i > 0; i--)
@ -48,11 +73,13 @@ code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC sigP clock
else else
sigP = P; sigP = P;
if (sigC == sigP)
reject;
clock = port(dsp, \CLK, SigBit()); clock = port(dsp, \CLK, SigBit());
endcode
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using the in_dffe subpattern)
code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock
argQ = sigC; argQ = sigC;
subpattern(in_dffe); subpattern(in_dffe);
if (dff) { if (dff) {
@ -77,22 +104,44 @@ endcode
// ####################### // #######################
// Subpattern for matching against input registers, based on knowledge of the
// 'Q' input. Typically, identifying registers with clock-enable and reset
// capability would be a task would be handled by other Yosys passes such as
// dff2dffe, but since DSP inference happens much before this, these patterns
// have to be manually identified.
// At a high level:
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// one that exclusively drives the 'D' input of the $dff, with one of its
// $mux inputs being fully zero
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
subpattern in_dffe subpattern in_dffe
arg argD argQ clock arg argD argQ clock
code code
dff = nullptr; dff = nullptr;
for (auto c : argQ.chunks()) { for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
if (!c.wire) if (!c.wire)
reject; reject;
// Abandon matches when 'Q' has the keep attribute set
if (c.wire->get_bool_attribute(\keep)) if (c.wire->get_bool_attribute(\keep))
reject; reject;
Const init = c.wire->attributes.at(\init, State::Sx); // Abandon matches when 'Q' has a non-zero init attribute set
if (!init.is_fully_undef() && !init.is_fully_zero()) // (not supported by DSP48E1)
Const init = c.wire->attributes.at(\init, Const());
for (auto b : init.extract(c.offset, c.width))
if (b != State::Sx && b != State::S0)
reject; reject;
} }
endcode endcode
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
match ff match ff
select ff->type.in($dff) select ff->type.in($dff)
// DSP48E1 does not support clock inversion // DSP48E1 does not support clock inversion
@ -105,14 +154,12 @@ match ff
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
set ffoffset offset set ffoffset offset
endmatch endmatch
code argQ argD code argQ argD
{
if (clock != SigBit() && port(ff, \CLK) != clock)
reject;
SigSpec Q = port(ff, \Q); SigSpec Q = port(ff, \Q);
dff = ff; dff = ff;
dffclock = port(ff, \CLK); dffclock = port(ff, \CLK);
@ -124,9 +171,11 @@ code argQ argD
// has two (ff, ffrstmux) users // has two (ff, ffrstmux) users
if (nusers(dffD) > 2) if (nusers(dffD) > 2)
argD = SigSpec(); argD = SigSpec();
}
endcode endcode
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// exclusively drives the 'D' input of the $dff, with one of the $mux
// inputs being fully zero
match ffrstmux match ffrstmux
if !argD.empty() if !argD.empty()
select ffrstmux->type.in($mux) select ffrstmux->type.in($mux)
@ -158,6 +207,10 @@ code argD
dffrstmux = nullptr; dffrstmux = nullptr;
endcode endcode
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
match ffcemux match ffcemux
if !argD.empty() if !argD.empty()
select ffcemux->type.in($mux) select ffcemux->type.in($mux)

View File

@ -1,3 +1,46 @@
// This file describes the third of three pattern matcher setups that
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc
// At a high level, it works as follows:
// (1) Starting from a DSP48E1 cell that (a) has the Z multiplexer
// (controlled by OPMODE[6:4]) set to zero and (b) doesn't already
// use the 'PCOUT' port
// (2.1) Match another DSP48E1 cell that (a) does not have the CREG enabled,
// (b) has its Z multiplexer output set to the 'C' port, which is
// driven by the 'P' output of the previous DSP cell, and (c) has its
// 'PCIN' port unused
// (2.2) Same as (2.1) but with the 'C' port driven by the 'P' output of the
// previous DSP cell right-shifted by 17 bits
// (3) For this subequent DSP48E1 match (i.e. PCOUT -> PCIN cascade exists)
// if (a) the previous DSP48E1 uses either the A2REG or A1REG, (b) this
// DSP48 does not use A2REG nor A1REG, (c) this DSP48E1 does not already
// have an ACOUT -> ACIN cascade, (d) the previous DSP does not already
// use its ACOUT port, then examine if an ACOUT -> ACIN cascade
// opportunity exists by matching for a $dff-with-optional-clock-enable-
// or-reset and checking that the 'D' input of this register is the same
// as the 'A' input of the previous DSP
// (4) Same as (3) but for BCOUT -> BCIN cascade
// (5) Recursively go to (2.1) until no more matches possible, keeping track
// of the longest possible chain found
// (6) The longest chain is then divided into chunks of no more than
// MAX_DSP_CASCADE in length (to prevent long cascades that exceed the
// height of a DSP column) with each DSP in each chunk being rewritten
// to use [ABP]COUT -> [ABP]CIN cascading as appropriate
// Notes:
// - Currently, [AB]COUT -> [AB]COUT cascades (3 or 4) are only considered
// if a PCOUT -> PCIN cascade is (2.1 or 2.2) first identified; this need
// not be the case --- [AB] cascades can exist independently of a P cascade
// (though all three cascades must come from the same DSP). This situation
// is not handled currently.
// - In addition, [AB]COUT -> [AB]COUT cascades (3 or 4) are currently
// conservative in that they examine the situation where (a) the previous
// DSP has [AB]2REG or [AB]1REG enabled, (b) that the downstream DSP has no
// registers enabled, and (c) that there exists only one additional register
// between the upstream and downstream DSPs. This can certainly be relaxed
// to identify situations ranging from (i) neither DSP uses any registers,
// to (ii) upstream DSP has 2 registers, downstream DSP has 2 registers, and
// there exists a further 2 registers between them. This remains a TODO
// item.
pattern xilinx_dsp_cascade pattern xilinx_dsp_cascade
udata <std::function<SigSpec(const SigSpec&)>> unextend udata <std::function<SigSpec(const SigSpec&)>> unextend
@ -6,7 +49,7 @@ state <Cell*> next
state <SigSpec> clock state <SigSpec> clock
state <int> AREG BREG state <int> AREG BREG
// subpattern // Variables used for subpatterns
state <SigSpec> argQ argD state <SigSpec> argQ argD
state <bool> ffcepol ffrstpol state <bool> ffcepol ffrstpol
state <int> ffoffset state <int> ffoffset
@ -19,12 +62,19 @@ code
#define MAX_DSP_CASCADE 20 #define MAX_DSP_CASCADE 20
endcode endcode
// (1) Starting from a DSP48E1 cell that (a) has the Z multiplexer
// (controlled by OPMODE[6:4]) set to zero and (b) doesn't already
// use the 'PCOUT' port
match first match first
select first->type.in(\DSP48E1) select first->type.in(\DSP48E1)
select port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000") select port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000")
select nusers(port(first, \PCOUT, SigSpec())) <= 1 select nusers(port(first, \PCOUT, SigSpec())) <= 1
endmatch endmatch
// (6) The longest chain is then divided into chunks of no more than
// MAX_DSP_CASCADE in length (to prevent long cascades that exceed the
// height of a DSP column) with each DSP in each chunk being rewritten
// to use [ABP]COUT -> [ABP]CIN cascading as appropriate
code code
longest_chain.clear(); longest_chain.clear();
chain.emplace_back(first, -1, -1, -1); chain.emplace_back(first, -1, -1, -1);
@ -106,6 +156,10 @@ subpattern tail
arg first arg first
arg next arg next
// (2.1) Match another DSP48E1 cell that (a) does not have the CREG enabled,
// (b) has its Z multiplexer output set to the 'C' port, which is
// driven by the 'P' output of the previous DSP cell, and (c) has its
// 'PCIN' port unused
match nextP match nextP
select nextP->type.in(\DSP48E1) select nextP->type.in(\DSP48E1)
select !param(nextP, \CREG, State::S1).as_bool() select !param(nextP, \CREG, State::S1).as_bool()
@ -116,6 +170,8 @@ match nextP
semioptional semioptional
endmatch endmatch
// (2.2) Same as (2.1) but with the 'C' port driven by the 'P' output of the
// previous DSP cell right-shifted by 17 bits
match nextP_shift17 match nextP_shift17
if !nextP if !nextP
select nextP_shift17->type.in(\DSP48E1) select nextP_shift17->type.in(\DSP48E1)
@ -145,6 +201,14 @@ code next
} }
endcode endcode
// (3) For this subequent DSP48E1 match (i.e. PCOUT -> PCIN cascade exists)
// if (a) the previous DSP48E1 uses either the A2REG or A1REG, (b) this
// DSP48 does not use A2REG nor A1REG, (c) this DSP48E1 does not already
// have an ACOUT -> ACIN cascade, (d) the previous DSP does not already
// use its ACOUT port, then examine if an ACOUT -> ACIN cascade
// opportunity exists by matching for a $dff-with-optional-clock-enable-
// or-reset and checking that the 'D' input of this register is the same
// as the 'A' input of the previous DSP
code argQ clock AREG code argQ clock AREG
AREG = -1; AREG = -1;
if (next) { if (next) {
@ -152,7 +216,6 @@ code argQ clock AREG
if (param(prev, \AREG, 2).as_int() > 0 && if (param(prev, \AREG, 2).as_int() > 0 &&
param(next, \AREG, 2).as_int() > 0 && param(next, \AREG, 2).as_int() > 0 &&
param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
port(next, \ACIN, SigSpec()).is_fully_zero() &&
nusers(port(prev, \ACOUT, SigSpec())) <= 1) { nusers(port(prev, \ACOUT, SigSpec())) <= 1) {
argQ = unextend(port(next, \A)); argQ = unextend(port(next, \A));
clock = port(prev, \CLK); clock = port(prev, \CLK);
@ -174,6 +237,7 @@ reject_AREG: ;
} }
endcode endcode
// (4) Same as (3) but for BCOUT -> BCIN cascade
code argQ clock BREG code argQ clock BREG
BREG = -1; BREG = -1;
if (next) { if (next) {
@ -203,13 +267,14 @@ reject_BREG: ;
} }
endcode endcode
// (5) Recursively go to (2.1) until no more matches possible, recording the
// longest possible chain
code code
if (next) { if (next) {
chain.emplace_back(next, nextP_shift17 ? 17 : nextP ? 0 : -1, AREG, BREG); chain.emplace_back(next, nextP_shift17 ? 17 : nextP ? 0 : -1, AREG, BREG);
SigSpec sigC = unextend(port(next, \C)); SigSpec sigC = unextend(port(next, \C));
// TODO: Cannot use 'reject' since semioptional
if (nextP_shift17) { if (nextP_shift17) {
if (GetSize(sigC)+17 <= GetSize(port(std::get<0>(chain.back()), \P)) && if (GetSize(sigC)+17 <= GetSize(port(std::get<0>(chain.back()), \P)) &&
port(std::get<0>(chain.back()), \P).extract(17, GetSize(sigC)) != sigC) port(std::get<0>(chain.back()), \P).extract(17, GetSize(sigC)) != sigC)
@ -232,22 +297,44 @@ endcode
// ####################### // #######################
// Subpattern for matching against input registers, based on knowledge of the
// 'Q' input. Typically, identifying registers with clock-enable and reset
// capability would be a task would be handled by other Yosys passes such as
// dff2dffe, but since DSP inference happens much before this, these patterns
// have to be manually identified.
// At a high level:
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// one that exclusively drives the 'D' input of the $dff, with one of its
// $mux inputs being fully zero
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
subpattern in_dffe subpattern in_dffe
arg argD argQ clock arg argD argQ clock
code code
dff = nullptr; dff = nullptr;
for (auto c : argQ.chunks()) { for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
if (!c.wire) if (!c.wire)
reject; reject;
// Abandon matches when 'Q' has the keep attribute set
if (c.wire->get_bool_attribute(\keep)) if (c.wire->get_bool_attribute(\keep))
reject; reject;
Const init = c.wire->attributes.at(\init, State::Sx); // Abandon matches when 'Q' has a non-zero init attribute set
if (!init.is_fully_undef() && !init.is_fully_zero()) // (not supported by DSP48E1)
Const init = c.wire->attributes.at(\init, Const());
for (auto b : init.extract(c.offset, c.width))
if (b != State::Sx && b != State::S0)
reject; reject;
} }
endcode endcode
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
match ff match ff
select ff->type.in($dff) select ff->type.in($dff)
// DSP48E1 does not support clock inversion // DSP48E1 does not support clock inversion
@ -260,14 +347,12 @@ match ff
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
set ffoffset offset set ffoffset offset
endmatch endmatch
code argQ argD code argQ argD
{
if (clock != SigBit() && port(ff, \CLK) != clock)
reject;
SigSpec Q = port(ff, \Q); SigSpec Q = port(ff, \Q);
dff = ff; dff = ff;
dffclock = port(ff, \CLK); dffclock = port(ff, \CLK);
@ -279,9 +364,11 @@ code argQ argD
// has two (ff, ffrstmux) users // has two (ff, ffrstmux) users
if (nusers(dffD) > 2) if (nusers(dffD) > 2)
argD = SigSpec(); argD = SigSpec();
}
endcode endcode
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// exclusively drives the 'D' input of the $dff, with one of the $mux
// inputs being fully zero
match ffrstmux match ffrstmux
if !argD.empty() if !argD.empty()
select ffrstmux->type.in($mux) select ffrstmux->type.in($mux)
@ -313,6 +400,10 @@ code argD
dffrstmux = nullptr; dffrstmux = nullptr;
endcode endcode
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
match ffcemux match ffcemux
if !argD.empty() if !argD.empty()
select ffcemux->type.in($mux) select ffcemux->type.in($mux)

View File

@ -71,21 +71,21 @@ RTLIL::Module *module;
bool clk_polarity, en_polarity; bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig; RTLIL::SigSpec clk_sig, en_sig;
inline std::string remap_name(RTLIL::IdString abc_name) inline std::string remap_name(RTLIL::IdString abc9_name)
{ {
return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
} }
void handle_loops(RTLIL::Design *design) void handle_loops(RTLIL::Design *design)
{ {
Pass::call(design, "scc -set_attr abc_scc_id {}"); Pass::call(design, "scc -set_attr abc9_scc_id {}");
// For every unique SCC found, (arbitrarily) find the first // For every unique SCC found, (arbitrarily) find the first
// cell in the component, and select (and mark) all its output // cell in the component, and select (and mark) all its output
// wires // wires
pool<RTLIL::Const> ids_seen; pool<RTLIL::Const> ids_seen;
for (auto cell : module->cells()) { for (auto cell : module->cells()) {
auto it = cell->attributes.find(ID(abc_scc_id)); auto it = cell->attributes.find(ID(abc9_scc_id));
if (it != cell->attributes.end()) { if (it != cell->attributes.end()) {
auto r = ids_seen.insert(it->second); auto r = ids_seen.insert(it->second);
if (r.second) { if (r.second) {
@ -105,7 +105,7 @@ void handle_loops(RTLIL::Design *design)
log_assert(w->port_input); log_assert(w->port_input);
log_assert(b.offset < GetSize(w)); log_assert(b.offset < GetSize(w));
} }
w->set_bool_attribute(ID(abc_scc_break)); w->set_bool_attribute(ID(abc9_scc_break));
module->swap_names(b.wire, w); module->swap_names(b.wire, w);
c.second = RTLIL::SigBit(w, b.offset); c.second = RTLIL::SigBit(w, b.offset);
} }
@ -118,7 +118,7 @@ void handle_loops(RTLIL::Design *design)
module->fixup_ports(); module->fixup_ports();
} }
std::string add_echos_to_abc_cmd(std::string str) std::string add_echos_to_abc9_cmd(std::string str)
{ {
std::string new_str, token; std::string new_str, token;
for (size_t i = 0; i < str.size(); i++) { for (size_t i = 0; i < str.size(); i++) {
@ -140,7 +140,7 @@ std::string add_echos_to_abc_cmd(std::string str)
return new_str; return new_str;
} }
std::string fold_abc_cmd(std::string str) std::string fold_abc9_cmd(std::string str)
{ {
std::string token, new_str = " "; std::string token, new_str = " ";
int char_counter = 10; int char_counter = 10;
@ -184,7 +184,7 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho
return text; return text;
} }
struct abc_output_filter struct abc9_output_filter
{ {
bool got_cr; bool got_cr;
int escape_seq_state; int escape_seq_state;
@ -192,7 +192,7 @@ struct abc_output_filter
std::string tempdir_name; std::string tempdir_name;
bool show_tempdir; bool show_tempdir;
abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir)
{ {
got_cr = false; got_cr = false;
escape_seq_state = 0; escape_seq_state = 0;
@ -247,7 +247,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
bool show_tempdir, std::string box_file, std::string lut_file, bool show_tempdir, std::string box_file, std::string lut_file,
std::string wire_delay, const dict<int,IdString> &box_lookup std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs
) )
{ {
module = current_module; module = current_module;
@ -293,68 +293,72 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
std::string abc_script; std::string abc9_script;
if (!lut_costs.empty()) { if (!lut_costs.empty()) {
abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
if (!box_file.empty()) if (!box_file.empty())
abc_script += stringf("read_box -v %s; ", box_file.c_str()); abc9_script += stringf("read_box -v %s; ", box_file.c_str());
} }
else else
if (!lut_file.empty()) { if (!lut_file.empty()) {
abc_script += stringf("read_lut %s; ", lut_file.c_str()); abc9_script += stringf("read_lut %s; ", lut_file.c_str());
if (!box_file.empty()) if (!box_file.empty())
abc_script += stringf("read_box -v %s; ", box_file.c_str()); abc9_script += stringf("read_box -v %s; ", box_file.c_str());
} }
else else
log_abort(); log_abort();
abc_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
if (!script_file.empty()) { if (!script_file.empty()) {
if (script_file[0] == '+') { if (script_file[0] == '+') {
for (size_t i = 1; i < script_file.size(); i++) for (size_t i = 1; i < script_file.size(); i++)
if (script_file[i] == '\'') if (script_file[i] == '\'')
abc_script += "'\\''"; abc9_script += "'\\''";
else if (script_file[i] == ',') else if (script_file[i] == ',')
abc_script += " "; abc9_script += " ";
else else
abc_script += script_file[i]; abc9_script += script_file[i];
} else } else
abc_script += stringf("source %s", script_file.c_str()); abc9_script += stringf("source %s", script_file.c_str());
} else if (!lut_costs.empty() || !lut_file.empty()) { } else if (!lut_costs.empty() || !lut_file.empty()) {
//bool all_luts_cost_same = true; //bool all_luts_cost_same = true;
//for (int this_cost : lut_costs) //for (int this_cost : lut_costs)
// if (this_cost != lut_costs.front()) // if (this_cost != lut_costs.front())
// all_luts_cost_same = false; // all_luts_cost_same = false;
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
//if (all_luts_cost_same && !fast_mode) //if (all_luts_cost_same && !fast_mode)
// abc_script += "; lutpack {S}"; // abc9_script += "; lutpack {S}";
} else } else
log_abort(); log_abort();
//if (script_file.empty() && !delay_target.empty()) //if (script_file.empty() && !delay_target.empty())
// for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) // for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1))
// abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); // abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8);
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3);
//for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) //for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos))
// abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3); // abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3);
for (size_t pos = abc_script.find("{W}"); pos != std::string::npos; pos = abc_script.find("{W}", pos)) for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos))
abc_script = abc_script.substr(0, pos) + wire_delay + abc_script.substr(pos+3); abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3);
abc_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); if (nomfs)
abc_script = add_echos_to_abc_cmd(abc_script); for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos))
abc9_script = abc9_script.erase(pos, strlen("&mfs"));
for (size_t i = 0; i+1 < abc_script.size(); i++) abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str());
if (abc_script[i] == ';' && abc_script[i+1] == ' ') abc9_script = add_echos_to_abc9_cmd(abc9_script);
abc_script[i+1] = '\n';
for (size_t i = 0; i+1 < abc9_script.size(); i++)
if (abc9_script[i] == ';' && abc9_script[i+1] == ' ')
abc9_script[i+1] = '\n';
FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt");
fprintf(f, "%s\n", abc_script.c_str()); fprintf(f, "%s\n", abc9_script.c_str());
fclose(f); fclose(f);
if (dff_mode || !clk_str.empty()) if (dff_mode || !clk_str.empty())
@ -420,7 +424,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
// the expose operation -- remove them from PO/PI // the expose operation -- remove them from PO/PI
// and re-connecting them back together // and re-connecting them back together
for (auto wire : module->wires()) { for (auto wire : module->wires()) {
auto it = wire->attributes.find(ID(abc_scc_break)); auto it = wire->attributes.find(ID(abc9_scc_break));
if (it != wire->attributes.end()) { if (it != wire->attributes.end()) {
wire->attributes.erase(it); wire->attributes.erase(it);
log_assert(wire->port_output); log_assert(wire->port_output);
@ -450,22 +454,22 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
#ifndef YOSYS_LINK_ABC #ifndef YOSYS_LINK_ABC
abc_output_filter filt(tempdir_name, show_tempdir); abc9_output_filter filt(tempdir_name, show_tempdir);
int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1));
#else #else
// These needs to be mutable, supposedly due to getopt // These needs to be mutable, supposedly due to getopt
char *abc_argv[5]; char *abc9_argv[5];
string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
abc_argv[0] = strdup(exe_file.c_str()); abc9_argv[0] = strdup(exe_file.c_str());
abc_argv[1] = strdup("-s"); abc9_argv[1] = strdup("-s");
abc_argv[2] = strdup("-f"); abc9_argv[2] = strdup("-f");
abc_argv[3] = strdup(tmp_script_name.c_str()); abc9_argv[3] = strdup(tmp_script_name.c_str());
abc_argv[4] = 0; abc9_argv[4] = 0;
int ret = Abc_RealMain(4, abc_argv); int ret = Abc_RealMain(4, abc9_argv);
free(abc_argv[0]); free(abc9_argv[0]);
free(abc_argv[1]); free(abc9_argv[1]);
free(abc_argv[2]); free(abc9_argv[2]);
free(abc_argv[3]); free(abc9_argv[3]);
#endif #endif
if (ret != 0) if (ret != 0)
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
@ -513,7 +517,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
signal = std::move(bits); signal = std::move(bits);
} }
dict<IdString, bool> abc_box; dict<IdString, bool> abc9_box;
vector<RTLIL::Cell*> boxes; vector<RTLIL::Cell*> boxes;
for (const auto &it : module->cells_) { for (const auto &it : module->cells_) {
auto cell = it.second; auto cell = it.second;
@ -521,10 +525,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
module->remove(cell); module->remove(cell);
continue; continue;
} }
auto jt = abc_box.find(cell->type); auto jt = abc9_box.find(cell->type);
if (jt == abc_box.end()) { if (jt == abc9_box.end()) {
RTLIL::Module* box_module = design->module(cell->type); RTLIL::Module* box_module = design->module(cell->type);
jt = abc_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc_box_id)))).first; jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first;
} }
if (jt->second) if (jt->second)
boxes.emplace_back(cell); boxes.emplace_back(cell);
@ -648,7 +652,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (!conn.second.is_wire()) if (!conn.second.is_wire())
continue; continue;
Wire *wire = conn.second.as_wire(); Wire *wire = conn.second.as_wire();
if (!wire->get_bool_attribute(ID(abc_padding))) if (!wire->get_bool_attribute(ID(abc9_padding)))
continue; continue;
cell->unsetPort(conn.first); cell->unsetPort(conn.first);
log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second)); log_debug("Dropping padded port connection for %s (%s) .%s (%s )\n", log_id(cell), cell->type.c_str(), log_id(conn.first), log_signal(conn.second));
@ -827,17 +831,17 @@ struct Abc9Pass : public Pass {
log(" if no -script parameter is given, the following scripts are used:\n"); log(" if no -script parameter is given, the following scripts are used:\n");
log("\n"); log("\n");
log(" for -lut/-luts (only one LUT size):\n"); log(" for -lut/-luts (only one LUT size):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str());
log("\n"); log("\n");
log(" for -lut/-luts (different LUT sizes):\n"); log(" for -lut/-luts (different LUT sizes):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str()); log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str());
log("\n"); log("\n");
log(" -fast\n"); log(" -fast\n");
log(" use different default scripts that are slightly faster (at the cost\n"); log(" use different default scripts that are slightly faster (at the cost\n");
log(" of output quality):\n"); log(" of output quality):\n");
log("\n"); log("\n");
log(" for -lut/-luts:\n"); log(" for -lut/-luts:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str()); log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str());
log("\n"); log("\n");
log(" -D <picoseconds>\n"); log(" -D <picoseconds>\n");
log(" set delay target. the string {D} in the default scripts above is\n"); log(" set delay target. the string {D} in the default scripts above is\n");
@ -921,6 +925,7 @@ struct Abc9Pass : public Pass {
std::string delay_target, lutin_shared = "-S 1", wire_delay; std::string delay_target, lutin_shared = "-S 1", wire_delay;
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false; bool show_tempdir = false;
bool nomfs = false;
vector<int> lut_costs; vector<int> lut_costs;
markgroups = false; markgroups = false;
@ -1043,6 +1048,10 @@ struct Abc9Pass : public Pass {
wire_delay = "-W " + args[++argidx]; wire_delay = "-W " + args[++argidx];
continue; continue;
} }
if (arg == "-nomfs") {
nomfs = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -1057,7 +1066,7 @@ struct Abc9Pass : public Pass {
dict<int,IdString> box_lookup; dict<int,IdString> box_lookup;
for (auto m : design->modules()) { for (auto m : design->modules()) {
auto it = m->attributes.find(ID(abc_box_id)); auto it = m->attributes.find(ID(abc9_box_id));
if (it == m->attributes.end()) if (it == m->attributes.end())
continue; continue;
if (m->name.begins_with("$paramod")) if (m->name.begins_with("$paramod"))
@ -1065,7 +1074,7 @@ struct Abc9Pass : public Pass {
auto id = it->second.as_int(); auto id = it->second.as_int();
auto r = box_lookup.insert(std::make_pair(id, m->name)); auto r = box_lookup.insert(std::make_pair(id, m->name));
if (!r.second) if (!r.second)
log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n", log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
log_id(m), id, log_id(r.first->second)); log_id(m), id, log_id(r.first->second));
log_assert(r.second); log_assert(r.second);
@ -1073,24 +1082,24 @@ struct Abc9Pass : public Pass {
for (auto p : m->ports) { for (auto p : m->ports) {
auto w = m->wire(p); auto w = m->wire(p);
log_assert(w); log_assert(w);
if (w->attributes.count(ID(abc_carry))) { if (w->attributes.count(ID(abc9_carry))) {
if (w->port_input) { if (w->port_input) {
if (carry_in) if (carry_in)
log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m));
carry_in = w; carry_in = w;
} }
else if (w->port_output) { else if (w->port_output) {
if (carry_out) if (carry_out)
log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m));
carry_out = w; carry_out = w;
} }
} }
} }
if (carry_in || carry_out) { if (carry_in || carry_out) {
if (carry_in && !carry_out) if (carry_in && !carry_out)
log_error("Module '%s' contains an 'abc_carry' input port but no output port.\n", log_id(m)); log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m));
if (!carry_in && carry_out) if (!carry_in && carry_out)
log_error("Module '%s' contains an 'abc_carry' output port but no input port.\n", log_id(m)); log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m));
// Make carry_in the last PI, and carry_out the last PO // Make carry_in the last PI, and carry_out the last PO
// since ABC requires it this way // since ABC requires it this way
auto &ports = m->ports; auto &ports = m->ports;
@ -1118,7 +1127,7 @@ struct Abc9Pass : public Pass {
for (auto mod : design->selected_modules()) for (auto mod : design->selected_modules())
{ {
if (mod->attributes.count(ID(abc_box_id))) if (mod->attributes.count(ID(abc9_box_id)))
continue; continue;
if (mod->processes.size() > 0) { if (mod->processes.size() > 0) {
@ -1131,7 +1140,7 @@ struct Abc9Pass : public Pass {
if (!dff_mode || !clk_str.empty()) { if (!dff_mode || !clk_str.empty()) {
abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
delay_target, lutin_shared, fast_mode, show_tempdir, delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, wire_delay, box_lookup); box_file, lut_file, wire_delay, box_lookup, nomfs);
continue; continue;
} }
@ -1277,7 +1286,7 @@ struct Abc9Pass : public Pass {
en_sig = assign_map(std::get<3>(it.first)); en_sig = assign_map(std::get<3>(it.first));
abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, lutin_shared, fast_mode, show_tempdir, keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, wire_delay, box_lookup); box_file, lut_file, wire_delay, box_lookup, nomfs);
assign_map.set(mod); assign_map.set(mod);
} }
} }

View File

@ -15,12 +15,12 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_unmap.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_unmap.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_model.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_model.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_5g.box))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_5g.lut))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g_nowide.lut)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_5g_nowide.lut))
EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk .SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk

View File

@ -18,7 +18,7 @@ CCU2C 1 1 9 3
# Box 2 : TRELLIS_DPR16X4_COMB (16x4 dist ram) # Box 2 : TRELLIS_DPR16X4_COMB (16x4 dist ram)
# Outputs: DO0, DO1, DO2, DO3 # Outputs: DO0, DO1, DO2, DO3
# name ID w/b ins outs # name ID w/b ins outs
$__ABC_DPR16X4_COMB 2 0 8 4 $__ABC9_DPR16X4_COMB 2 0 8 4
#A0 A1 A2 A3 RAD0 RAD1 RAD2 RAD3 #A0 A1 A2 A3 RAD0 RAD1 RAD2 RAD3
0 0 0 0 141 379 275 379 0 0 0 0 141 379 275 379

View File

@ -20,5 +20,5 @@ module TRELLIS_DPR16X4 (
.RAD(RAD), .DO(\$DO ) .RAD(RAD), .DO(\$DO )
); );
\$__ABC_DPR16X4_COMB do (.A(\$DO ), .S(RAD), .Y(DO)); \$__ABC9_DPR16X4_COMB do (.A(\$DO ), .S(RAD), .Y(DO));
endmodule endmodule

View File

@ -0,0 +1,5 @@
// ---------------------------------------
(* abc9_box_id=2 *)
module \$__ABC9_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y);
endmodule

View File

@ -1,5 +1,5 @@
// --------------------------------------- // ---------------------------------------
module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y); module \$__ABC9_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y);
assign Y = A; assign Y = A;
endmodule endmodule

View File

@ -1,5 +0,0 @@
// ---------------------------------------
(* abc_box_id=2 *)
module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y);
endmodule

View File

@ -333,6 +333,13 @@ module ECLKSYNCB(
); );
endmodule endmodule
(* blackbox *)
module ECLKBRIDGECS(
input CLK0, CLK1, SEL,
output ECSOUT
);
endmodule
(* blackbox *) (* blackbox *)
module DCCA( module DCCA(
input CLKI, CE, input CLKI, CE,

View File

@ -23,15 +23,15 @@ module FD1S3JX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLI
// module FL1S3AY(); endmodule // module FL1S3AY(); endmodule
// Diamond I/O registers // Diamond I/O registers
module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
// TODO: Diamond I/O latches // TODO: Diamond I/O latches
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule // module IFS1S1B(input PD, D, SCLK, output Q); endmodule

View File

@ -9,19 +9,19 @@ module LUT4(input A, B, C, D, output Z);
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=4, lib_whitebox *) (* abc9_box_id=4, lib_whitebox *)
module L6MUX21 (input D0, D1, SD, output Z); module L6MUX21 (input D0, D1, SD, output Z);
assign Z = SD ? D1 : D0; assign Z = SD ? D1 : D0;
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=1, lib_whitebox *) (* abc9_box_id=1, lib_whitebox *)
module CCU2C( module CCU2C(
(* abc_carry *) (* abc9_carry *)
input CIN, input CIN,
input A0, B0, C0, D0, A1, B1, C1, D1, input A0, B0, C0, D0, A1, B1, C1, D1,
output S0, S1, output S0, S1,
(* abc_carry *) (* abc9_carry *)
output COUT output COUT
); );
parameter [15:0] INIT0 = 16'h0000; parameter [15:0] INIT0 = 16'h0000;
@ -103,7 +103,7 @@ module TRELLIS_RAM16X2 (
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=3, lib_whitebox *) (* abc9_box_id=3, lib_whitebox *)
module PFUMX (input ALUT, BLUT, C0, output Z); module PFUMX (input ALUT, BLUT, C0, output Z);
assign Z = C0 ? ALUT : BLUT; assign Z = C0 ? ALUT : BLUT;
endmodule endmodule
@ -115,7 +115,7 @@ module TRELLIS_DPR16X4 (
input WRE, input WRE,
input WCK, input WCK,
input [3:0] RAD, input [3:0] RAD,
/* (* abc_arrival=<TODO> *) */ /* (* abc9_arrival=<TODO> *) */
output [3:0] DO output [3:0] DO
); );
parameter WCKMUX = "WCK"; parameter WCKMUX = "WCK";

View File

@ -297,6 +297,7 @@ struct SynthEcp5Pass : public ScriptPass
run("simplemap"); run("simplemap");
run("ecp5_ffinit"); run("ecp5_ffinit");
run("ecp5_gsr"); run("ecp5_gsr");
run("attrmvcp -copy -attr syn_useioff");
run("opt_clean"); run("opt_clean");
} }
@ -307,15 +308,16 @@ struct SynthEcp5Pass : public ScriptPass
} }
std::string techmap_args = "-map +/ecp5/latches_map.v"; std::string techmap_args = "-map +/ecp5/latches_map.v";
if (abc9) if (abc9)
techmap_args += " -map +/ecp5/abc_map.v -max_iter 1"; techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
run("techmap " + techmap_args); run("techmap " + techmap_args);
if (abc9) { if (abc9) {
run("read_verilog -icells -lib +/ecp5/abc9_model.v");
if (nowidelut) if (nowidelut)
run("abc9 -lut +/ecp5/abc_5g_nowide.lut -box +/ecp5/abc_5g.box -W 200"); run("abc9 -lut +/ecp5/abc9_5g_nowide.lut -box +/ecp5/abc9_5g.box -W 200");
else else
run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200"); run("abc9 -lut +/ecp5/abc9_5g.lut -box +/ecp5/abc9_5g.box -W 200");
run("techmap -map +/ecp5/abc_unmap.v"); run("techmap -map +/ecp5/abc9_unmap.v");
} else { } else {
if (nowidelut) if (nowidelut)
run("abc -lut 4 -dress"); run("abc -lut 4 -dress");

View File

@ -28,12 +28,13 @@ $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/dsp_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/dsp_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.box)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_model.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.lut)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_hx.box))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.box)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_hx.lut))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.lut)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_lp.box))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.box)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_lp.lut))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.lut)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_u.box))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_u.lut))
$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh)) $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh))
$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh)) $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh))

View File

@ -0,0 +1,27 @@
(* abc9_box_id = 1, lib_whitebox *)
module \$__ICE40_CARRY_WRAPPER (
(* abc9_carry *)
output CO,
output O,
input A, B,
(* abc9_carry *)
input CI,
input I0, I3
);
parameter LUT = 0;
SB_CARRY carry (
.I0(A),
.I1(B),
.CI(CI),
.CO(CO)
);
SB_LUT4 #(
.LUT_INIT(LUT)
) adder (
.I0(I0),
.I1(A),
.I2(B),
.I3(I3),
.O(O)
);
endmodule

View File

@ -2,9 +2,9 @@
`define SB_DFF_REG reg Q = 0 `define SB_DFF_REG reg Q = 0
// `define SB_DFF_REG reg Q // `define SB_DFF_REG reg Q
`define ABC_ARRIVAL_HX(TIME) `ifdef ICE40_HX (* abc_arrival=TIME *) `endif `define ABC9_ARRIVAL_HX(TIME) `ifdef ICE40_HX (* abc9_arrival=TIME *) `endif
`define ABC_ARRIVAL_LP(TIME) `ifdef ICE40_LP (* abc_arrival=TIME *) `endif `define ABC9_ARRIVAL_LP(TIME) `ifdef ICE40_LP (* abc9_arrival=TIME *) `endif
`define ABC_ARRIVAL_U(TIME) `ifdef ICE40_U (* abc_arrival=TIME *) `endif `define ABC9_ARRIVAL_U(TIME) `ifdef ICE40_U (* abc9_arrival=TIME *) `endif
// SiliconBlue IO Cells // SiliconBlue IO Cells
@ -145,34 +145,6 @@ module SB_CARRY (output CO, input I0, I1, CI);
assign CO = (I0 && I1) || ((I0 || I1) && CI); assign CO = (I0 && I1) || ((I0 || I1) && CI);
endmodule endmodule
(* abc_box_id = 1, lib_whitebox *)
module \$__ICE40_CARRY_WRAPPER (
(* abc_carry *)
output CO,
output O,
input A, B,
(* abc_carry *)
input CI,
input I0, I3
);
parameter LUT = 0;
SB_CARRY carry (
.I0(A),
.I1(B),
.CI(CI),
.CO(CO)
);
SB_LUT4 #(
.LUT_INIT(LUT)
) adder (
.I0(I0),
.I1(A),
.I2(B),
.I3(I3),
.O(O)
);
endmodule
// Max delay from: https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 // Max delay from: https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
@ -180,9 +152,9 @@ endmodule
// Positive Edge SiliconBlue FF Cells // Positive Edge SiliconBlue FF Cells
module SB_DFF ( module SB_DFF (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, D input C, D
); );
@ -191,9 +163,9 @@ module SB_DFF (
endmodule endmodule
module SB_DFFE ( module SB_DFFE (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, D input C, E, D
); );
@ -203,9 +175,9 @@ module SB_DFFE (
endmodule endmodule
module SB_DFFSR ( module SB_DFFSR (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
); );
@ -217,9 +189,9 @@ module SB_DFFSR (
endmodule endmodule
module SB_DFFR ( module SB_DFFR (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
); );
@ -231,9 +203,9 @@ module SB_DFFR (
endmodule endmodule
module SB_DFFSS ( module SB_DFFSS (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
); );
@ -245,9 +217,9 @@ module SB_DFFSS (
endmodule endmodule
module SB_DFFS ( module SB_DFFS (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
); );
@ -259,9 +231,9 @@ module SB_DFFS (
endmodule endmodule
module SB_DFFESR ( module SB_DFFESR (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
); );
@ -275,9 +247,9 @@ module SB_DFFESR (
endmodule endmodule
module SB_DFFER ( module SB_DFFER (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
); );
@ -289,9 +261,9 @@ module SB_DFFER (
endmodule endmodule
module SB_DFFESS ( module SB_DFFESS (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
); );
@ -305,9 +277,9 @@ module SB_DFFESS (
endmodule endmodule
module SB_DFFES ( module SB_DFFES (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
); );
@ -321,9 +293,9 @@ endmodule
// Negative Edge SiliconBlue FF Cells // Negative Edge SiliconBlue FF Cells
module SB_DFFN ( module SB_DFFN (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, D input C, D
); );
@ -332,9 +304,9 @@ module SB_DFFN (
endmodule endmodule
module SB_DFFNE ( module SB_DFFNE (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, D input C, E, D
); );
@ -344,9 +316,9 @@ module SB_DFFNE (
endmodule endmodule
module SB_DFFNSR ( module SB_DFFNSR (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
); );
@ -358,9 +330,9 @@ module SB_DFFNSR (
endmodule endmodule
module SB_DFFNR ( module SB_DFFNR (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, R, D input C, R, D
); );
@ -372,9 +344,9 @@ module SB_DFFNR (
endmodule endmodule
module SB_DFFNSS ( module SB_DFFNSS (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
); );
@ -386,9 +358,9 @@ module SB_DFFNSS (
endmodule endmodule
module SB_DFFNS ( module SB_DFFNS (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, S, D input C, S, D
); );
@ -400,9 +372,9 @@ module SB_DFFNS (
endmodule endmodule
module SB_DFFNESR ( module SB_DFFNESR (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
); );
@ -416,9 +388,9 @@ module SB_DFFNESR (
endmodule endmodule
module SB_DFFNER ( module SB_DFFNER (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, R, D input C, E, R, D
); );
@ -430,9 +402,9 @@ module SB_DFFNER (
endmodule endmodule
module SB_DFFNESS ( module SB_DFFNESS (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
); );
@ -446,9 +418,9 @@ module SB_DFFNESS (
endmodule endmodule
module SB_DFFNES ( module SB_DFFNES (
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output `SB_DFF_REG, output `SB_DFF_REG,
input C, E, S, D input C, E, S, D
); );
@ -462,9 +434,9 @@ endmodule
// SiliconBlue RAM Cells // SiliconBlue RAM Cells
module SB_RAM40_4K ( module SB_RAM40_4K (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 `ABC9_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 `ABC9_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 `ABC9_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -633,9 +605,9 @@ module SB_RAM40_4K (
endmodule endmodule
module SB_RAM40_4KNR ( module SB_RAM40_4KNR (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 `ABC9_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 `ABC9_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 `ABC9_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -701,9 +673,9 @@ module SB_RAM40_4KNR (
endmodule endmodule
module SB_RAM40_4KNW ( module SB_RAM40_4KNW (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 `ABC9_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 `ABC9_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 `ABC9_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -769,9 +741,9 @@ module SB_RAM40_4KNW (
endmodule endmodule
module SB_RAM40_4KNRNW ( module SB_RAM40_4KNRNW (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 `ABC9_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 `ABC9_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 `ABC9_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -841,9 +813,9 @@ endmodule
module ICESTORM_LC ( module ICESTORM_LC (
input I0, I1, I2, I3, CIN, CLK, CEN, SR, input I0, I1, I2, I3, CIN, CLK, CEN, SR,
output LO, output LO,
`ABC_ARRIVAL_HX(540) `ABC9_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796) `ABC9_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391) `ABC9_ARRIVAL_U(1391)
output O, output O,
output COUT output COUT
); );
@ -1445,7 +1417,6 @@ module SB_MAC16 (
input ADDSUBTOP, ADDSUBBOT, input ADDSUBTOP, ADDSUBBOT,
input OHOLDTOP, OHOLDBOT, input OHOLDTOP, OHOLDBOT,
input CI, ACCUMCI, SIGNEXTIN, input CI, ACCUMCI, SIGNEXTIN,
//`ABC_ARRIVAL_U(1984) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [31:0] O, output [31:0] O,
output CO, ACCUMCO, SIGNEXTOUT output CO, ACCUMCO, SIGNEXTOUT
); );

View File

@ -245,7 +245,7 @@ struct SynthIce40Pass : public ScriptPass
define = "-D ICE40_U"; define = "-D ICE40_U";
else else
define = "-D ICE40_HX"; define = "-D ICE40_HX";
run("read_verilog -icells " + define + " -lib +/ice40/cells_sim.v"); run("read_verilog " + define + " -lib +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
run("proc"); run("proc");
} }
@ -349,6 +349,7 @@ struct SynthIce40Pass : public ScriptPass
} }
if (!noabc) { if (!noabc) {
if (abc == "abc9") { if (abc == "abc9") {
run("read_verilog -icells -lib +/ice40/abc9_model.v");
int wire_delay; int wire_delay;
if (device_opt == "lp") if (device_opt == "lp")
wire_delay = 400; wire_delay = 400;
@ -356,7 +357,7 @@ struct SynthIce40Pass : public ScriptPass
wire_delay = 750; wire_delay = 750;
else else
wire_delay = 250; wire_delay = 250;
run(abc + stringf(" -W %d -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)"); run(abc + stringf(" -W %d -lut +/ice40/abc9_%s.lut -box +/ice40/abc9_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
} }
else else
run(abc + " -dress -lut 4", "(skip if -noabc)"); run(abc + " -dress -lut 4", "(skip if -noabc)");

View File

@ -44,12 +44,12 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/dsp_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/dsp_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_unmap.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_unmap.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_model.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_model.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_xc7.box))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_xc7.lut))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7_nowide.lut)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_xc7_nowide.lut))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))

View File

@ -39,8 +39,8 @@ module RAM32X1D (
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
); );
\$__ABC_LUT6 dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO)); \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO));
\$__ABC_LUT6 spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO)); \$__ABC9_LUT6 spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO));
endmodule endmodule
module RAM64X1D ( module RAM64X1D (
@ -62,8 +62,8 @@ module RAM64X1D (
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
); );
\$__ABC_LUT6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO)); \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO));
\$__ABC_LUT6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO)); \$__ABC9_LUT6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO));
endmodule endmodule
module RAM128X1D ( module RAM128X1D (
@ -84,8 +84,8 @@ module RAM128X1D (
.A(A), .A(A),
.DPRA(DPRA) .DPRA(DPRA)
); );
\$__ABC_LUT7 dpo (.A(\$DPO ), .S(A), .Y(DPO)); \$__ABC9_LUT7 dpo (.A(\$DPO ), .S(A), .Y(DPO));
\$__ABC_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO)); \$__ABC9_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO));
endmodule endmodule
module SRL16E ( module SRL16E (
@ -101,7 +101,7 @@ module SRL16E (
.Q(\$Q ), .Q(\$Q ),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
); );
\$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A0, A1, A2, A3, 1'b1}), .Y(Q)); \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A0, A1, A2, A3, 1'b1}), .Y(Q));
endmodule endmodule
module SRLC32E ( module SRLC32E (
@ -119,7 +119,7 @@ module SRLC32E (
.Q(\$Q ), .Q31(Q31), .Q(\$Q ), .Q31(Q31),
.A(A), .CE(CE), .CLK(CLK), .D(D) .A(A), .CE(CE), .CLK(CLK), .D(D)
); );
\$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q)); \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q));
endmodule endmodule
module DSP48E1 ( module DSP48E1 (
@ -308,15 +308,15 @@ __CELL__ #(
if (AREG == 0 && MREG == 0 && PREG == 0) if (AREG == 0 && MREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx; assign iA = A, pA = 1'bx;
else else
\$__ABC_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA)); \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && MREG == 0 && PREG == 0) if (BREG == 0 && MREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx; assign iB = B, pB = 1'bx;
else else
\$__ABC_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB)); \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0) if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx; assign iC = C, pC = 1'bx;
else else
\$__ABC_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC)); \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 0) if (DREG == 0)
assign iD = D; assign iD = D;
else if (techmap_guard) else if (techmap_guard)
@ -327,27 +327,27 @@ __CELL__ #(
assign pAD = 1'bx; assign pAD = 1'bx;
if (PREG == 0) begin if (PREG == 0) begin
if (MREG == 1) if (MREG == 1)
\$__ABC_REG rM (.Q(pM)); \$__ABC9_REG rM (.Q(pM));
else else
assign pM = 1'bx; assign pM = 1'bx;
assign pP = 1'bx; assign pP = 1'bx;
end else begin end else begin
assign pM = 1'bx; assign pM = 1'bx;
\$__ABC_REG rP (.Q(pP)); \$__ABC9_REG rP (.Q(pP));
end end
if (MREG == 0 && PREG == 0) if (MREG == 0 && PREG == 0)
assign mP = oP, mPCOUT = oPCOUT; assign mP = oP, mPCOUT = oPCOUT;
else else
assign mP = 1'bx, mPCOUT = 1'bx; assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC_DSP48E1_MULT_P_MUX muxP ( \$__ABC9_DSP48E1_MULT_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
); );
\$__ABC_DSP48E1_MULT_PCOUT_MUX muxPCOUT ( \$__ABC9_DSP48E1_MULT_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
); );
`DSP48E1_INST(\$__ABC_DSP48E1_MULT ) `DSP48E1_INST(\$__ABC9_DSP48E1_MULT )
end end
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
// Disconnect the A-input if MREG is enabled, since // Disconnect the A-input if MREG is enabled, since
@ -355,26 +355,26 @@ __CELL__ #(
if (AREG == 0 && ADREG == 0 && MREG == 0 && PREG == 0) if (AREG == 0 && ADREG == 0 && MREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx; assign iA = A, pA = 1'bx;
else else
\$__ABC_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA)); \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && MREG == 0 && PREG == 0) if (BREG == 0 && MREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx; assign iB = B, pB = 1'bx;
else else
\$__ABC_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB)); \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0) if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx; assign iC = C, pC = 1'bx;
else else
\$__ABC_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC)); \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 0 && ADREG == 0) if (DREG == 0 && ADREG == 0)
assign iD = D, pD = 1'bx; assign iD = D, pD = 1'bx;
else else
\$__ABC_REG #(.WIDTH(25)) rD (.I(D), .O(iD), .Q(pD)); \$__ABC9_REG #(.WIDTH(25)) rD (.I(D), .O(iD), .Q(pD));
if (PREG == 0) begin if (PREG == 0) begin
if (MREG == 1) begin if (MREG == 1) begin
assign pAD = 1'bx; assign pAD = 1'bx;
\$__ABC_REG rM (.Q(pM)); \$__ABC9_REG rM (.Q(pM));
end else begin end else begin
if (ADREG == 1) if (ADREG == 1)
\$__ABC_REG rAD (.Q(pAD)); \$__ABC9_REG rAD (.Q(pAD));
else else
assign pAD = 1'bx; assign pAD = 1'bx;
assign pM = 1'bx; assign pM = 1'bx;
@ -382,21 +382,21 @@ __CELL__ #(
assign pP = 1'bx; assign pP = 1'bx;
end else begin end else begin
assign pAD = 1'bx, pM = 1'bx; assign pAD = 1'bx, pM = 1'bx;
\$__ABC_REG rP (.Q(pP)); \$__ABC9_REG rP (.Q(pP));
end end
if (MREG == 0 && PREG == 0) if (MREG == 0 && PREG == 0)
assign mP = oP, mPCOUT = oPCOUT; assign mP = oP, mPCOUT = oPCOUT;
else else
assign mP = 1'bx, mPCOUT = 1'bx; assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC_DSP48E1_MULT_DPORT_P_MUX muxP ( \$__ABC9_DSP48E1_MULT_DPORT_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
); );
\$__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX muxPCOUT ( \$__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
); );
`DSP48E1_INST(\$__ABC_DSP48E1_MULT_DPORT ) `DSP48E1_INST(\$__ABC9_DSP48E1_MULT_DPORT )
end end
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
// Disconnect the A-input if MREG is enabled, since // Disconnect the A-input if MREG is enabled, since
@ -404,15 +404,15 @@ __CELL__ #(
if (AREG == 0 && PREG == 0) if (AREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx; assign iA = A, pA = 1'bx;
else else
\$__ABC_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA)); \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && PREG == 0) if (BREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx; assign iB = B, pB = 1'bx;
else else
\$__ABC_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB)); \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0) if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx; assign iC = C, pC = 1'bx;
else else
\$__ABC_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC)); \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 1 && techmap_guard) if (DREG == 1 && techmap_guard)
$error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\""); $error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
assign pD = 1'bx; assign pD = 1'bx;
@ -423,7 +423,7 @@ __CELL__ #(
$error("Invalid DSP48E1 configuration: MREG enabled but USE_MULT == \"NONE\""); $error("Invalid DSP48E1 configuration: MREG enabled but USE_MULT == \"NONE\"");
assign pM = 1'bx; assign pM = 1'bx;
if (PREG == 1) if (PREG == 1)
\$__ABC_REG rP (.Q(pP)); \$__ABC9_REG rP (.Q(pP));
else else
assign pP = 1'bx; assign pP = 1'bx;
@ -431,14 +431,14 @@ __CELL__ #(
assign mP = oP, mPCOUT = oPCOUT; assign mP = oP, mPCOUT = oPCOUT;
else else
assign mP = 1'bx, mPCOUT = 1'bx; assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC_DSP48E1_P_MUX muxP ( \$__ABC9_DSP48E1_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
); );
\$__ABC_DSP48E1_PCOUT_MUX muxPCOUT ( \$__ABC9_DSP48E1_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
); );
`DSP48E1_INST(\$__ABC_DSP48E1 ) `DSP48E1_INST(\$__ABC9_DSP48E1 )
end end
else else
$error("Invalid DSP48E1 configuration"); $error("Invalid DSP48E1 configuration");

View File

@ -24,7 +24,7 @@
// Necessary to make these an atomic unit so that // Necessary to make these an atomic unit so that
// ABC cannot optimise just one of the MUXF7 away // ABC cannot optimise just one of the MUXF7 away
// and expect to save on its delay // and expect to save on its delay
(* abc_box_id = 3, lib_whitebox *) (* abc9_box_id = 3, lib_whitebox *)
module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1); module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
assign O = S1 ? (S0 ? I3 : I2) assign O = S1 ? (S0 ? I3 : I2)
: (S0 ? I1 : I0); : (S0 ? I1 : I0);
@ -36,32 +36,32 @@ endmodule
// is only committed on the next clock edge). // is only committed on the next clock edge).
// To model the combinatorial path, such cells have to be split // To model the combinatorial path, such cells have to be split
// into comb and seq parts, with this box modelling only the former. // into comb and seq parts, with this box modelling only the former.
(* abc_box_id=2000 *) (* abc9_box_id=2000 *)
module \$__ABC_LUT6 (input A, input [5:0] S, output Y); module \$__ABC9_LUT6 (input A, input [5:0] S, output Y);
endmodule endmodule
// Box to emulate comb/seq behaviour of RAMD128 // Box to emulate comb/seq behaviour of RAMD128
(* abc_box_id=2001 *) (* abc9_box_id=2001 *)
module \$__ABC_LUT7 (input A, input [6:0] S, output Y); module \$__ABC9_LUT7 (input A, input [6:0] S, output Y);
endmodule endmodule
// Modules used to model the comb/seq behaviour of DSP48E1 // Modules used to model the comb/seq behaviour of DSP48E1
// With abc_map.v responsible for splicing the below modules // With abc9_map.v responsible for splicing the below modules
// between the combinatorial DSP48E1 box (e.g. disconnecting // between the combinatorial DSP48E1 box (e.g. disconnecting
// A when AREG, MREG or PREG is enabled and splicing in the // A when AREG, MREG or PREG is enabled and splicing in the
// "$__ABC_DSP48E1_REG" blackbox as "REG" in the diagram below) // "$__ABC9_DSP48E1_REG" blackbox as "REG" in the diagram below)
// this acts to first disables the combinatorial path (as there // this acts to first disables the combinatorial path (as there
// is no connectivity through REG), and secondly, since this is // is no connectivity through REG), and secondly, since this is
// blackbox a new PI will be introduced with an arrival time of // blackbox a new PI will be introduced with an arrival time of
// zero. // zero.
// Note: Since these "$__ABC_DSP48E1_REG" modules are of a // Note: Since these "$__ABC9_DSP48E1_REG" modules are of a
// sequential nature, they are not passed as a box to ABC and // sequential nature, they are not passed as a box to ABC and
// (desirably) represented as PO/PIs. // (desirably) represented as PO/PIs.
// //
// At the DSP output, we place a blackbox mux ("M" in the diagram // At the DSP output, we place a blackbox mux ("M" in the diagram
// below) to capture the fact that the critical-path could come // below) to capture the fact that the critical-path could come
// from any one of its inputs. // from any one of its inputs.
// In contrast to "REG", the "$__ABC_DSP48E1_*_MUX" modules are // In contrast to "REG", the "$__ABC9_DSP48E1_*_MUX" modules are
// combinatorial blackboxes that do get passed to ABC. // combinatorial blackboxes that do get passed to ABC.
// The propagation delay through this box (specified in the box // The propagation delay through this box (specified in the box
// file) captures the arrival time of the register (i.e. // file) captures the arrival time of the register (i.e.
@ -90,18 +90,18 @@ endmodule
// B >>------| | // B >>------| |
// +---------+ // +---------+
// //
`define ABC_DSP48E1_MUX(__NAME__) """ `define ABC9_DSP48E1_MUX(__NAME__) """
module __NAME__ (input Aq, ADq, Bq, Cq, Dq, input [47:0] I, input Mq, input [47:0] P, input Pq, output [47:0] O); module __NAME__ (input Aq, ADq, Bq, Cq, Dq, input [47:0] I, input Mq, input [47:0] P, input Pq, output [47:0] O);
endmodule endmodule
""" """
(* abc_box_id=2100 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_P_MUX ) (* abc9_box_id=2100 *) `ABC9_DSP48E1_MUX(\$__ABC9_DSP48E1_MULT_P_MUX )
(* abc_box_id=2101 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_PCOUT_MUX ) (* abc9_box_id=2101 *) `ABC9_DSP48E1_MUX(\$__ABC9_DSP48E1_MULT_PCOUT_MUX )
(* abc_box_id=2102 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_DPORT_P_MUX ) (* abc9_box_id=2102 *) `ABC9_DSP48E1_MUX(\$__ABC9_DSP48E1_MULT_DPORT_P_MUX )
(* abc_box_id=2103 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX ) (* abc9_box_id=2103 *) `ABC9_DSP48E1_MUX(\$__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX )
(* abc_box_id=2104 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_P_MUX ) (* abc9_box_id=2104 *) `ABC9_DSP48E1_MUX(\$__ABC9_DSP48E1_P_MUX )
(* abc_box_id=2105 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_PCOUT_MUX ) (* abc9_box_id=2105 *) `ABC9_DSP48E1_MUX(\$__ABC9_DSP48E1_PCOUT_MUX )
`define ABC_DSP48E1(__NAME__) """ `define ABC9_DSP48E1(__NAME__) """
module __NAME__ ( module __NAME__ (
output [29:0] ACOUT, output [29:0] ACOUT,
output [17:0] BCOUT, output [17:0] BCOUT,
@ -185,6 +185,6 @@ module __NAME__ (
parameter [6:0] IS_OPMODE_INVERTED = 7'b0; parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
endmodule endmodule
""" """
(* abc_box_id=3000 *) `ABC_DSP48E1(\$__ABC_DSP48E1_MULT ) (* abc9_box_id=3000 *) `ABC9_DSP48E1(\$__ABC9_DSP48E1_MULT )
(* abc_box_id=3001 *) `ABC_DSP48E1(\$__ABC_DSP48E1_MULT_DPORT ) (* abc9_box_id=3001 *) `ABC9_DSP48E1(\$__ABC9_DSP48E1_MULT_DPORT )
(* abc_box_id=3002 *) `ABC_DSP48E1(\$__ABC_DSP48E1 ) (* abc9_box_id=3002 *) `ABC9_DSP48E1(\$__ABC9_DSP48E1 )

View File

@ -20,19 +20,19 @@
// ============================================================================ // ============================================================================
module \$__ABC_LUT6 (input A, input [5:0] S, output Y); module \$__ABC9_LUT6 (input A, input [5:0] S, output Y);
assign Y = A; assign Y = A;
endmodule endmodule
module \$__ABC_LUT7 (input A, input [6:0] S, output Y); module \$__ABC9_LUT7 (input A, input [6:0] S, output Y);
assign Y = A; assign Y = A;
endmodule endmodule
module \$__ABC_REG (input [WIDTH-1:0] I, output [WIDTH-1:0] O, output Q); module \$__ABC9_REG (input [WIDTH-1:0] I, output [WIDTH-1:0] O, output Q);
parameter WIDTH = 1; parameter WIDTH = 1;
assign O = I; assign O = I;
endmodule endmodule
(* techmap_celltype = "$__ABC_DSP48E1_MULT_P_MUX $__ABC_DSP48E1_MULT_PCOUT_MUX $__ABC_DSP48E1_MULT_DPORT_P_MUX $__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX $__ABC_DSP48E1_P_MUX $__ABC_DSP48E1_PCOUT_MUX" *) (* techmap_celltype = "$__ABC9_DSP48E1_MULT_P_MUX $__ABC9_DSP48E1_MULT_PCOUT_MUX $__ABC9_DSP48E1_MULT_DPORT_P_MUX $__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX $__ABC9_DSP48E1_P_MUX $__ABC9_DSP48E1_PCOUT_MUX" *)
module \$__ABC_DSP48E1_MUX ( module \$__ABC9_DSP48E1_MUX (
input Aq, Bq, Cq, Dq, ADq, input Aq, Bq, Cq, Dq, ADq,
input [47:0] I, input [47:0] I,
input Mq, input Mq,
@ -43,8 +43,8 @@ module \$__ABC_DSP48E1_MUX (
assign O = I; assign O = I;
endmodule endmodule
(* techmap_celltype = "$__ABC_DSP48E1_MULT $__ABC_DSP48E1_MULT_DPORT $__ABC_DSP48E1" *) (* techmap_celltype = "$__ABC9_DSP48E1_MULT $__ABC9_DSP48E1_MULT_DPORT $__ABC9_DSP48E1" *)
module \$__ABC_DSP48E1 ( module \$__ABC9_DSP48E1 (
(* techmap_autopurge *) output [29:0] ACOUT, (* techmap_autopurge *) output [29:0] ACOUT,
(* techmap_autopurge *) output [17:0] BCOUT, (* techmap_autopurge *) output [17:0] BCOUT,
(* techmap_autopurge *) output reg CARRYCASCOUT, (* techmap_autopurge *) output reg CARRYCASCOUT,

View File

@ -50,18 +50,18 @@ CARRY4 4 1 10 8
# into comb and seq parts, with this box modelling only the former. # into comb and seq parts, with this box modelling only the former.
# Inputs: A S0 S1 S2 S3 S4 S5 # Inputs: A S0 S1 S2 S3 S4 S5
# Outputs: Y # Outputs: Y
$__ABC_LUT6 2000 0 7 1 $__ABC9_LUT6 2000 0 7 1
0 642 631 472 407 238 127 0 642 631 472 407 238 127
# SLICEM/A6LUT + F7BMUX # SLICEM/A6LUT + F7BMUX
# Box to emulate comb/seq behaviour of RAMD128 # Box to emulate comb/seq behaviour of RAMD128
# Inputs: A S0 S1 S2 S3 S4 S5 S6 # Inputs: A S0 S1 S2 S3 S4 S5 S6
# Outputs: DPO SPO # Outputs: DPO SPO
$__ABC_LUT7 2001 0 8 1 $__ABC9_LUT7 2001 0 8 1
0 1047 1036 877 812 643 532 478 0 1047 1036 877 812 643 532 478
# Boxes used to represent the comb/seq behaviour of DSP48E1 # Boxes used to represent the comb/seq behaviour of DSP48E1
# With abc_map.v responsible for disconnecting inputs to # With abc9_map.v responsible for disconnecting inputs to
# the combinatorial DSP48E1 model by a register (e.g. # the combinatorial DSP48E1 model by a register (e.g.
# disconnecting A when AREG, MREG or PREG is enabled) # disconnecting A when AREG, MREG or PREG is enabled)
# this mux captures the existence of a replacement path # this mux captures the existence of a replacement path
@ -70,7 +70,7 @@ $__ABC_LUT7 2001 0 8 1
# the mux at zero time, the combinatorial delay through # the mux at zero time, the combinatorial delay through
# these muxes thus represents the clock-to-q delay at # these muxes thus represents the clock-to-q delay at
# P/PCOUT. # P/PCOUT.
$__ABC_DSP48E1_MULT_P_MUX 2100 0 103 48 $__ABC9_DSP48E1_MULT_P_MUX 2100 0 103 48
# A AD B C D I M P Pq # A AD B C D I M P Pq
2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
@ -120,7 +120,7 @@ $__ABC_DSP48E1_MULT_P_MUX 2100 0 103 48
2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 2952 - 2813 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
$__ABC_DSP48E1_MULT_PCOUT_MUX 2101 0 103 48 $__ABC9_DSP48E1_MULT_PCOUT_MUX 2101 0 103 48
# A AD B C D I M P Pq # A AD B C D I M P Pq
3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
@ -170,7 +170,7 @@ $__ABC_DSP48E1_MULT_PCOUT_MUX 2101 0 103 48
3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 3098 - 2960 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
$__ABC_DSP48E1_MULT_DPORT_P_MUX 2102 0 103 48 $__ABC9_DSP48E1_MULT_DPORT_P_MUX 2102 0 103 48
# A AD B C D I M P Pq # A AD B C D I M P Pq
3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
@ -220,7 +220,7 @@ $__ABC_DSP48E1_MULT_DPORT_P_MUX 2102 0 103 48
3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 3935 2958 2813 1687 3908 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
$__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX 2103 0 103 48 $__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX 2103 0 103 48
# A AD B C D I M P Pq # A AD B C D I M P Pq
4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
@ -270,7 +270,7 @@ $__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX 2103 0 103 48
4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 4083 2859 2960 1835 4056 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
$__ABC_DSP48E1_P_MUX 2104 0 103 48 $__ABC9_DSP48E1_P_MUX 2104 0 103 48
# A AD B C D I M P Pq # A AD B C D I M P Pq
1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
@ -320,7 +320,7 @@ $__ABC_DSP48E1_P_MUX 2104 0 103 48
1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329 1632 - 1616 1687 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 329
$__ABC_DSP48E1_PCOUT_MUX 2105 0 103 48 $__ABC9_DSP48E1_PCOUT_MUX 2105 0 103 48
# A AD B C D I M P Pq # A AD B C D I M P Pq
1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
@ -371,7 +371,7 @@ $__ABC_DSP48E1_PCOUT_MUX 2105 0 103 48
1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435 1780 - 1765 1835 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1819 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435
$__ABC_DSP48E1_MULT 3000 0 263 154 $__ABC9_DSP48E1_MULT 3000 0 263 154
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 - - 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 - - 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 - - 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 - - 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 - - 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 2823 - - 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 2970 -
@ -635,7 +635,7 @@ $__ABC_DSP48E1_MULT 3000 0 263 154
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$__ABC_DSP48E1_MULT_DPORT 3001 0 263 154 $__ABC9_DSP48E1_MULT_DPORT 3001 0 263 154
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 - - 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 - - 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 - - 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 - - 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 - - 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 3806 - - 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 3954 -
@ -899,7 +899,7 @@ $__ABC_DSP48E1_MULT_DPORT 3001 0 263 154
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$__ABC_DSP48E1 3002 0 263 154 $__ABC9_DSP48E1 3002 0 263 154
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 - - 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 - - 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 - - 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 - - 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 - - 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523 - - 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 1671 -

View File

@ -38,6 +38,17 @@ module IBUF(
assign O = I; assign O = I;
endmodule endmodule
module IBUFG(
output O,
(* iopad_external_pin *)
input I);
parameter CAPACITANCE = "DONT_CARE";
parameter IBUF_DELAY_VALUE = "0";
parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT";
assign O = I;
endmodule
module OBUF( module OBUF(
(* iopad_external_pin *) (* iopad_external_pin *)
output O, output O,
@ -184,12 +195,12 @@ module MUXCY(output O, input CI, DI, S);
assign O = S ? CI : DI; assign O = S ? CI : DI;
endmodule endmodule
(* abc_box_id = 1, lib_whitebox *) (* abc9_box_id = 1, lib_whitebox *)
module MUXF7(output O, input I0, I1, S); module MUXF7(output O, input I0, I1, S);
assign O = S ? I1 : I0; assign O = S ? I1 : I0;
endmodule endmodule
(* abc_box_id = 2, lib_whitebox *) (* abc9_box_id = 2, lib_whitebox *)
module MUXF8(output O, input I0, I1, S); module MUXF8(output O, input I0, I1, S);
assign O = S ? I1 : I0; assign O = S ? I1 : I0;
endmodule endmodule
@ -198,12 +209,12 @@ module XORCY(output O, input CI, LI);
assign O = CI ^ LI; assign O = CI ^ LI;
endmodule endmodule
(* abc_box_id = 4, lib_whitebox *) (* abc9_box_id = 4, lib_whitebox *)
module CARRY4( module CARRY4(
(* abc_carry *) (* abc9_carry *)
output [3:0] CO, output [3:0] CO,
output [3:0] O, output [3:0] O,
(* abc_carry *) (* abc9_carry *)
input CI, input CI,
input CYINIT, input CYINIT,
input [3:0] DI, S input [3:0] DI, S
@ -241,7 +252,7 @@ endmodule
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
module FDRE ( module FDRE (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *) (* invertible_pin = "IS_C_INVERTED" *)
@ -264,7 +275,7 @@ module FDRE (
endmodule endmodule
module FDSE ( module FDSE (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *) (* invertible_pin = "IS_C_INVERTED" *)
@ -287,7 +298,7 @@ module FDSE (
endmodule endmodule
module FDCE ( module FDCE (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *) (* invertible_pin = "IS_C_INVERTED" *)
@ -312,7 +323,7 @@ module FDCE (
endmodule endmodule
module FDPE ( module FDPE (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *) (* invertible_pin = "IS_C_INVERTED" *)
@ -337,7 +348,7 @@ module FDPE (
endmodule endmodule
module FDRE_1 ( module FDRE_1 (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
input C, input C,
@ -349,7 +360,7 @@ module FDRE_1 (
endmodule endmodule
module FDSE_1 ( module FDSE_1 (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
input C, input C,
@ -361,7 +372,7 @@ module FDSE_1 (
endmodule endmodule
module FDCE_1 ( module FDCE_1 (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
input C, input C,
@ -373,7 +384,7 @@ module FDCE_1 (
endmodule endmodule
module FDPE_1 ( module FDPE_1 (
(* abc_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
input C, input C,
@ -430,7 +441,7 @@ endmodule
module RAM32X1D ( module RAM32X1D (
// 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#L957
(* abc_arrival=1153 *) (* abc9_arrival=1153 *)
output DPO, SPO, output DPO, SPO,
input D, input D,
(* clkbuf_sink *) (* clkbuf_sink *)
@ -453,7 +464,7 @@ endmodule
module RAM64X1D ( module RAM64X1D (
// 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#L957
(* abc_arrival=1153 *) (* abc9_arrival=1153 *)
output DPO, SPO, output DPO, SPO,
input D, input D,
(* clkbuf_sink *) (* clkbuf_sink *)
@ -476,7 +487,7 @@ endmodule
module RAM128X1D ( module RAM128X1D (
// 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#L957
(* abc_arrival=1153 *) (* abc9_arrival=1153 *)
output DPO, SPO, output DPO, SPO,
input D, input D,
(* clkbuf_sink *) (* clkbuf_sink *)
@ -496,7 +507,7 @@ endmodule
module SRL16E ( module SRL16E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
(* abc_arrival=1472 *) (* abc9_arrival=1472 *)
output Q, output Q,
input A0, A1, A2, A3, CE, input A0, A1, A2, A3, CE,
(* clkbuf_sink *) (* clkbuf_sink *)
@ -544,9 +555,9 @@ endmodule
module SRLC32E ( module SRLC32E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
(* abc_arrival=1472 *) (* abc9_arrival=1472 *)
output Q, output Q,
(* abc_arrival=1114 *) (* abc9_arrival=1114 *)
output Q31, output Q31,
input [4:0] A, input [4:0] A,
input CE, input CE,

View File

@ -53,7 +53,7 @@ XC6S_CELLS = [
# Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), # Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}),
@ -137,7 +137,7 @@ XC6V_CELLS = [
Cell('SYSMON'), Cell('SYSMON'),
# Arithmetic functions. # Arithmetic functions.
Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}),
# Clock components. # Clock components.
# Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}),
@ -174,7 +174,7 @@ XC6V_CELLS = [
Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_GTHE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_GTHE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), # Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}),
@ -264,7 +264,7 @@ XC7_CELLS = [
Cell('XADC'), Cell('XADC'),
# Arithmetic functions. # Arithmetic functions.
Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}),
# Clock components. # Clock components.
# Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}),
@ -307,7 +307,7 @@ XC7_CELLS = [
Cell('IBUFDS_GTE2', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_GTE2', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), # Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}),

View File

@ -339,10 +339,14 @@ struct SynthXilinxPass : public ScriptPass
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6");
} }
if (check_label("map_dsp"), "(skip if '-nodsp')") { if (check_label("map_dsp", "(skip if '-nodsp')")) {
if (!nodsp || help_mode) { if (!nodsp || help_mode) {
// NB: Xilinx multipliers are signed only // NB: Xilinx multipliers are signed only
run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_A_MAXWIDTH_PARTIAL=18 -D DSP_B_MAXWIDTH=18 " run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 "
"-D DSP_A_MAXWIDTH_PARTIAL=18 -D DSP_B_MAXWIDTH=18 " // Partial multipliers are intentionally
// limited to 18x18 in order to take
// advantage of the (PCOUT << 17) -> PCIN
// dedicated cascade chain capability
"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers "-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller "-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18"); "-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18");
@ -474,13 +478,18 @@ struct SynthXilinxPass : public ScriptPass
run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut'; option for '-retime')"); run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut'; option for '-retime')");
else if (abc9) { else if (abc9) {
if (family != "xc7") if (family != "xc7")
log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n"); log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, "
run("techmap -map +/xilinx/abc_map.v -max_iter 1"); "will use timing for 'xc7' instead.\n", family.c_str());
run("read_verilog -icells -lib +/xilinx/abc_model.v"); run("techmap -map +/xilinx/abc9_map.v -max_iter 1");
run("read_verilog -icells -lib +/xilinx/abc9_model.v");
std::string abc9_opts = " -box +/xilinx/abc9_xc7.box";
abc9_opts += stringf(" -W %d", XC7_WIRE_DELAY);
abc9_opts += " -nomfs";
if (nowidelut) if (nowidelut)
run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY)); abc9_opts += " -lut +/xilinx/abc9_xc7_nowide.lut";
else else
run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY)); abc9_opts += " -lut +/xilinx/abc9_xc7.lut";
run("abc9" + abc9_opts);
} }
else { else {
if (nowidelut) if (nowidelut)
@ -498,7 +507,7 @@ struct SynthXilinxPass : public ScriptPass
if (help_mode) if (help_mode)
techmap_args += " [-map " + ff_map_file + "]"; techmap_args += " [-map " + ff_map_file + "]";
else if (abc9) else if (abc9)
techmap_args += " -map +/xilinx/abc_unmap.v"; techmap_args += " -map +/xilinx/abc9_unmap.v";
else else
techmap_args += " -map " + ff_map_file; techmap_args += " -map " + ff_map_file;
run("techmap " + techmap_args); run("techmap " + techmap_args);

View File

@ -19,9 +19,13 @@ module RAMB8BWER (
input [1:0] WEAWEL, input [1:0] WEAWEL,
input [1:0] WEBWEU, input [1:0] WEBWEU,
/* (* abc9_arrival=<TODO> *) */
output [15:0] DOADO, output [15:0] DOADO,
/* (* abc9_arrival=<TODO> *) */
output [15:0] DOBDO, output [15:0] DOBDO,
/* (* abc9_arrival=<TODO> *) */
output [1:0] DOPADOP, output [1:0] DOPADOP,
/* (* abc9_arrival=<TODO> *) */
output [1:0] DOPBDOP output [1:0] DOPBDOP
); );
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
@ -109,9 +113,13 @@ module RAMB16BWER (
input [3:0] WEA, input [3:0] WEA,
input [3:0] WEB, input [3:0] WEB,
/* (* abc9_arrival=<TODO> *) */
output [31:0] DOA, output [31:0] DOA,
/* (* abc9_arrival=<TODO> *) */
output [31:0] DOB, output [31:0] DOB,
/* (* abc9_arrival=<TODO> *) */
output [3:0] DOPA, output [3:0] DOPA,
/* (* abc9_arrival=<TODO> *) */
output [3:0] DOPB output [3:0] DOPB
); );
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;

View File

@ -1282,16 +1282,6 @@ module IBUFDS_DIFF_OUT (...);
input IB; input IB;
endmodule endmodule
module IBUFG (...);
parameter CAPACITANCE = "DONT_CARE";
parameter IBUF_DELAY_VALUE = "0";
parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT";
output O;
(* iopad_external_pin *)
input I;
endmodule
module IBUFGDS (...); module IBUFGDS (...);
parameter CAPACITANCE = "DONT_CARE"; parameter CAPACITANCE = "DONT_CARE";
parameter DIFF_TERM = "FALSE"; parameter DIFF_TERM = "FALSE";

View File

@ -647,94 +647,6 @@ module SYSMON (...);
input [6:0] DADDR; input [6:0] DADDR;
endmodule endmodule
module DSP48E1 (...);
parameter integer ACASCREG = 1;
parameter integer ADREG = 1;
parameter integer ALUMODEREG = 1;
parameter integer AREG = 1;
parameter AUTORESET_PATDET = "NO_RESET";
parameter A_INPUT = "DIRECT";
parameter integer BCASCREG = 1;
parameter integer BREG = 1;
parameter B_INPUT = "DIRECT";
parameter integer CARRYINREG = 1;
parameter integer CARRYINSELREG = 1;
parameter integer CREG = 1;
parameter integer DREG = 1;
parameter integer INMODEREG = 1;
parameter integer MREG = 1;
parameter integer OPMODEREG = 1;
parameter integer PREG = 1;
parameter SEL_MASK = "MASK";
parameter SEL_PATTERN = "PATTERN";
parameter USE_DPORT = "FALSE";
parameter USE_MULT = "MULTIPLY";
parameter USE_PATTERN_DETECT = "NO_PATDET";
parameter USE_SIMD = "ONE48";
parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
parameter [47:0] PATTERN = 48'h000000000000;
parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
parameter [4:0] IS_INMODE_INVERTED = 5'b0;
parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
output [29:0] ACOUT;
output [17:0] BCOUT;
output CARRYCASCOUT;
output [3:0] CARRYOUT;
output MULTSIGNOUT;
output OVERFLOW;
output [47:0] P;
output PATTERNBDETECT;
output PATTERNDETECT;
output [47:0] PCOUT;
output UNDERFLOW;
input [29:0] A;
input [29:0] ACIN;
(* invertible_pin = "IS_ALUMODE_INVERTED" *)
input [3:0] ALUMODE;
input [17:0] B;
input [17:0] BCIN;
input [47:0] C;
input CARRYCASCIN;
(* invertible_pin = "IS_CARRYIN_INVERTED" *)
input CARRYIN;
input [2:0] CARRYINSEL;
input CEA1;
input CEA2;
input CEAD;
input CEALUMODE;
input CEB1;
input CEB2;
input CEC;
input CECARRYIN;
input CECTRL;
input CED;
input CEINMODE;
input CEM;
input CEP;
(* clkbuf_sink *)
(* invertible_pin = "IS_CLK_INVERTED" *)
input CLK;
input [24:0] D;
(* invertible_pin = "IS_INMODE_INVERTED" *)
input [4:0] INMODE;
input MULTSIGNIN;
(* invertible_pin = "IS_OPMODE_INVERTED" *)
input [6:0] OPMODE;
input [47:0] PCIN;
input RSTA;
input RSTALLCARRYIN;
input RSTALUMODE;
input RSTB;
input RSTC;
input RSTCTRL;
input RSTD;
input RSTINMODE;
input RSTM;
input RSTP;
endmodule
module BUFGCE (...); module BUFGCE (...);
parameter CE_TYPE = "SYNC"; parameter CE_TYPE = "SYNC";
parameter [0:0] IS_CE_INVERTED = 1'b0; parameter [0:0] IS_CE_INVERTED = 1'b0;
@ -1909,16 +1821,6 @@ module IBUFDS_GTHE1 (...);
input IB; input IB;
endmodule endmodule
module IBUFG (...);
parameter CAPACITANCE = "DONT_CARE";
parameter IBUF_DELAY_VALUE = "0";
parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT";
output O;
(* iopad_external_pin *)
input I;
endmodule
module IBUFGDS (...); module IBUFGDS (...);
parameter CAPACITANCE = "DONT_CARE"; parameter CAPACITANCE = "DONT_CARE";
parameter DIFF_TERM = "FALSE"; parameter DIFF_TERM = "FALSE";

View File

@ -31,13 +31,13 @@ module RAMB18E1 (
input [1:0] WEA, input [1:0] WEA,
input [3:0] WEBWE, input [3:0] WEBWE,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [15:0] DOADO, output [15:0] DOADO,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [15:0] DOBDO, output [15:0] DOBDO,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [1:0] DOPADOP, output [1:0] DOPADOP,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [1:0] DOPBDOP output [1:0] DOPBDOP
); );
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
@ -169,13 +169,13 @@ module RAMB36E1 (
input [3:0] WEA, input [3:0] WEA,
input [7:0] WEBWE, input [7:0] WEBWE,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [31:0] DOADO, output [31:0] DOADO,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [31:0] DOBDO, output [31:0] DOBDO,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [3:0] DOPADOP, output [3:0] DOPADOP,
(* abc_arrival=2454 *) (* abc9_arrival=2454 *)
output [3:0] DOPBDOP output [3:0] DOPBDOP
); );
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;

View File

@ -3376,94 +3376,6 @@ module XADC (...);
input [6:0] DADDR; input [6:0] DADDR;
endmodule endmodule
module DSP48E1 (...);
parameter integer ACASCREG = 1;
parameter integer ADREG = 1;
parameter integer ALUMODEREG = 1;
parameter integer AREG = 1;
parameter AUTORESET_PATDET = "NO_RESET";
parameter A_INPUT = "DIRECT";
parameter integer BCASCREG = 1;
parameter integer BREG = 1;
parameter B_INPUT = "DIRECT";
parameter integer CARRYINREG = 1;
parameter integer CARRYINSELREG = 1;
parameter integer CREG = 1;
parameter integer DREG = 1;
parameter integer INMODEREG = 1;
parameter integer MREG = 1;
parameter integer OPMODEREG = 1;
parameter integer PREG = 1;
parameter SEL_MASK = "MASK";
parameter SEL_PATTERN = "PATTERN";
parameter USE_DPORT = "FALSE";
parameter USE_MULT = "MULTIPLY";
parameter USE_PATTERN_DETECT = "NO_PATDET";
parameter USE_SIMD = "ONE48";
parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
parameter [47:0] PATTERN = 48'h000000000000;
parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
parameter [4:0] IS_INMODE_INVERTED = 5'b0;
parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
output [29:0] ACOUT;
output [17:0] BCOUT;
output CARRYCASCOUT;
output [3:0] CARRYOUT;
output MULTSIGNOUT;
output OVERFLOW;
output [47:0] P;
output PATTERNBDETECT;
output PATTERNDETECT;
output [47:0] PCOUT;
output UNDERFLOW;
input [29:0] A;
input [29:0] ACIN;
(* invertible_pin = "IS_ALUMODE_INVERTED" *)
input [3:0] ALUMODE;
input [17:0] B;
input [17:0] BCIN;
input [47:0] C;
input CARRYCASCIN;
(* invertible_pin = "IS_CARRYIN_INVERTED" *)
input CARRYIN;
input [2:0] CARRYINSEL;
input CEA1;
input CEA2;
input CEAD;
input CEALUMODE;
input CEB1;
input CEB2;
input CEC;
input CECARRYIN;
input CECTRL;
input CED;
input CEINMODE;
input CEM;
input CEP;
(* clkbuf_sink *)
(* invertible_pin = "IS_CLK_INVERTED" *)
input CLK;
input [24:0] D;
(* invertible_pin = "IS_INMODE_INVERTED" *)
input [4:0] INMODE;
input MULTSIGNIN;
(* invertible_pin = "IS_OPMODE_INVERTED" *)
input [6:0] OPMODE;
input [47:0] PCIN;
input RSTA;
input RSTALLCARRYIN;
input RSTALUMODE;
input RSTB;
input RSTC;
input RSTCTRL;
input RSTD;
input RSTINMODE;
input RSTM;
input RSTP;
endmodule
module BUFGCE (...); module BUFGCE (...);
parameter CE_TYPE = "SYNC"; parameter CE_TYPE = "SYNC";
parameter [0:0] IS_CE_INVERTED = 1'b0; parameter [0:0] IS_CE_INVERTED = 1'b0;
@ -4020,16 +3932,6 @@ module IBUFDS_INTERMDISABLE (...);
input INTERMDISABLE; input INTERMDISABLE;
endmodule endmodule
module IBUFG (...);
parameter CAPACITANCE = "DONT_CARE";
parameter IBUF_DELAY_VALUE = "0";
parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT";
output O;
(* iopad_external_pin *)
input I;
endmodule
module IBUFGDS (...); module IBUFGDS (...);
parameter CAPACITANCE = "DONT_CARE"; parameter CAPACITANCE = "DONT_CARE";
parameter DIFF_TERM = "FALSE"; parameter DIFF_TERM = "FALSE";

2
tests/ecp5/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.log
/run-test.mk

13
tests/ecp5/add_sub.v Normal file
View File

@ -0,0 +1,13 @@
module top
(
input [3:0] x,
input [3:0] y,
output [3:0] A,
output [3:0] B
);
assign A = x + y;
assign B = x - y;
endmodule

9
tests/ecp5/add_sub.ys Normal file
View File

@ -0,0 +1,9 @@
read_verilog add_sub.v
hierarchy -top top
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 10 t:LUT4
select -assert-none t:LUT4 %% t:* %D

47
tests/ecp5/adffs.v Normal file
View File

@ -0,0 +1,47 @@
module adff
( input d, clk, clr, output reg q );
initial begin
q = 0;
end
always @( posedge clk, posedge clr )
if ( clr )
q <= 1'b0;
else
q <= d;
endmodule
module adffn
( input d, clk, clr, output reg q );
initial begin
q = 0;
end
always @( posedge clk, negedge clr )
if ( !clr )
q <= 1'b0;
else
q <= d;
endmodule
module dffs
( input d, clk, pre, clr, output reg q );
initial begin
q = 0;
end
always @( posedge clk )
if ( pre )
q <= 1'b1;
else
q <= d;
endmodule
module ndffnr
( input d, clk, pre, clr, output reg q );
initial begin
q = 0;
end
always @( negedge clk )
if ( !clr )
q <= 1'b0;
else
q <= d;
endmodule

40
tests/ecp5/adffs.ys Normal file
View File

@ -0,0 +1,40 @@
read_verilog adffs.v
design -save read
hierarchy -top adff
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd adff # Constrain all select calls below inside the top module
select -assert-count 1 t:TRELLIS_FF
select -assert-none t:TRELLIS_FF %% t:* %D
design -load read
hierarchy -top adffn
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd adffn # Constrain all select calls below inside the top module
select -assert-count 1 t:TRELLIS_FF
select -assert-count 1 t:LUT4
select -assert-none t:TRELLIS_FF t:LUT4 %% t:* %D
design -load read
hierarchy -top dffs
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd dffs # Constrain all select calls below inside the top module
select -assert-count 1 t:TRELLIS_FF
select -assert-count 1 t:LUT4
select -assert-none t:TRELLIS_FF t:LUT4 %% t:* %D
design -load read
hierarchy -top ndffnr
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd ndffnr # Constrain all select calls below inside the top module
select -assert-count 1 t:TRELLIS_FF
select -assert-count 1 t:LUT4
select -assert-none t:TRELLIS_FF t:LUT4 %% t:* %D

17
tests/ecp5/counter.v Normal file
View File

@ -0,0 +1,17 @@
module top (
out,
clk,
reset
);
output [7:0] out;
input clk, reset;
reg [7:0] out;
always @(posedge clk, posedge reset)
if (reset) begin
out <= 8'b0 ;
end else
out <= out + 1;
endmodule

10
tests/ecp5/counter.ys Normal file
View File

@ -0,0 +1,10 @@
read_verilog counter.v
hierarchy -top top
proc
flatten
equiv_opt -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 4 t:CCU2C
select -assert-count 8 t:TRELLIS_FF
select -assert-none t:CCU2C t:TRELLIS_FF %% t:* %D

15
tests/ecp5/dffs.v Normal file
View File

@ -0,0 +1,15 @@
module dff
( input d, clk, output reg q );
always @( posedge clk )
q <= d;
endmodule
module dffe
( input d, clk, en, output reg q );
initial begin
q = 0;
end
always @( posedge clk )
if ( en )
q <= d;
endmodule

19
tests/ecp5/dffs.ys Normal file
View File

@ -0,0 +1,19 @@
read_verilog dffs.v
design -save read
hierarchy -top dff
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd dff # Constrain all select calls below inside the top module
select -assert-count 1 t:TRELLIS_FF
select -assert-none t:TRELLIS_FF %% t:* %D
design -load read
hierarchy -top dffe
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd dffe # Constrain all select calls below inside the top module
select -assert-count 1 t:TRELLIS_FF
select -assert-none t:TRELLIS_FF %% t:* %D

23
tests/ecp5/dpram.v Normal file
View File

@ -0,0 +1,23 @@
/*
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 72].
*/
module top (din, write_en, waddr, wclk, raddr, rclk, dout);
parameter addr_width = 8;
parameter data_width = 8;
input [addr_width-1:0] waddr, raddr;
input [data_width-1:0] din;
input write_en, wclk, rclk;
output [data_width-1:0] dout;
reg [data_width-1:0] dout;
reg [data_width-1:0] mem [(1<<addr_width)-1:0]
/* synthesis syn_ramstyle = "no_rw_check" */ ;
always @(posedge wclk) // Write memory.
begin
if (write_en)
mem[waddr] <= din; // Using write address bus.
end
always @(posedge rclk) // Read memory.
begin
dout <= mem[raddr]; // Using read address bus.
end
endmodule

18
tests/ecp5/dpram.ys Normal file
View File

@ -0,0 +1,18 @@
read_verilog dpram.v
hierarchy -top top
proc
memory -nomap
equiv_opt -run :prove -map +/ecp5/cells_sim.v synth_ecp5
memory
opt -full
miter -equiv -flatten -make_assert -make_outputs gold gate miter
#Blocked by issue #1358 (Missing ECP5 simulation models)
#ERROR: Failed to import cell gate.mem.0.0.0 (type DP16KD) to SAT database.
#sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
cd top
select -assert-count 1 t:DP16KD
select -assert-none t:DP16KD %% t:* %D

55
tests/ecp5/fsm.v Normal file
View File

@ -0,0 +1,55 @@
module fsm (
clock,
reset,
req_0,
req_1,
gnt_0,
gnt_1
);
input clock,reset,req_0,req_1;
output gnt_0,gnt_1;
wire clock,reset,req_0,req_1;
reg gnt_0,gnt_1;
parameter SIZE = 3 ;
parameter IDLE = 3'b001,GNT0 = 3'b010,GNT1 = 3'b100,GNT2 = 3'b101 ;
reg [SIZE-1:0] state;
reg [SIZE-1:0] next_state;
always @ (posedge clock)
begin : FSM
if (reset == 1'b1) begin
state <= #1 IDLE;
gnt_0 <= 0;
gnt_1 <= 0;
end else
case(state)
IDLE : if (req_0 == 1'b1) begin
state <= #1 GNT0;
gnt_0 <= 1;
end else if (req_1 == 1'b1) begin
gnt_1 <= 1;
state <= #1 GNT0;
end else begin
state <= #1 IDLE;
end
GNT0 : if (req_0 == 1'b1) begin
state <= #1 GNT0;
end else begin
gnt_0 <= 0;
state <= #1 IDLE;
end
GNT1 : if (req_1 == 1'b1) begin
state <= #1 GNT2;
gnt_1 <= req_0;
end
GNT2 : if (req_0 == 1'b1) begin
state <= #1 GNT1;
gnt_1 <= req_1;
end
default : state <= #1 IDLE;
endcase
end
endmodule

12
tests/ecp5/fsm.ys Normal file
View File

@ -0,0 +1,12 @@
read_verilog fsm.v
hierarchy -top fsm
proc
flatten
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd fsm # Constrain all select calls below inside the top module
select -assert-count 1 t:L6MUX21
select -assert-count 13 t:LUT4
select -assert-count 5 t:PFUMX
select -assert-count 5 t:TRELLIS_FF
select -assert-none t:L6MUX21 t:LUT4 t:PFUMX t:TRELLIS_FF %% t:* %D

24
tests/ecp5/latches.v Normal file
View File

@ -0,0 +1,24 @@
module latchp
( input d, clk, en, output reg q );
always @*
if ( en )
q <= d;
endmodule
module latchn
( input d, clk, en, output reg q );
always @*
if ( !en )
q <= d;
endmodule
module latchsr
( input d, clk, en, clr, pre, output reg q );
always @*
if ( clr )
q <= 1'b0;
else if ( pre )
q <= 1'b1;
else if ( en )
q <= d;
endmodule

35
tests/ecp5/latches.ys Normal file
View File

@ -0,0 +1,35 @@
read_verilog latches.v
design -save read
hierarchy -top latchp
proc
# Can't run any sort of equivalence check because latches are blown to LUTs
synth_ecp5
cd latchp # Constrain all select calls below inside the top module
select -assert-count 1 t:LUT4
select -assert-none t:LUT4 %% t:* %D
design -load read
hierarchy -top latchn
proc
# Can't run any sort of equivalence check because latches are blown to LUTs
synth_ecp5
cd latchn # Constrain all select calls below inside the top module
select -assert-count 1 t:LUT4
select -assert-none t:LUT4 %% t:* %D
design -load read
hierarchy -top latchsr
proc
# Can't run any sort of equivalence check because latches are blown to LUTs
synth_ecp5
cd latchsr # Constrain all select calls below inside the top module
select -assert-count 2 t:LUT4
select -assert-count 1 t:PFUMX
select -assert-none t:LUT4 t:PFUMX %% t:* %D

18
tests/ecp5/logic.v Normal file
View File

@ -0,0 +1,18 @@
module top
(
input [0:7] in,
output B1,B2,B3,B4,B5,B6,B7,B8,B9,B10
);
assign B1 = in[0] & in[1];
assign B2 = in[0] | in[1];
assign B3 = in[0] ~& in[1];
assign B4 = in[0] ~| in[1];
assign B5 = in[0] ^ in[1];
assign B6 = in[0] ~^ in[1];
assign B7 = ~in[0];
assign B8 = in[0];
assign B9 = in[0:1] && in [2:3];
assign B10 = in[0:1] || in [2:3];
endmodule

8
tests/ecp5/logic.ys Normal file
View File

@ -0,0 +1,8 @@
read_verilog logic.v
hierarchy -top top
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 9 t:LUT4
select -assert-none t:LUT4 %% t:* %D

25
tests/ecp5/macc.v Normal file
View File

@ -0,0 +1,25 @@
/*
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 77].
*/
module top(clk,a,b,c,set);
parameter A_WIDTH = 4;
parameter B_WIDTH = 3;
input set;
input clk;
input signed [(A_WIDTH - 1):0] a;
input signed [(B_WIDTH - 1):0] b;
output signed [(A_WIDTH + B_WIDTH - 1):0] c;
reg [(A_WIDTH + B_WIDTH - 1):0] reg_tmp_c;
assign c = reg_tmp_c;
always @(posedge clk)
begin
if(set)
begin
reg_tmp_c <= 0;
end
else
begin
reg_tmp_c <= a * b + c;
end
end
endmodule

13
tests/ecp5/macc.ys Normal file
View File

@ -0,0 +1,13 @@
read_verilog macc.v
hierarchy -top top
proc
# Blocked by issue #1358 (Missing ECP5 simulation models)
#equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
equiv_opt -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:MULT18X18D
select -assert-count 4 t:CCU2C
select -assert-count 7 t:TRELLIS_FF
select -assert-none t:CCU2C t:MULT18X18D t:TRELLIS_FF %% t:* %D

21
tests/ecp5/memory.v Normal file
View File

@ -0,0 +1,21 @@
module top
(
input [7:0] data_a,
input [6:1] addr_a,
input we_a, clk,
output reg [7:0] q_a
);
// Declare the RAM variable
reg [7:0] ram[63:0];
// Port A
always @ (posedge clk)
begin
if (we_a)
begin
ram[addr_a] <= data_a;
q_a <= data_a;
end
q_a <= ram[addr_a];
end
endmodule

19
tests/ecp5/memory.ys Normal file
View File

@ -0,0 +1,19 @@
read_verilog memory.v
hierarchy -top top
proc
memory -nomap
equiv_opt -run :prove -map +/ecp5/cells_sim.v synth_ecp5
memory
opt -full
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
cd top
select -assert-count 24 t:L6MUX21
select -assert-count 71 t:LUT4
select -assert-count 32 t:PFUMX
select -assert-count 8 t:TRELLIS_DPR16X4
select -assert-count 35 t:TRELLIS_FF
select -assert-none t:L6MUX21 t:LUT4 t:PFUMX t:TRELLIS_DPR16X4 t:TRELLIS_FF %% t:* %D

11
tests/ecp5/mul.v Normal file
View File

@ -0,0 +1,11 @@
module top
(
input [5:0] x,
input [5:0] y,
output [11:0] A,
);
assign A = x * y;
endmodule

11
tests/ecp5/mul.ys Normal file
View File

@ -0,0 +1,11 @@
read_verilog mul.v
hierarchy -top top
proc
# Blocked by issue #1358 (Missing ECP5 simulation models)
#equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
equiv_opt -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:MULT18X18D
select -assert-none t:MULT18X18D %% t:* %D

66
tests/ecp5/mux.v Normal file
View File

@ -0,0 +1,66 @@
module mux2 (S,A,B,Y);
input S;
input A,B;
output reg Y;
always @(*)
Y = (S)? B : A;
endmodule
module mux4 ( S, D, Y );
input[1:0] S;
input[3:0] D;
output Y;
reg Y;
wire[1:0] S;
wire[3:0] D;
always @*
begin
case( S )
0 : Y = D[0];
1 : Y = D[1];
2 : Y = D[2];
3 : Y = D[3];
endcase
end
endmodule
module mux8 ( S, D, Y );
input[2:0] S;
input[7:0] D;
output Y;
reg Y;
wire[2:0] S;
wire[7:0] D;
always @*
begin
case( S )
0 : Y = D[0];
1 : Y = D[1];
2 : Y = D[2];
3 : Y = D[3];
4 : Y = D[4];
5 : Y = D[5];
6 : Y = D[6];
7 : Y = D[7];
endcase
end
endmodule
module mux16 (D, S, Y);
input [15:0] D;
input [3:0] S;
output Y;
assign Y = D[S];
endmodule

46
tests/ecp5/mux.ys Normal file
View File

@ -0,0 +1,46 @@
read_verilog mux.v
design -save read
hierarchy -top mux2
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux2 # Constrain all select calls below inside the top module
select -assert-count 1 t:LUT4
select -assert-none t:LUT4 %% t:* %D
design -load read
hierarchy -top mux4
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux4 # Constrain all select calls below inside the top module
select -assert-count 1 t:L6MUX21
select -assert-count 4 t:LUT4
select -assert-count 2 t:PFUMX
select -assert-none t:LUT4 t:L6MUX21 t:PFUMX %% t:* %D
design -load read
hierarchy -top mux8
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux8 # Constrain all select calls below inside the top module
select -assert-count 1 t:L6MUX21
select -assert-count 7 t:LUT4
select -assert-count 2 t:PFUMX
select -assert-none t:LUT4 t:L6MUX21 t:PFUMX %% t:* %D
design -load read
hierarchy -top mux16
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux16 # Constrain all select calls below inside the top module
select -assert-count 8 t:L6MUX21
select -assert-count 26 t:LUT4
select -assert-count 12 t:PFUMX
select -assert-none t:LUT4 t:L6MUX21 t:PFUMX %% t:* %D

18
tests/ecp5/rom.v Normal file
View File

@ -0,0 +1,18 @@
/*
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 74].
*/
module top(data, addr);
output [3:0] data;
input [4:0] addr;
always @(addr) begin
case (addr)
0 : data = 'h4;
1 : data = 'h9;
2 : data = 'h1;
15 : data = 'h8;
16 : data = 'h1;
17 : data = 'h0;
default : data = 'h0;
endcase
end
endmodule

10
tests/ecp5/rom.ys Normal file
View File

@ -0,0 +1,10 @@
read_verilog rom.v
hierarchy -top top
proc
flatten
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 6 t:LUT4
select -assert-count 3 t:PFUMX
select -assert-none t:LUT4 t:PFUMX %% t:* %D

20
tests/ecp5/run-test.sh Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
{
echo "all::"
for x in *.ys; do
echo "all:: run-$x"
echo "run-$x:"
echo " @echo 'Running $x..'"
echo " @../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
done
for s in *.sh; do
if [ "$s" != "run-test.sh" ]; then
echo "all:: run-$s"
echo "run-$s:"
echo " @echo 'Running $s..'"
echo " @bash $s"
fi
done
} > run-test.mk
exec ${MAKE:-make} -f run-test.mk

16
tests/ecp5/shifter.v Normal file
View File

@ -0,0 +1,16 @@
module top (
out,
clk,
in
);
output [7:0] out;
input signed clk, in;
reg signed [7:0] out = 0;
always @(posedge clk)
begin
out <= out >> 1;
out[7] <= in;
end
endmodule

10
tests/ecp5/shifter.ys Normal file
View File

@ -0,0 +1,10 @@
read_verilog shifter.v
hierarchy -top top
proc
flatten
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 8 t:TRELLIS_FF
select -assert-none t:TRELLIS_FF %% t:* %D

8
tests/ecp5/tribuf.v Normal file
View File

@ -0,0 +1,8 @@
module tristate (en, i, o);
input en;
input i;
output o;
assign o = en ? i : 1'bz;
endmodule

9
tests/ecp5/tribuf.ys Normal file
View File

@ -0,0 +1,9 @@
read_verilog tribuf.v
hierarchy -top tristate
proc
flatten
equiv_opt -assert -map +/ecp5/cells_sim.v -map +/simcells.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd tristate # Constrain all select calls below inside the top module
select -assert-count 1 t:$_TBUF_
select -assert-none t:$_TBUF_ %% t:* %D

View File

@ -1,14 +1,11 @@
read_verilog latches.v read_verilog latches.v
design -save read
proc proc
async2sync # converts latches to a 'sync' variant clocked by a 'super'-clock
flatten flatten
synth_ice40 # Can't run any sort of equivalence check because latches are blown to LUTs
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check #equiv_opt -async2sync -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
design -load read #design -load preopt
synth_ice40 synth_ice40
cd top cd top
select -assert-count 4 t:SB_LUT4 select -assert-count 4 t:SB_LUT4

22
tests/ice40/wrapcarry.ys Normal file
View File

@ -0,0 +1,22 @@
read_verilog <<EOT
module top(input A, B, CI, output O, CO);
SB_CARRY carry (
.I0(A),
.I1(B),
.CI(CI),
.CO(CO)
);
SB_LUT4 #(
.LUT_INIT(16'b 0110_1001_1001_0110)
) adder (
.I0(1'b0),
.I1(A),
.I2(B),
.I3(1'b0),
.O(O)
);
endmodule
EOT
ice40_wrapcarry
select -assert-count 1 t:$__ICE40_CARRY_WRAPPER

3
tests/svtypes/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/*.log
/*.out
/run-test.mk

20
tests/svtypes/run-test.sh Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
{
echo "all::"
for x in *.ys; do
echo "all:: run-$x"
echo "run-$x:"
echo " @echo 'Running $x..'"
echo " @../../yosys -ql ${x%.ys}.log $x"
done
for x in *.sv; do
if [ ! -f "${x%.sv}.ys" ]; then
echo "all:: check-$x"
echo "check-$x:"
echo " @echo 'Checking $x..'"
echo " @../../yosys -ql ${x%.sv}.log -p \"prep -top top; sat -verify -prove-asserts\" $x"
fi
done
} > run-test.mk
exec ${MAKE:-make} -f run-test.mk

View File

@ -0,0 +1,10 @@
module top(input [3:0] addr, wdata, input clk, wen, output reg [3:0] rdata);
typedef logic [3:0] ram16x4_t[0:15];
(ram16x4_t) mem;
always @(posedge clk) begin
if (wen) mem[addr] <= wdata;
rdata <= mem[addr];
end
endmodule

View File

@ -0,0 +1,3 @@
read_verilog -sv typedef_memory.sv
prep -top top
select -assert-count 1 t:$mem r:SIZE=16 %i r:WIDTH=4 %i

Some files were not shown because too many files have changed in this diff Show More