/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf * * 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 "kernel/register.h" #include "kernel/celltypes.h" #include "kernel/sigtools.h" #include "kernel/rtlil.h" #include "kernel/log.h" #include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct SpliceWorker { RTLIL::Design *design; RTLIL::Module *module; bool sel_by_cell; bool sel_by_wire; bool sel_any_bit; bool no_outputs; bool do_wires; std::set ports; std::set no_ports; CellTypes ct; SigMap sigmap; std::vector driven_bits; std::map driven_bits_map; std::set driven_chunks; std::map spliced_signals_cache; std::map sliced_signals_cache; SpliceWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module), ct(design), sigmap(module) { } RTLIL::SigSpec get_sliced_signal(RTLIL::SigSpec sig) { if (sig.size() == 0 || sig.is_fully_const()) return sig; if (sliced_signals_cache.count(sig)) return sliced_signals_cache.at(sig); int offset = 0; int p = driven_bits_map.at(sig.extract(0, 1).as_bit()) - 1; while (driven_bits.at(p) != RTLIL::State::Sm) p--, offset++; RTLIL::SigSpec sig_a; for (p++; driven_bits.at(p) != RTLIL::State::Sm; p++) sig_a.append(driven_bits.at(p)); RTLIL::SigSpec new_sig = sig; if (sig_a.size() != sig.size()) { RTLIL::Cell *cell = module->addCell(NEW_ID, ID($slice)); cell->parameters[ID::OFFSET] = offset; cell->parameters[ID::A_WIDTH] = sig_a.size(); cell->parameters[ID::Y_WIDTH] = sig.size(); cell->setPort(ID::A, sig_a); cell->setPort(ID::Y, module->addWire(NEW_ID, sig.size())); new_sig = cell->getPort(ID::Y); } sliced_signals_cache[sig] = new_sig; return new_sig; } RTLIL::SigSpec get_spliced_signal(RTLIL::SigSpec sig) { if (sig.size() == 0 || sig.is_fully_const()) return sig; if (spliced_signals_cache.count(sig)) return spliced_signals_cache.at(sig); int last_bit = -1; std::vector chunks; for (auto &bit : sig.to_sigbit_vector()) { if (bit.wire == nullptr) { if (last_bit == 0) chunks.back().append(bit); else chunks.push_back(bit); last_bit = 0; continue; } if (driven_bits_map.count(bit)) { int this_bit = driven_bits_map.at(bit); if (last_bit+1 == this_bit) chunks.back().append(bit); else chunks.push_back(bit); last_bit = this_bit; continue; } log(" Failed to generate spliced signal %s.\n", log_signal(sig)); spliced_signals_cache[sig] = sig; return sig; } RTLIL::SigSpec new_sig = get_sliced_signal(chunks.front()); for (size_t i = 1; i < chunks.size(); i++) { RTLIL::SigSpec sig2 = get_sliced_signal(chunks[i]); RTLIL::Cell *cell = module->addCell(NEW_ID, ID($concat)); cell->parameters[ID::A_WIDTH] = new_sig.size(); cell->parameters[ID::B_WIDTH] = sig2.size(); cell->setPort(ID::A, new_sig); cell->setPort(ID::B, sig2); cell->setPort(ID::Y, module->addWire(NEW_ID, new_sig.size() + sig2.size())); new_sig = cell->getPort(ID::Y); } spliced_signals_cache[sig] = new_sig; log(" Created spliced signal: %s -> %s\n", log_signal(sig), log_signal(new_sig)); return new_sig; } void run() { log("Splicing signals in module %s:\n", log_id(module->name)); driven_bits.push_back(RTLIL::State::Sm); driven_bits.push_back(RTLIL::State::Sm); for (auto wire : module->wires()) if (wire->port_input) { RTLIL::SigSpec sig = sigmap(wire); driven_chunks.insert(sig); for (auto &bit : sig.to_sigbit_vector()) driven_bits.push_back(bit); driven_bits.push_back(RTLIL::State::Sm); } for (auto cell : module->cells()) for (auto &conn : cell->connections()) if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first)) { RTLIL::SigSpec sig = sigmap(conn.second); driven_chunks.insert(sig); for (auto &bit : sig.to_sigbit_vector()) driven_bits.push_back(bit); driven_bits.push_back(RTLIL::State::Sm); } driven_bits.push_back(RTLIL::State::Sm); for (size_t i = 0; i < driven_bits.size(); i++) driven_bits_map[driven_bits[i]] = i; SigPool selected_bits; if (!sel_by_cell) for (auto wire : module->selected_wires()) selected_bits.add(sigmap(wire)); std::vector mod_cells = module->cells(); for (auto cell : mod_cells) { if (!sel_by_wire && !design->selected(module, cell)) continue; for (auto &conn : cell->connections_) if (ct.cell_input(cell->type, conn.first)) { if (ports.size() > 0 && !ports.count(conn.first)) continue; if (no_ports.size() > 0 && no_ports.count(conn.first)) continue; RTLIL::SigSpec sig = sigmap(conn.second); if (!sel_by_cell) { if (!sel_any_bit && !selected_bits.check_all(sig)) continue; if (sel_any_bit && !selected_bits.check_any(sig)) continue; } if (driven_chunks.count(sig) > 0) continue; conn.second = get_spliced_signal(sig); } } std::vector> rework_wires; std::vector mod_wires = module->wires(); for (auto wire : mod_wires) if ((!no_outputs && wire->port_output) || (do_wires && wire->name[0] == '\\')) { if (!design->selected(module, wire)) continue; RTLIL::SigSpec sig = sigmap(wire); if (driven_chunks.count(sig) > 0) continue; RTLIL::SigSpec new_sig = get_spliced_signal(sig); if (new_sig != sig) rework_wires.push_back(std::pair(wire, new_sig)); } else if (!wire->port_input) { RTLIL::SigSpec sig = sigmap(wire); if (spliced_signals_cache.count(sig) && spliced_signals_cache.at(sig) != sig) rework_wires.push_back(std::pair(wire, spliced_signals_cache.at(sig))); else if (sliced_signals_cache.count(sig) && sliced_signals_cache.at(sig) != sig) rework_wires.push_back(std::pair(wire, sliced_signals_cache.at(sig))); } for (auto &it : rework_wires) { RTLIL::IdString orig_name = it.first->name; module->rename(it.first, NEW_ID); RTLIL::Wire *new_port = module->addWire(orig_name, it.first); it.first->port_id = 0; it.first->port_input = false; it.first->port_output = false; module->connect(RTLIL::SigSig(new_port, it.second)); } } }; struct SplicePass : public Pass { SplicePass() : Pass("splice", "create explicit splicing cells") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" splice [options] [selection]\n"); log("\n"); log("This command adds $slice and $concat cells to the design to make the splicing\n"); log("of multi-bit signals explicit. This for example is useful for coarse grain\n"); log("synthesis, where dedicated hardware is needed to splice signals.\n"); log("\n"); log(" -sel_by_cell\n"); log(" only select the cell ports to rewire by the cell. if the selection\n"); log(" contains a cell, than all cell inputs are rewired, if necessary.\n"); log("\n"); log(" -sel_by_wire\n"); log(" only select the cell ports to rewire by the wire. if the selection\n"); log(" contains a wire, than all cell ports driven by this wire are wired,\n"); log(" if necessary.\n"); log("\n"); log(" -sel_any_bit\n"); log(" it is sufficient if the driver of any bit of a cell port is selected.\n"); log(" by default all bits must be selected.\n"); log("\n"); log(" -wires\n"); log(" also add $slice and $concat cells to drive otherwise unused wires.\n"); log("\n"); log(" -no_outputs\n"); log(" do not rewire selected module outputs.\n"); log("\n"); log(" -port \n"); log(" only rewire cell ports with the specified name. can be used multiple\n"); log(" times. implies -no_output.\n"); log("\n"); log(" -no_port \n"); log(" do not rewire cell ports with the specified name. can be used multiple\n"); log(" times. can not be combined with -port .\n"); log("\n"); log("By default selected output wires and all cell ports of selected cells driven\n"); log("by selected wires are rewired.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { bool sel_by_cell = false; bool sel_by_wire = false; bool sel_any_bit = false; bool no_outputs = false; bool do_wires = false; std::set ports, no_ports; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-sel_by_cell") { sel_by_cell = true; continue; } if (args[argidx] == "-sel_by_wire") { sel_by_wire = true; continue; } if (args[argidx] == "-sel_any_bit") { sel_any_bit = true; continue; } if (args[argidx] == "-wires") { do_wires = true; continue; } if (args[argidx] == "-no_outputs") { no_outputs
#
# Copyright (C) 2006-2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

