From 696412df40f9c04c0178702b770e715d759c9efc Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 8 Sep 2022 21:01:02 +0200 Subject: [PATCH] :sparkles: QLL writer for mQCA (MagCAD & SCERPA) (#49) * :sparkles: Adjusted write_qll_layout for mQCA files aimed at the SCERPA simulator and MagCAD's mQCA plugin * :bug: Prevent I/O cells from being handled twice in the mQCA qll writer and represent constant cells as input pins * :bug: Correctly handle multi-layer mQCA designs * :bug: Fix additional via cells * :memo: Added documentation on SCERPA --- README.md | 7 +- cli/cmd/io/qll.hpp | 5 +- docs/cli.rst | 4 +- docs/io/physical_simulation.rst | 18 +- include/fiction/io/write_qll_layout.hpp | 265 +++++++++------ test/io/write_qll_layout.cpp | 352 +++++++++++++++++++- test/utils/blueprints/layout_blueprints.hpp | 97 ++++++ 7 files changed, 630 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 9a32c84cb..695d022f3 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ Gate libraries: File formats: - `*.qca` for [QCADesigner](https://waluslab.ece.ubc.ca/qcadesigner/) +- `*.qll` for [MagCAD](https://topolinano.polito.it/) and [SCERPA](https://ieeexplore.ieee.org/document/8935211) - `*.fqca` for [QCA-STACK](https://github.com/wlambooy/QCA-STACK) - `*.svg` for visual representation @@ -89,10 +90,10 @@ Gate libraries: File formats: -- `*.qll` for [ToPoliNano and MagCAD](https://topolinano.polito.it/) -- `*.qcc` for [ToPoliNano and MagCAD](https://topolinano.polito.it/) +- `*.qcc` for [ToPoliNano](https://topolinano.polito.it/) +- `*.qll` for [ToPoliNano & MagCAD](https://topolinano.polito.it/) -Many thanks to Umberto Garlando and Fabrizio Riente for their support! +Many thanks to Umberto Garlando, Fabrizio Riente, and Giuliana Beretta for their support! ### Silicon Dangling Bonds (SiDBs) diff --git a/cli/cmd/io/qll.hpp b/cli/cmd/io/qll.hpp index 9254dde6d..9494a6365 100644 --- a/cli/cmd/io/qll.hpp +++ b/cli/cmd/io/qll.hpp @@ -61,13 +61,14 @@ class qll_command : public command { using Lyt = typename std::decay_t::element_type; - if constexpr (std::is_same_v, fiction::inml_technology>) + if constexpr (std::is_same_v, fiction::inml_technology> || + std::is_same_v, fiction::qca_technology>) { fiction::write_qll_layout(*lyt_ptr, filename); } else { - env->out() << fmt::format("[e] {}'s cell technology is not iNML but {}", get_name(lyt_ptr), + env->out() << fmt::format("[e] {}'s cell technology is neither iNML nor QCA but {}", get_name(lyt_ptr), fiction::tech_impl_name>) << std::endl; } diff --git a/docs/cli.rst b/docs/cli.rst index efc941c5e..415656839 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -254,8 +254,8 @@ Cell-level layouts can be written to files parsable by various physical simulato simulators are currently supported: - ``qca `` creates a `QCADesigner `_ QCA file -- ``qll `` creates a `ToPoliNano & MagCAD `_ QLL file -- ``qcc `` creates a `ToPoliNano & MagCAD `_ QCC file +- ``qcc `` creates a `ToPoliNano `_ design component QCC file +- ``qll `` creates a `ToPoliNano & MagCAD `_ or `SCERPA `_ layout QLL file - ``sqd `` creates a `SiQAD `_ SQD file - ``fqca `` creates a `QCA-STACK `_ FQCA file diff --git a/docs/io/physical_simulation.rst b/docs/io/physical_simulation.rst index 6a9f147c5..84aabfb31 100644 --- a/docs/io/physical_simulation.rst +++ b/docs/io/physical_simulation.rst @@ -24,20 +24,22 @@ QCA-STACK .. doxygenfunction:: fiction::read_fqca_layout(std::istream& is, const std::string& name = "") .. doxygenfunction:: fiction::read_fqca_layout(const std::string& filename, const std::string& name = "") -ToPoliNano & MagCAD -################### - -**Header:** ``fiction/io/write_qll_layout.hpp`` - -.. doxygenfunction:: fiction::write_qll_layout(const Lyt& lyt, std::ostream& os) -.. doxygenfunction:: fiction::write_qll_layout(const Lyt& lyt, const std::string& filename) - +ToPoliNano +########## **Header:** ``fiction/io/write_qcc_layout.hpp`` .. doxygenfunction:: fiction::write_qcc_layout(const Lyt& lyt, std::ostream& os, write_qcc_layout_params ps = {}) .. doxygenfunction:: fiction::write_qcc_layout(const Lyt& lyt, const std::string& filename, write_qcc_layout_params ps = {}) +MagCAD & SCERPA +############### + +**Header:** ``fiction/io/write_qll_layout.hpp`` + +.. doxygenfunction:: fiction::write_qll_layout(const Lyt& lyt, std::ostream& os) +.. doxygenfunction:: fiction::write_qll_layout(const Lyt& lyt, const std::string& filename) + SiQAD ##### diff --git a/include/fiction/io/write_qll_layout.hpp b/include/fiction/io/write_qll_layout.hpp index 796eccb82..c115fa7f0 100644 --- a/include/fiction/io/write_qll_layout.hpp +++ b/include/fiction/io/write_qll_layout.hpp @@ -45,30 +45,41 @@ static constexpr const char* CLOSE_QCA_LAYOUT = "\n"; static constexpr const char* OPEN_TECHNOLOGIES = "\t\n"; static constexpr const char* CLOSE_TECHNOLOGIES = "\t\n"; -static constexpr const char* SETTINGS_BLOCK = "\t\t\n" // technology - "\t\t\t\n" // layout width - "\t\t\t\n" // layout height - "\t\t\t\n" // num clocks - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" - "\t\t\n"; +static constexpr const char* OPEN_SETTINGS = "\t\t\n"; // technology + +static constexpr const char* GENERAL_SETTINGS = + "\t\t\t\n" // layout width + "\t\t\t\n" // layout height + "\t\t\t\n" // multi-layer design + "\t\t\t\n" // num clocks + "\t\t\t\n"; + +static constexpr const char* INML_SETTINGS = "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n"; + +static constexpr const char* MQCA_SETTINGS = "\t\t\t\n"; + +static constexpr const char* CLOSE_SETTINGS = "\t\t\n"; static constexpr const char* OPEN_COMPONENTS = "\t\n"; static constexpr const char* CLOSE_COMPONENTS = "\t\n"; static constexpr const char* OPEN_LAYOUT = "\t\n"; static constexpr const char* CLOSE_LAYOUT = "\t\n"; -static constexpr const char* COMPONENT_ITEM = "\t\t\n"; -static constexpr const char* OPEN_LAYOUT_ITEM = "\t\t\n"; +static constexpr const char* INML_COMPONENT_ITEM = "\t\t\n"; +static constexpr const char* MQCA_COMPONENT_ITEM = "\t\t\n"; + +static constexpr const char* OPEN_INML_LAYOUT_ITEM = "\t\t\n"; +static constexpr const char* OPEN_MQCA_LAYOUT_ITEM = + "\t\t\n"; + static constexpr const char* CLOSE_LAYOUT_ITEM = "\t\t\n"; static constexpr const char* LAYOUT_ITEM_PROPERTY = "\t\t\t\n"; @@ -81,7 +92,7 @@ static constexpr const char* PIN = static constexpr const std::array components{"Magnet", "Coupler", "Cross Wire", "And", "Inverter", "Or"}; -static const std::map component_selector{ +static const std::map inml_component_selector{ {inml_technology::cell_type::NORMAL, 0}, {inml_technology::cell_type::INPUT, 0}, {inml_technology::cell_type::OUTPUT, 0}, {inml_technology::cell_type::FANOUT_COUPLER_MAGNET, 1}, {inml_technology::cell_type::CROSSWIRE_MAGNET, 2}, {inml_technology::cell_type::SLANTED_EDGE_DOWN_MAGNET, 3}, @@ -104,11 +115,11 @@ class write_qll_layout_impl void run() { - if (!has_border_io_pins()) + if (std::is_same_v, inml_technology> && !has_border_io_pins()) { throw std::invalid_argument( - "the iNML layout does not fulfill all requirements to be written as a QCC file because it does not " - "have designated I/O pins or they are not routed to the layout's borders"); + "the layout does not fulfill all requirements to be written as a QLL file because it does not have " + "designated I/O pins or they are not routed to the layout's borders"); } write_header(); @@ -132,7 +143,11 @@ class write_qll_layout_impl std::ostream& os; - uint64_t magnet_id{1}; + uint64_t cell_id{1}; + + const char* tech_name{std::is_same_v, inml_technology> ? "iNML" : + std::is_same_v, qca_technology> ? "MolQCA" : + "?"}; [[nodiscard]] std::vector> sorted_pis() const noexcept { @@ -200,17 +215,40 @@ class write_qll_layout_impl void write_technology_settings() { os << qll::OPEN_TECHNOLOGIES; - os << fmt::format(qll::SETTINGS_BLOCK, tech_impl_name>, lyt.x(), lyt.y(), lyt.num_clocks()); + + os << fmt::format(qll::OPEN_SETTINGS, tech_name); + + os << fmt::format(qll::GENERAL_SETTINGS, lyt.x(), lyt.y(), (lyt.z() > 0 ? "true" : "false"), lyt.num_clocks()); + + if constexpr (std::is_same_v, inml_technology>) + { + os << qll::INML_SETTINGS; + } + else if constexpr (std::is_same_v, qca_technology>) + { + os << qll::MQCA_SETTINGS; + } + + os << qll::CLOSE_SETTINGS; os << qll::CLOSE_TECHNOLOGIES; } void write_components() { os << qll::OPEN_COMPONENTS; - for (const auto& comp : qll::components) + + if constexpr (std::is_same_v, inml_technology>) { - os << fmt::format(qll::COMPONENT_ITEM, tech_impl_name>, comp); + for (const auto& comp : qll::components) + { + os << fmt::format(qll::INML_COMPONENT_ITEM, tech_name, comp); + } } + else if constexpr (std::is_same_v, qca_technology>) + { + os << qll::MQCA_COMPONENT_ITEM; + } + os << qll::CLOSE_COMPONENTS; } @@ -218,13 +256,11 @@ class write_qll_layout_impl { for (const auto& pi : sorted_pi_list) { - os << fmt::format(qll::PIN, tech_impl_name>, lyt.get_cell_name(pi), 0, magnet_id++, - bb_x(pi), bb_y(pi), pi.z); + os << fmt::format(qll::PIN, tech_name, lyt.get_cell_name(pi), 0, cell_id++, bb_x(pi), bb_y(pi), pi.z); } for (const auto& po : sorted_po_list) { - os << fmt::format(qll::PIN, tech_impl_name>, lyt.get_cell_name(po), 1, magnet_id++, - bb_x(po), bb_y(po), po.z); + os << fmt::format(qll::PIN, tech_name, lyt.get_cell_name(po), 1, cell_id++, bb_x(po), bb_y(po), po.z); } } @@ -234,72 +270,108 @@ class write_qll_layout_impl os << qll::OPEN_LAYOUT; - for (decltype(lyt.y()) row = 0; row <= lyt.y(); ++row) + for (decltype(lyt.z()) layer = 0; layer <= lyt.z(); ++layer) { - for (decltype(lyt.x()) col = 0; col <= lyt.x(); ++col) + for (decltype(lyt.y()) row = 0; row <= lyt.y(); ++row) { - const auto c = cell{col, row}; - const auto type = lyt.get_cell_type(c); - - // skip empty cells and cells marked as to be skipped as well (duh...) - if (lyt.is_empty_cell(c) || skip.count(c) > 0u) - { - continue; - } - - // if an AND or an OR structure is encountered, the next two magnets in southern direction need to - // be skipped - if (type == inml_technology::cell_type::SLANTED_EDGE_UP_MAGNET || - type == inml_technology::cell_type::SLANTED_EDGE_DOWN_MAGNET) - { - skip.insert({c.x, c.y + 1}); - skip.insert({c.x, c.y + 2}); - } - // if a coupler is encountered, skip all magnets relating to the fan-out structure - else if (type == inml_technology::cell_type::FANOUT_COUPLER_MAGNET) + for (decltype(lyt.x()) col = 0; col <= lyt.x(); ++col) { - skip.insert({c.x, c.y + 1}); - skip.insert({c.x, c.y + 2}); - skip.insert({c.x + 1, c.y}); - skip.insert({c.x + 1, c.y + 2}); + const auto c = cell{col, row, layer}; + const auto type = lyt.get_cell_type(c); + + // skip empty cells and cells marked as to be skipped as well (duh...) + if (lyt.is_empty_cell(c) || skip.count(c) > 0u) + { + continue; + } + + // write iNML cell + if constexpr (std::is_same_v, inml_technology>) + { + // if an AND or an OR structure is encountered, the next two magnets in southern direction need + // to be skipped + if (type == inml_technology::cell_type::SLANTED_EDGE_UP_MAGNET || + type == inml_technology::cell_type::SLANTED_EDGE_DOWN_MAGNET) + { + skip.insert({c.x, c.y + 1}); + skip.insert({c.x, c.y + 2}); + } + // if a coupler is encountered, skip all magnets relating to the fan-out structure + else if (type == inml_technology::cell_type::FANOUT_COUPLER_MAGNET) + { + skip.insert({c.x, c.y + 1}); + skip.insert({c.x, c.y + 2}); + skip.insert({c.x + 1, c.y}); + skip.insert({c.x + 1, c.y + 2}); + } + // if a cross wire is encountered, skip all magnets relating to the crossing structure + else if (type == inml_technology::cell_type::CROSSWIRE_MAGNET) + { + skip.insert({c.x + 2, c.y}); + skip.insert({c.x, c.y + 2}); + skip.insert({c.x + 1, c.y + 1}); + skip.insert({c.x + 2, c.y + 2}); + } + // inverters are single structures taking up 4 magnets in the library, so skip the next 3 if + // encountered one + else if (type == inml_technology::cell_type::INVERTER_MAGNET) + { + skip.insert({c.x + 1, c.y}); + skip.insert({c.x + 2, c.y}); + skip.insert({c.x + 3, c.y}); + } + + if (const auto it = qll::inml_component_selector.find(type); + it != qll::inml_component_selector.end()) + { + os << fmt::format(qll::OPEN_INML_LAYOUT_ITEM, it->second, cell_id++, bb_x(c), bb_y(c)); + } + else + { + std::cout << fmt::format("[w] cell at position {} has an unsupported type", c) << std::endl; + } + + os << fmt::format(qll::LAYOUT_ITEM_PROPERTY, qll::PROPERTY_PHASE, lyt.get_clock_number(c)); + + if (type == inml_technology::cell_type::INVERTER_MAGNET) + { + os << fmt::format(qll::LAYOUT_ITEM_PROPERTY, qll::PROPERTY_LENGTH, 4); + } + + os << qll::CLOSE_LAYOUT_ITEM; + } + // write mQCA cell + else if constexpr (std::is_same_v, qca_technology>) + { + const auto mode = lyt.get_cell_mode(c); + + // write normal cell + if (qca_technology::is_normal_cell(type)) + { + os << fmt::format(qll::OPEN_MQCA_LAYOUT_ITEM, 0, cell_id++, bb_x(c), bb_y(c), c.z * 2); + os << fmt::format(qll::LAYOUT_ITEM_PROPERTY, qll::PROPERTY_PHASE, lyt.get_clock_number(c)); + os << qll::CLOSE_LAYOUT_ITEM; + } + // constant cells are handled as input pins + else if (qca_technology::is_constant_cell(type)) + { + const auto const_name = qca_technology::is_const_0_cell(type) ? "const0" : "const1"; + os << fmt::format(qll::PIN, tech_name, const_name, 0, cell_id++, bb_x(c), bb_y(c), c.z * 2); + } + + // write via cell + if (qca_technology::is_vertical_cell_mode(mode) && c.z != lyt.z()) + { + os << fmt::format(qll::OPEN_MQCA_LAYOUT_ITEM, 0, cell_id++, bb_x(c), bb_y(c), c.z * 2 + 1); + os << fmt::format(qll::LAYOUT_ITEM_PROPERTY, qll::PROPERTY_PHASE, lyt.get_clock_number(c)); + os << qll::CLOSE_LAYOUT_ITEM; + } + } } - // if a cross wire is encountered, skip all magnets relating to the crossing structure - else if (type == inml_technology::cell_type::CROSSWIRE_MAGNET) - { - skip.insert({c.x + 2, c.y}); - skip.insert({c.x, c.y + 2}); - skip.insert({c.x + 1, c.y + 1}); - skip.insert({c.x + 2, c.y + 2}); - } - // inverters are single structures taking up 4 magnets in the library, so skip the next 3 if - // encountered one - else if (type == inml_technology::cell_type::INVERTER_MAGNET) - { - skip.insert({c.x + 1, c.y}); - skip.insert({c.x + 2, c.y}); - skip.insert({c.x + 3, c.y}); - } - - if (const auto it = qll::component_selector.find(type); it != qll::component_selector.end()) - { - os << fmt::format(qll::OPEN_LAYOUT_ITEM, it->second, magnet_id++, bb_x(c), bb_y(c)); - } - else - { - std::cout << fmt::format("[w] cell at position {} has an unsupported type", c) << std::endl; - } - - os << fmt::format(qll::LAYOUT_ITEM_PROPERTY, qll::PROPERTY_PHASE, lyt.get_clock_number(c)); - - if (type == inml_technology::cell_type::INVERTER_MAGNET) - { - os << fmt::format(qll::LAYOUT_ITEM_PROPERTY, qll::PROPERTY_LENGTH, 4); - } - - os << qll::CLOSE_LAYOUT_ITEM; } } + // I/O cells are not considered in the cases above because they need to be handled separately write_pins(); os << qll::CLOSE_LAYOUT; @@ -309,12 +381,13 @@ class write_qll_layout_impl } // namespace detail /** - * Writes a cell-level iNML layout to a qll file that is used by ToPoliNano & MagCAD (https://topolinano.polito.it/), - * an EDA tool and a physical simulator for the iNML technology platform. + * Writes a cell-level QCA or iNML layout to a qll file that is used by ToPoliNano & MagCAD + * (https://topolinano.polito.it/), an EDA tool and a physical simulator for the iNML technology platform as well as + * SCERPA (https://ieeexplore.ieee.org/document/8935211), a physical simulator for the mQCA technology platform. * * This overload uses an output stream to write into. * - * @tparam Lyt Cell-level iNML layout type. + * @tparam Lyt Cell-level QCA or iNML layout type. * @param lyt The layout to be written. * @param os The output stream to write into. * @param ps Parameters. @@ -323,15 +396,17 @@ template void write_qll_layout(const Lyt& lyt, std::ostream& os) { static_assert(is_cell_level_layout_v, "Lyt is not a cell-level layout"); - static_assert(std::is_same_v, inml_technology>, "Lyt must be an iNML layout"); + static_assert(std::is_same_v, inml_technology> || std::is_same_v, qca_technology>, + "Lyt must be a QCA or an iNML layout"); detail::write_qll_layout_impl p{lyt, os}; p.run(); } /** - * Writes a cell-level iNML layout to a qll file that is used by ToPoliNano & MagCAD (https://topolinano.polito.it/), - * an EDA tool and a physical simulator for the iNML technology platform. + * Writes a cell-level QCA or iNML layout to a qll file that is used by ToPoliNano & MagCAD + * (https://topolinano.polito.it/), an EDA tool and a physical simulator for the iNML technology platform as well as + * SCERPA (https://ieeexplore.ieee.org/document/8935211), a physical simulator for the mQCA technology platform. * * This overload uses a file name to create and write into. * diff --git a/test/io/write_qll_layout.cpp b/test/io/write_qll_layout.cpp index 7cd519536..0fcd1e373 100644 --- a/test/io/write_qll_layout.cpp +++ b/test/io/write_qll_layout.cpp @@ -17,7 +17,7 @@ using namespace fiction; -TEST_CASE("Write empty layout", "[qll]") +TEST_CASE("Write empty iNML layout", "[qll]") { static const std::string qll_layout = fmt::format("\n" "\n" @@ -26,7 +26,9 @@ TEST_CASE("Write empty layout", "[qll]") "\t\t\n" "\t\t\t\n" "\t\t\t\n" + "\t\t\t\n" "\t\t\t\n" + "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" @@ -35,8 +37,6 @@ TEST_CASE("Write empty layout", "[qll]") "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\n" @@ -55,14 +55,32 @@ TEST_CASE("Write empty layout", "[qll]") std::ostringstream layout_stream{}; - const inml_cell_clk_lyt layout{{2, 2, 1}, "empty layout"}; + const inml_cell_clk_lyt layout{{2, 2}, "empty layout"}; write_qll_layout(layout, layout_stream); CHECK(layout_stream.str() == qll_layout); } -TEST_CASE("Write single-layer MAJ gate", "[qll]") +TEST_CASE("Abort on non-pin iNML layouts", "[qll]") +{ + std::ostringstream layout_stream{}; + + inml_cell_clk_lyt layout{{4, 4}, "Non-pin layout"}; + + // add two normal cells to span a bounding boy + layout.assign_cell_type({0, 0}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({4, 4}, fiction::inml_technology::cell_type::NORMAL); + + // add I/O cells inside the bounding box such that they are not located at the borders + layout.assign_cell_type({1, 1}, fiction::inml_technology::cell_type::INPUT); + layout.assign_cell_type({2, 2}, fiction::inml_technology::cell_type::OUTPUT); + + // this layout should throw an exception + CHECK_THROWS_AS(write_qll_layout(layout, layout_stream), std::invalid_argument); +} + +TEST_CASE("Write single-layer iNML MAJ gate", "[qll]") { static const std::string qll_layout = fmt::format("\n" @@ -72,7 +90,9 @@ TEST_CASE("Write single-layer MAJ gate", "[qll]") "\t\t\n" "\t\t\t\n" "\t\t\t\n" + "\t\t\t\n" "\t\t\t\n" + "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" @@ -81,8 +101,6 @@ TEST_CASE("Write single-layer MAJ gate", "[qll]") "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" - "\t\t\t\n" - "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\n" @@ -149,4 +167,322 @@ TEST_CASE("Write single-layer MAJ gate", "[qll]") write_qll_layout(layout, layout_stream); CHECK(layout_stream.str() == qll_layout); -} \ No newline at end of file +} + +TEST_CASE("Write single-layer iNML coupler with inverter magnet", "[qll]") +{ + static const std::string qll_layout = + fmt::format("\n" + "\n" + "\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\n" + "\n", + FICTION_VERSION, FICTION_REPO); + + std::ostringstream layout_stream{}; + + const auto layout = blueprints::single_layer_inml_coupler_with_inverter(); + + write_qll_layout(layout, layout_stream); + + CHECK(layout_stream.str() == qll_layout); +} + +TEST_CASE("Write single-layer iNML crosswire", "[qll]") +{ + static const std::string qll_layout = + fmt::format("\n" + "\n" + "\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\n" + "\n", + FICTION_VERSION, FICTION_REPO); + + std::ostringstream layout_stream{}; + + const auto layout = blueprints::single_layer_inml_crosswire(); + + write_qll_layout(layout, layout_stream); + + CHECK(layout_stream.str() == qll_layout); +} + +TEST_CASE("Write empty mQCA layout", "[qll]") +{ + static const std::string qll_layout = + fmt::format("\n" + "\n" + "\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\n" + "\n", + FICTION_VERSION, FICTION_REPO); + + std::ostringstream layout_stream{}; + + const qca_cell_clk_lyt layout{{2, 2, 1}, "empty layout"}; + + write_qll_layout(layout, layout_stream); + + CHECK(layout_stream.str() == qll_layout); +} + +TEST_CASE("Write single-layer mQCA AND gate", "[qll]") +{ + static const std::string qll_layout = + fmt::format("\n" + "\n" + "\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\n" + "\n", + FICTION_VERSION, FICTION_REPO); + + std::ostringstream layout_stream{}; + + const auto layout = blueprints::single_layer_qca_and_gate(); + + write_qll_layout(layout, layout_stream); + + CHECK(layout_stream.str() == qll_layout); +} + +TEST_CASE("Write dual-layer mQCA crossover", "[qll]") +{ + static const std::string qll_layout = + fmt::format("\n" + "\n" + "\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\n" + "\n", + FICTION_VERSION, FICTION_REPO); + + std::ostringstream layout_stream{}; + + const auto layout = blueprints::two_layer_qca_wire_crossing(); + + write_qll_layout(layout, layout_stream); + + CHECK(layout_stream.str() == qll_layout); +} diff --git a/test/utils/blueprints/layout_blueprints.hpp b/test/utils/blueprints/layout_blueprints.hpp index 2133991cd..d9e83545f 100644 --- a/test/utils/blueprints/layout_blueprints.hpp +++ b/test/utils/blueprints/layout_blueprints.hpp @@ -299,6 +299,43 @@ CellLyt single_layer_qca_and_gate() noexcept return layout; } +template +CellLyt two_layer_qca_wire_crossing() noexcept +{ + CellLyt layout{{4, 4, 1}, "Crossover"}; + + layout.assign_cell_type({0, 2}, fiction::qca_technology::cell_type::INPUT); + layout.assign_cell_type({2, 0}, fiction::qca_technology::cell_type::INPUT); + + layout.assign_cell_type({2, 1}, fiction::qca_technology::cell_type::NORMAL); + layout.assign_cell_type({2, 2}, fiction::qca_technology::cell_type::NORMAL); + layout.assign_cell_type({2, 3}, fiction::qca_technology::cell_type::NORMAL); + + layout.assign_cell_type({0, 2, 1}, fiction::qca_technology::cell_type::NORMAL); + layout.assign_cell_type({1, 2, 1}, fiction::qca_technology::cell_type::NORMAL); + layout.assign_cell_type({2, 2, 1}, fiction::qca_technology::cell_type::NORMAL); + layout.assign_cell_type({3, 2, 1}, fiction::qca_technology::cell_type::NORMAL); + layout.assign_cell_type({4, 2, 1}, fiction::qca_technology::cell_type::NORMAL); + + layout.assign_cell_mode({0, 2}, fiction::qca_technology::cell_mode::VERTICAL); + layout.assign_cell_mode({0, 2, 1}, fiction::qca_technology::cell_mode::CROSSOVER); + layout.assign_cell_mode({1, 2, 1}, fiction::qca_technology::cell_mode::CROSSOVER); + layout.assign_cell_mode({2, 2, 1}, fiction::qca_technology::cell_mode::CROSSOVER); + layout.assign_cell_mode({3, 2, 1}, fiction::qca_technology::cell_mode::CROSSOVER); + layout.assign_cell_mode({4, 2, 1}, fiction::qca_technology::cell_mode::CROSSOVER); + layout.assign_cell_mode({4, 2}, fiction::qca_technology::cell_mode::VERTICAL); + + layout.assign_cell_type({4, 2}, fiction::qca_technology::cell_type::OUTPUT); + layout.assign_cell_type({2, 4}, fiction::qca_technology::cell_type::OUTPUT); + + layout.assign_cell_name({0, 2}, "a"); + layout.assign_cell_name({2, 0}, "b"); + layout.assign_cell_name({4, 2}, "a'"); + layout.assign_cell_name({2, 4}, "b'"); + + return layout; +} + template CellLyt single_layer_inml_maj_gate() noexcept { @@ -326,6 +363,66 @@ CellLyt single_layer_inml_maj_gate() noexcept return layout; } +template +CellLyt single_layer_inml_coupler_with_inverter() noexcept +{ + CellLyt layout{{11, 4}, "Coupler with inverter"}; + + layout.assign_cell_type({0, 2}, fiction::inml_technology::cell_type::INPUT); + layout.assign_cell_type({1, 2}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({2, 2}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({3, 1}, fiction::inml_technology::cell_type::FANOUT_COUPLER_MAGNET); + layout.assign_cell_type({3, 2}, fiction::inml_technology::cell_type::FANOUT_COUPLER_MAGNET); + layout.assign_cell_type({3, 3}, fiction::inml_technology::cell_type::FANOUT_COUPLER_MAGNET); + layout.assign_cell_type({4, 1}, fiction::inml_technology::cell_type::FANOUT_COUPLER_MAGNET); + layout.assign_cell_type({4, 3}, fiction::inml_technology::cell_type::FANOUT_COUPLER_MAGNET); + layout.assign_cell_type({5, 1}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({6, 1}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({5, 3}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({6, 3}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({7, 1}, fiction::inml_technology::cell_type::INVERTER_MAGNET); + layout.assign_cell_type({8, 1}, fiction::inml_technology::cell_type::INVERTER_MAGNET); + layout.assign_cell_type({9, 1}, fiction::inml_technology::cell_type::INVERTER_MAGNET); + layout.assign_cell_type({10, 1}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({7, 3}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({8, 3}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({9, 3}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({10, 3}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({11, 1}, fiction::inml_technology::cell_type::OUTPUT); + layout.assign_cell_type({11, 3}, fiction::inml_technology::cell_type::OUTPUT); + + layout.assign_cell_name({0, 2}, "a"); + layout.assign_cell_name({11, 1}, "not a"); + layout.assign_cell_name({11, 3}, "a"); + + return layout; +} + +template +CellLyt single_layer_inml_crosswire() noexcept +{ + CellLyt layout{{5, 2}, "Crosswire"}; + + layout.assign_cell_type({0, 0}, fiction::inml_technology::cell_type::INPUT); + layout.assign_cell_type({0, 2}, fiction::inml_technology::cell_type::INPUT); + layout.assign_cell_type({1, 0}, fiction::inml_technology::cell_type::CROSSWIRE_MAGNET); + layout.assign_cell_type({1, 2}, fiction::inml_technology::cell_type::CROSSWIRE_MAGNET); + layout.assign_cell_type({2, 1}, fiction::inml_technology::cell_type::CROSSWIRE_MAGNET); + layout.assign_cell_type({3, 0}, fiction::inml_technology::cell_type::CROSSWIRE_MAGNET); + layout.assign_cell_type({3, 2}, fiction::inml_technology::cell_type::CROSSWIRE_MAGNET); + layout.assign_cell_type({4, 0}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({4, 2}, fiction::inml_technology::cell_type::NORMAL); + layout.assign_cell_type({5, 0}, fiction::inml_technology::cell_type::OUTPUT); + layout.assign_cell_type({5, 2}, fiction::inml_technology::cell_type::OUTPUT); + + layout.assign_cell_name({0, 0}, "a"); + layout.assign_cell_name({0, 2}, "b"); + layout.assign_cell_name({5, 0}, "b'"); + layout.assign_cell_name({5, 2}, "a'"); + + return layout; +} + } // namespace blueprints #endif // FICTION_LAYOUT_BLUEPRINTS_HPP