/* * Copyright (c) 2011-2025 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * Copyright CERN 2016 * @author Maciej Suminski * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # define __STDC_LIMIT_MACROS # include "parse_misc.h" # include "compiler.h" # include "package.h" # include "std_types.h" # include "std_funcs.h" # include # include # include # include # include # include # include using namespace std; /* * The library_work_path is the path to the work directory. */ static const char*library_work_path = 0; /* * The library_search_path is a list of directory names to search to * find a named library. The library name is the name given to the * "import" statement. */ static list library_search_path; /* * The "import" statement causes me to build a map of a library name * to a library directory. */ static map library_dir; /* * The "libraries" table maps library name to a set of packages. This * map is filled in by "use" statements. */ struct library_contents { map packages; }; static map libraries; void library_add_directory(const char*directory) { // Make sure the directory path really is a directory. Ignore // it if it is not. struct stat stat_buf; int rc = stat(directory, &stat_buf); if (rc < 0 || !S_ISDIR(stat_buf.st_mode)) { return; } library_search_path.push_front(directory); } SubprogramHeader*library_match_subprogram(perm_string name, const list*params) { SubprogramHeader*subp; map::const_iterator lib_it; for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) { const struct library_contents&lib = lib_it->second; map::const_iterator pack_it; for(pack_it = lib.packages.begin(); pack_it != lib.packages.end(); ++pack_it) { if((subp = pack_it->second->match_subprogram(name, params))) return subp; } } return NULL; } static void store_package_in_work(const Package*pack); static string make_work_package_path(const char*name) { return string(library_work_path).append("/").append(name).append(".pkg"); } static string make_library_package_path(perm_string lib_name, perm_string name) { string path = library_dir[lib_name]; if (path == "") return ""; path = path.append("/").append(name).append(".pkg"); return path; } static void import_ieee(void); static void import_ieee_use(const YYLTYPE&loc, ActiveScope*res, perm_string package, perm_string name); static void import_std_use(const YYLTYPE&loc, ActiveScope*res, perm_string package, perm_string name); static void dump_library_package(ostream&file, perm_string lname, perm_string pname, const Package*pack) { file << "package " << lname << "." << pname << endl; if (pack) { pack->dump_scope(file); } else { file << " " << endl; } file << "end package " << lname << "." << pname << endl; } static void dump_library_packages(ostream&file, perm_string lname, mappackages) { for (map::iterator cur = packages.begin() ; cur != packages.end() ; ++cur) { dump_library_package(file, lname, cur->first, cur->second); } } void dump_libraries(ostream&file) { for (map::iterator cur = libraries.begin() ; cur != libraries.end() ; ++cur) { dump_library_packages(file, cur->first, cur->second.packages); } } /* * This function saves a package into the named library. Create the * library if necessary. The parser uses this when it is finished with * a package declaration. */ void library_save_package(perm_string parse_library_name, Package*pack) { perm_string use_libname = parse_library_name.str() ? parse_library_name : perm_string::literal("work"); struct library_contents&lib = libraries[use_libname]; lib.packages[pack->name()] = pack; // If this is a work package, and we are NOT parsing the work // library right now, then store it in the work library. if (parse_library_name.str() == 0) store_package_in_work(pack); else pack->set_library(parse_library_name); } /* * The parser uses this function in the package body rule to recall * the package that was declared earlier. */ Package*library_recall_package(perm_string parse_library_name, perm_string package_name) { perm_string use_libname = parse_library_name.str() ? parse_library_name : perm_string::literal("work"); map::iterator lib = libraries.find(use_libname); if (lib == libraries.end()) return 0; map::iterator pkg = lib->second.packages.find(package_name); if (pkg == lib->second.packages.end()) return 0; return pkg->second; } static void import_library_name(const YYLTYPE&loc, perm_string name) { if (library_dir[name] != string()) return; for (list::const_iterator cur = library_search_path.begin() ; cur != library_search_path.end() ; ++cur) { string curdir = *cur; string try_path = curdir.append("/").append(name); struct stat stat_buf; int rc = stat(try_path.c_str(), &stat_buf); if (rc < 0) continue; if (!S_ISDIR(stat_buf.st_mode)) continue; library_dir[name] = try_path; return; } errormsg(loc, "library import cannot find library %s\n", name.str()); } void library_import(const YYLTYPE&loc, const std::list*names) { for (std::list::const_iterator cur = names->begin() ; cur != names->end() ; ++cur) { if (*cur == "ieee") { // The ieee library is special and handled by an // internal function. import_ieee(); } else if (*cur == "std") { // The std library is always implicitly imported. } else if (*cur == "work") { // The work library is always implicitly imported. } else { // Otherwise, do a generic library import import_library_name(loc, *cur); } } } void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*package, const char*name) { if (libname == 0) { errormsg(loc, "error: No library name for this use clause?\n"); return; } perm_string use_library = lex_strings.make(libname); perm_string use_package = lex_strings.make(package); perm_string use_name = name? lex_strings.make(name) : perm_string::literal("all"); // Special case handling for the IEEE library. if (use_library == "ieee") { import_ieee_use(loc, res, use_package, use_name); return; } // Special case handling for the STD library. if (use_library == "std") { import_std_use(loc, res, use_package, use_name); return; } struct library_contents&lib = libraries[use_library]; Package*pack = lib.packages[use_package]; // If the package is not found in the work library already // parsed, then see if it exists unparsed. if (use_library=="work" && pack == 0) { string path = make_work_package_path(use_package.str()); parse_source_file(path.c_str(), use_library); pack = lib.packages[use_package]; } else if (use_library != "ieee" && pack == 0) { string path = make_library_package_path(use_library, use_package); if (path == "") { errormsg(loc, "Unable to find library %s\n", use_library.str()); return; } int rc = parse_source_file(path.c_str(), use_library); if (rc < 0) errormsg(loc, "Unable to open library file %s\n", path.c_str()); else if (rc > 0) errormsg(loc, "Errors in library file %s\n", path.c_str()); else pack = lib.packages[use_package]; } // If the package is still not found, then error. if (pack == 0) { errormsg(loc, "No package %s in library %s\n", use_package.str(), use_library.str()); return; } // We have a package that we are going to extract names // from. Use the name to get the selected objects, and write // results into the "res" members. if (use_name == "all") { res->use_from(pack); return; } if (ComponentBase*cur = pack->find_component(use_name)) { res->bind_name(use_name, cur); return; } errormsg(loc, "No such name %s in package %s\n", use_name.str(), pack->name().str()); } static void import_ieee(void) { } static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name) { bool all_flag = name=="all"; if (all_flag || name == "std_logic_vector") { res->use_name(perm_string::literal("std_logic_vector"), &primitive_STDLOGIC_VECTOR); } } static void import_ieee_use_std_logic_misc(ActiveScope*, perm_string name) { bool all_flag = name=="all"; list*args; if (all_flag || name == "or_reduce") { /* function or_reduce(arg : std_logic_vector) return std_logic; */ args = new list(); args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); register_std_subprogram(new SubprogramBuiltin(perm_string::literal("or_reduce"), perm_string::literal("|"), args, &primitive_STDLOGIC)); } if (all_flag || name == "and_reduce") { /* function and_reduce(arg : std_logic_vector) return std_logic; */ args = new list(); args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); register_std_subprogram(new SubprogramBuiltin(perm_string::literal("and_reduce"), perm_string::literal("&"), args, &primitive_STDLOGIC)); } } static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name) { bool all_flag = name=="all"; if (all_flag || name == "signed") { res->use_name(perm_string::literal("signed"), &primitive_SIGNED); } if (all_flag || name == "unsigned") { res->use_name(perm_string::literal("unsigned"), &primitive_UNSIGNED); } } static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name) { bool all_flag = name=="all"; if (all_flag || name == "signed") { res->use_name(perm_string::literal("signed"), &primitive_SIGNED); } if (all_flag || name == "unsigned") { res->use_name(perm_string::literal("unsigned"), &primitive_UNSIGNED); } } static void import_ieee_use(const YYLTYPE&/*loc*/, ActiveScope*res, perm_string package, perm_string name) { if (package == "std_logic_1164") { import_ieee_use_std_logic_1164(res, name); return; } if (package == "std_logic_arith") { // arithmetic operators for std_logic_vector return; } if (package == "std_logic_misc") { import_ieee_use_std_logic_misc(res, name); return; } if (package == "std_logic_unsigned") { // arithmetic operators for std_logic_vector return; } if (package == "numeric_bit") { import_ieee_use_numeric_bit(res, name); return; } if (package == "numeric_std") { import_ieee_use_numeric_std(res, name); return; } cerr << "Warning: Package ieee." << package.str() <<" is not yet supported" << endl; } static void import_std_use(const YYLTYPE&/*loc*/, ActiveScope*res, perm_string package, perm_string /*name*/) { if (package == "standard") { // do nothing return; } else if (package == "textio") { res->use_name(perm_string::literal("text"), &primitive_INTEGER); res->use_name(perm_string::literal("line"), &primitive_STRING); res->use_name(type_FILE_OPEN_KIND.peek_name(), &type_FILE_OPEN_KIND); res->use_name(type_FILE_OPEN_STATUS.peek_name(), &type_FILE_OPEN_STATUS); return; } else { cerr << "Warning: Package std." << package.str() <<" is not yet supported" << endl; return; } } void library_set_work_path(const char*path) { assert(library_work_path == 0); library_work_path = path; } list work_packages; static void store_package_in_work(const Package*pack) { work_packages.push_back(pack); } static int emit_packages(perm_string, const map&packages) { int errors = 0; for (map::const_iterator cur = packages.begin() ; cur != packages.end() ; ++cur) { errors += cur->second->emit_package(cout); } for (list::const_iterator cur = work_packages.begin() ; cur != work_packages.end(); ++cur) { string path = make_work_package_path((*cur)->name()); ofstream file (path.c_str(), ios_base::out); (*cur)->write_to_stream(file); } return errors; } int emit_packages(void) { int errors = 0; for (map::iterator cur = libraries.begin() ; cur != libraries.end() ; ++cur) { errors += emit_packages(cur->first, cur->second.packages); } return errors; } static int elaborate_library_packages(mappackages) { int errors = 0; for (map::iterator cur = packages.begin() ; cur != packages.end() ; ++cur) { errors += cur->second->elaborate(); } return errors; } int elaborate_libraries() { int errors = 0; for (map::iterator cur = libraries.begin() ; cur != libraries.end() ; ++cur) { errors += elaborate_library_packages(cur->second.packages); } return errors; }