LEDS_MENU:=LED modules

define KernelPackage/leds-gpio
  SUBMENU:=$(LEDS_MENU)
  TITLE:=GPIO LED support
  DEPENDS:= @GPIO_SUPPORT
  KCONFIG:=CONFIG_LEDS_GPIO
  FILES:=$(LINUX_DIR)/drivers/leds/leds-gpio.ko
  AUTOLOAD:=$(call AutoLoad,60,leds-gpio,1)
endef

define KernelPackage/leds-gpio/description
 Kernel module for LEDs on GPIO lines
endef

$(eval $(call KernelPackage,leds-gpio))


define KernelPackage/ledtrig-heartbeat
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED Heartbeat Trigger
  KCONFIG:=CONFIG_LEDS_TRIGGER_HEARTBEAT
  FILES:=$(LINUX_DIR)/drivers/leds/$(if $(call kernel_patchver_ge,3.10),trigger/)ledtrig-heartbeat.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-heartbeat)
endef

define KernelPackage/ledtrig-gpio/description
 Kernel module that allows LEDs to blink like heart beat
endef

$(eval $(call KernelPackage,ledtrig-heartbeat))


define KernelPackage/ledtrig-gpio
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED GPIO Trigger
  KCONFIG:=CONFIG_LEDS_TRIGGER_GPIO
  FILES:=$(LINUX_DIR)/drivers/leds/$(if $(call kernel_patchver_ge,3.10),trigger/)ledtrig-gpio.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-gpio)
