diff --git a/machxo2/CMakeLists.txt b/machxo2/CMakeLists.txt index 5060c432..294e6c99 100644 --- a/machxo2/CMakeLists.txt +++ b/machxo2/CMakeLists.txt @@ -22,6 +22,8 @@ set(SOURCES globals.cc lpf.cc pack.cc + pio.cc + pio.h ) add_nextpnr_architecture(${family} diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 52a20cb5..329596c4 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -29,6 +29,7 @@ #include "config.h" #include "log.h" #include "util.h" +#include "pio.h" #define fmt_str(x) (static_cast(std::ostringstream() << x).str()) @@ -420,9 +421,45 @@ struct MachXO2Bitgen BelId bel = ci->bel; std::string pio = ctx->tile_info(bel)->bel_data[bel.index].name.get(); std::string iotype = str_or_default(ci->attrs, id_IO_TYPE, "LVCMOS33"); + IOType io_type = ioType_from_str(iotype); std::string dir = str_or_default(ci->params, id_DIR, "INPUT"); std::string pic_tile = get_pic_tile(bel); cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); + bool is_opendrain = false; + + if (ci->attrs.count(id_OPENDRAIN)) { + if (opendrain_capable(io_type, dir)) { + cc.tiles[pic_tile].add_enum(pio + ".OPENDRAIN", str_or_default(ci->attrs, id_OPENDRAIN, "OFF")); + is_opendrain = true; + } + else + log_error("IO of type %s and direction %s cannot be set to opendrain\n", iotype.c_str(), dir.c_str()); + } + + if (ci->attrs.count(id_SLEWRATE) && !is_differential(io_type) && dir != "INPUT") + cc.tiles[pic_tile].add_enum(pio + ".SLEWRATE", str_or_default(ci->attrs, id_SLEWRATE, "SLOW")); + if (ci->attrs.count(id_DIFFRESISTOR)) + cc.tiles[pic_tile].add_enum(pio + ".DIFFRESISTOR", str_or_default(ci->attrs, id_DIFFRESISTOR, "OFF")); + + if (!is_opendrain) { + if (ci->attrs.count(id_CLAMP)) + cc.tiles[pic_tile].add_enum(pio + ".CLAMP", str_or_default(ci->attrs, id_CLAMP, "OFF")); + if (ci->attrs.count(id_PULLMODE) || dir == "INPUT") + cc.tiles[pic_tile].add_enum(pio + ".PULLMODE", str_or_default(ci->attrs, id_PULLMODE, is_lvcmos(io_type) ? "DOWN" : "NONE")); + } + + if (ci->attrs.count(id_DRIVE) && !is_differential(io_type) && dir != "INPUT") { + std::string drive = str_or_default(ci->attrs, id_DRIVE, "8"); + if (is_drive_ok(io_type, drive)) + cc.tiles[pic_tile].add_enum(pio + ".DRIVE", drive); + else + log_error("DRIVE %s cannot be set for IO type %s\n", drive.c_str(), iotype.c_str()); + } + + if ((dir == "INPUT" || dir == "BIDIR") && !is_differential(ioType_from_str(iotype)) && + !is_referenced(ioType_from_str(iotype)) && ci->attrs.count(id_HYSTERESIS)) { + cc.tiles[pic_tile].add_enum(pio + ".HYSTERESIS", str_or_default(ci->attrs, id_HYSTERESIS, "SMALL")); + } } void write_dcc(CellInfo *ci) diff --git a/machxo2/constids.inc b/machxo2/constids.inc index 6f074d90..78141079 100644 --- a/machxo2/constids.inc +++ b/machxo2/constids.inc @@ -24,6 +24,13 @@ X(PADDI) X(PADDO) X(PADDT) +X(CLAMP) +X(DIFFRESISTOR) +X(DRIVE) +X(HYSTERESIS) +X(OPENDRAIN) +X(PULLMODE) + X(TRELLIS_SLICE) X(A0) X(B0) diff --git a/machxo2/iotypes.inc b/machxo2/iotypes.inc new file mode 100644 index 00000000..2551ef7b --- /dev/null +++ b/machxo2/iotypes.inc @@ -0,0 +1,41 @@ +X(LVTTL33) +X(LVCMOS33) +X(LVCMOS25) +X(LVCMOS18) +X(LVCMOS15) +X(LVCMOS12) + +X(SSTL25_I) +X(SSTL25_II) +X(SSTL18_I) +X(SSTL18_II) +X(HSTL18_I) +X(HSTL18_II) + +X(PCI33) + +X(SSTL18D_I) +X(SSTL18D_II) +X(HSTL18D_I) +X(HSTL18D_II) +X(SSTL25D_I) +X(SSTL25D_II) +X(LVTTL33D) +X(LVCMOS33D) +X(LVCMOS25D) +X(LVCMOS15D) +X(LVCMOS12D) +X(MIPI) + +X(LVDS) +X(BLVDS25) +X(MLVDS25) +X(LVPECL33) +X(RSDS25) +X(LVCMOS18D) + +X(LVDS25E) +X(BLVDS25E) +X(MLVDS25E) +X(LVPECL33E) + diff --git a/machxo2/pio.cc b/machxo2/pio.cc new file mode 100644 index 00000000..e0eae193 --- /dev/null +++ b/machxo2/pio.cc @@ -0,0 +1,216 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 gatecat + * + * 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. + * + */ + +#include "pio.h" + +NEXTPNR_NAMESPACE_BEGIN + +std::string iovoltage_to_str(IOVoltage v) +{ + switch (v) { + case IOVoltage::VCC_3V3: + return "3V3"; + case IOVoltage::VCC_2V5: + return "2V5"; + case IOVoltage::VCC_1V8: + return "1V8"; + case IOVoltage::VCC_1V5: + return "1V5"; + case IOVoltage::VCC_1V2: + return "1V2"; + } + NPNR_ASSERT_FALSE("unknown IO voltage"); +} + +IOVoltage iovoltage_from_str(const std::string &name) +{ + if (name == "3V3") + return IOVoltage::VCC_3V3; + if (name == "2V5") + return IOVoltage::VCC_2V5; + if (name == "1V8") + return IOVoltage::VCC_1V8; + if (name == "1V5") + return IOVoltage::VCC_1V5; + if (name == "1V2") + return IOVoltage::VCC_1V2; + NPNR_ASSERT_FALSE("unknown IO voltage"); +} + +std::string iotype_to_str(IOType type) +{ + if (type == IOType::TYPE_NONE) + return "NONE"; +#define X(t) \ + if (type == IOType::t) \ + return #t; +#include "iotypes.inc" +#undef X + if (type == IOType::TYPE_UNKNOWN) + return ""; + NPNR_ASSERT_FALSE("unknown IO type"); +} + +IOType ioType_from_str(const std::string &name) +{ + if (name == "NONE") + return IOType::TYPE_NONE; +#define X(t) \ + if (name == #t) \ + return IOType::t; +#include "iotypes.inc" + return IOType::TYPE_UNKNOWN; +} + +IOVoltage get_vccio(IOType type) +{ + switch (type) { + case IOType::LVTTL33: + case IOType::LVCMOS33: + case IOType::LVCMOS33D: + case IOType::LVPECL33: + case IOType::LVPECL33E: + case IOType::PCI33: + return IOVoltage::VCC_3V3; + case IOType::LVCMOS25: + case IOType::LVCMOS25D: + case IOType::LVDS: + case IOType::RSDS25: + case IOType::LVDS25E: + case IOType::MLVDS25: + case IOType::MLVDS25E: + case IOType::BLVDS25: + case IOType::SSTL25_I: + case IOType::SSTL25_II: + case IOType::SSTL25D_I: + case IOType::SSTL25D_II: + return IOVoltage::VCC_2V5; + case IOType::LVCMOS18: + case IOType::LVCMOS18D: + case IOType::SSTL18_I: + case IOType::SSTL18_II: + case IOType::HSTL18_I: + case IOType::HSTL18_II: + case IOType::SSTL18D_I: + case IOType::SSTL18D_II: + case IOType::HSTL18D_I: + case IOType::HSTL18D_II: + return IOVoltage::VCC_1V8; + case IOType::LVCMOS15: + case IOType::LVCMOS15D: + return IOVoltage::VCC_1V5; + case IOType::LVCMOS12: + case IOType::LVCMOS12D: + case IOType::MIPI: + return IOVoltage::VCC_1V2; + default: + NPNR_ASSERT_FALSE("unknown IO type, unable to determine VccIO"); + } +} + +bool is_differential(IOType type) +{ + switch (type) { + case IOType::LVCMOS33D: + case IOType::LVCMOS25D: + case IOType::LVCMOS15D: + case IOType::LVCMOS12D: + case IOType::LVPECL33: + case IOType::LVDS: + case IOType::MLVDS25: + case IOType::BLVDS25: + case IOType::LVCMOS18D: + case IOType::SSTL18D_I: + case IOType::SSTL18D_II: + case IOType::SSTL25D_I: + case IOType::SSTL25D_II: + case IOType::HSTL18D_I: + case IOType::HSTL18D_II: + case IOType::MIPI: + case IOType::RSDS25: + return true; + default: + return false; + } +} + +bool is_referenced(IOType type) +{ + switch (type) { + case IOType::SSTL18_I: + case IOType::SSTL18_II: + case IOType::SSTL18D_I: + case IOType::SSTL18D_II: + case IOType::SSTL25_I: + case IOType::SSTL25_II: + case IOType::SSTL25D_I: + case IOType::SSTL25D_II: + case IOType::HSTL18_I: + case IOType::HSTL18_II: + case IOType::HSTL18D_I: + case IOType::HSTL18D_II: + return true; + default: + return false; + } +} + +bool is_lvcmos(IOType type) +{ + switch (type) { + case IOType::LVTTL33: + case IOType::LVCMOS33: + case IOType::LVCMOS25: + case IOType::LVCMOS18: + case IOType::LVCMOS15: + case IOType::LVCMOS12: + return true; + default: + return false; + } +} + +bool is_drive_ok(IOType type, std::string d) +{ + switch (type) { + case IOType::LVTTL33: + case IOType::LVCMOS33: + return (d == "4" || d == "8" || d == "12" || d == "16" || d == "24"); + case IOType::LVCMOS25: + return (d == "4" || d == "8" || d == "12" || d == "16"); + case IOType::LVCMOS18: + return (d == "4" || d == "8" || d == "12"); + case IOType::LVCMOS15: + return (d == "4" || d == "8"); + case IOType::LVCMOS12: + return (d == "2" || d == "6"); + default: + return false; + } +} + +bool opendrain_capable(IOType type, std::string dir) +{ + if (dir != "OUTPUT" && dir != "BIDIR") + return false; + + return is_lvcmos(type); +} + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/pio.h b/machxo2/pio.h new file mode 100644 index 00000000..a5269d8a --- /dev/null +++ b/machxo2/pio.h @@ -0,0 +1,60 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 gatecat + * + * 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 IO_H +#define IO_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +enum class IOVoltage +{ + VCC_3V3, + VCC_2V5, + VCC_1V8, + VCC_1V5, + VCC_1V2 +}; + +std::string iovoltage_to_str(IOVoltage v); +IOVoltage iovoltage_from_str(const std::string &name); + +enum class IOType +{ + TYPE_NONE, +#define X(t) t, +#include "iotypes.inc" +#undef X + TYPE_UNKNOWN, +}; + +std::string iotype_to_str(IOType type); +IOType ioType_from_str(const std::string &name); + +// IO related functions +bool is_differential(IOType type); +bool is_referenced(IOType type); +bool is_lvcmos(IOType type); +bool is_drive_ok(IOType type, std::string d); +bool opendrain_capable(IOType type, std::string dir); + +NEXTPNR_NAMESPACE_END + +#endif