endef

define KernelPackage/ledtrig-gpio/description
 Kernel module that allows LEDs to be controlled by gpio events
endef

$(eval $(call KernelPackage,ledtrig-gpio))


define KernelPackage/ledtrig-morse
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED Morse Trigger
  KCONFIG:=CONFIG_LEDS_TRIGGER_MORSE
  FILES:=$(LINUX_DIR)/drivers/leds/ledtrig-morse.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-morse)
endef

define KernelPackage/ledtrig-morse/description
 Kernel module to show morse coded messages on LEDs
endef

$(eval $(call KernelPackage,ledtrig-morse))


define KernelPackage/ledtrig-netdev
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED NETDEV Trigger
  KCONFIG:=CONFIG_LEDS_TRIGGER_NETDEV
  FILES:=$(LINUX_DIR)/drivers/leds/ledtrig-netdev.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-netdev)
endef

define KernelPackage/ledtrig-netdev/description
 Kernel module to drive LEDs based on network activity
endef

$(eval $(call KernelPackage,ledtrig-netdev))


define KernelPackage/ledtrig-netfilter
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED NetFilter Trigger
  DEPENDS:=kmod-ipt-core
  KCONFIG:=CONFIG_NETFILTER_XT_TARGET_LED
  FILES:=$(LINUX_DIR)/net/netfilter/xt_LED.ko
  AUTOLOAD:=$(call AutoLoad,50,xt_LED)
endef

define KernelPackage/ledtrig-netfilter/description
 Kernel module to flash LED when a particular packets passing through your machine.

 For example to create an LED trigger for incoming SSH traffic:
    iptables -A INPUT -p tcp --dport 22 -j LED --led-trigger-id ssh --led-delay 1000
 Then attach the new trigger to an LED on your system:
    echo netfilter-ssh > /sys/class/leds/<ledname>/trigger
endef

$(eval $(call KernelPackage,ledtrig-netfilter))


define KernelPackage/ledtrig-usbdev
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED USB device Trigger
  DEPENDS:=@USB_SUPPORT kmod-usb-core
  KCONFIG:=CONFIG_LEDS_TRIGGER_USBDEV
  FILES:=$(LINUX_DIR)/drivers/leds/ledtrig-usbdev.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-usbdev)
endef

define KernelPackage/ledtrig-usbdev/description
 Kernel module to drive LEDs based on USB device presence/activity
endef

$(eval $(call KernelPackage,ledtrig-usbdev))


define KernelPackage/ledtrig-default-on
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED Default ON Trigger
  KCONFIG:=CONFIG_LEDS_TRIGGER_DEFAULT_ON
  FILES:=$(LINUX_DIR)/drivers/leds/$(if $(call kernel_patchver_ge,3.10),trigger/)ledtrig-default-on.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-default-on,1)
endef

define KernelPackage/ledtrig-default-on/description
 Kernel module that allows LEDs to be initialised in the ON state
endef

$(eval $(call KernelPackage,ledtrig-default-on))


define KernelPackage/ledtrig-timer
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED Timer Trigger
  KCONFIG:=CONFIG_LEDS_TRIGGER_TIMER
  FILES:=$(LINUX_DIR)/drivers/leds/$(if $(call kernel_patchver_ge,3.10),trigger/)ledtrig-timer.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-timer,1)
endef

define KernelPackage/ledtrig-timer/description
 Kernel module that allows LEDs to be controlled by a programmable timer
 via sysfs
endef

$(eval $(call KernelPackage,ledtrig-timer))


define KernelPackage/ledtrig-oneshot
  SUBMENU:=$(LEDS_MENU)
  TITLE:=LED One-Shot Trigger
  DEPENDS:=@!LINUX_3_3
  KCONFIG:=CONFIG_LEDS_TRIGGER_ONESHOT
  FILES:=$(LINUX_DIR)/drivers/leds/$(if $(call kernel_patchver_ge,3.10),trigger/)ledtrig-oneshot.ko
  AUTOLOAD:=$(call AutoLoad,50,ledtrig-oneshot)
endef

define KernelPackage/ledtrig-oneshot/description
 Kernel module that allows LEDs to be triggered by sporadic events in
 one-shot pulses
endef

$(eval $(call KernelPackage,ledtrig-oneshot))


define KernelPackage/leds-tlc59116
  SUBMENU:=$(LEDS_MENU)
  TITLE:=TLC59116 LED support
  DEPENDS:=@TARGET_mvebu kmod-i2c-core
  KCONFIG:=CONFIG_LEDS_TLC59116
  FILES:=$(LINUX_DIR)/drivers/leds/leds-tlc59116.ko
  AUTOLOAD:=$(call AutoLoad,60,leds-tlc59116,1)
endef

define KernelPackage/leds-tlc59116/description
 Kernel module for LEDs on TLC59116
endef

$(eval $(call KernelPackage,leds-tlc59116))