/* ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /** * @file hal_can.c * @brief CAN Driver code. * * @addtogroup CAN * @{ */ #include "hal.h" #if (HAL_USE_CAN == TRUE) || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver local variables and types. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ /** * @brief CAN Driver initialization. * @note This function is implicitly invoked by @p halInit(), there is * no need to explicitly initialize the driver. * * @init */ void canInit(void) { can_lld_init(); } /** * @brief Initializes the standard part of a @p CANDriver structure. * * @param[out] canp pointer to the @p CANDriver object * * @init */ void canObjectInit(CANDriver *canp) { canp->state = CAN_STOP; canp->config = NULL; osalThreadQueueObjectInit(&canp->txqueue); osalThreadQueueObjectInit(&canp->rxqueue); #if !defined(CAN_ENFORCE_USE_CALLBACKS) osalEventObjectInit(&canp->rxfull_event); osalEventObjectInit(&canp->txempty_event); osalEventObjectInit(&canp->error_event); #if CAN_USE_SLEEP_MODE == TRUE osalEventObjectInit(&canp->sleep_event); osalEventObjectInit(&canp->wakeup_event); #endif #else /* defined(CAN_ENFORCE_USE_CALLBACKS) */ canp->rxfull_cb = NULL; canp->txempty_cb = NULL; canp->error_cb = NULL; #if CAN_USE_SLEEP_MODE == TRUE canp->wakeup_cb = NULL; #endif #endif /* defined(CAN_ENFORCE_USE_CALLBACKS) */ } /** * @brief Configures and activates the CAN peripheral. * @note Activating the CAN bus can be a slow operation. * @note Unlike other drivers it is not possible to restart the CAN * driver without first stopping it using canStop(). * * @param[in] canp pointer to the @p CANDriver object * @param[in] config pointer to the @p CANConfig object. Depending on * the implementation the value can be @p NULL. * * @api */ void canStart(CANDriver *canp, const CANConfig *config) { osalDbgCheck(canp != NULL); osalSysLock(); osalDbgAssert(canp->state == CAN_STOP, "invalid state"); /* Entering initialization mode. */ canp->state = CAN_STARTING; canp->config = config; /* Low level initialization, could be a slow process and sleeps could be performed inside.*/ can_lld_start(canp); /* The driver finally goes into the ready state.*/ canp->state = CAN_READY; osalSysUnlock(); } /** * @brief Deactivates the CAN peripheral. * * @param[in] canp pointer to the @p CANDriver object * * @api */ void canStop(CANDriver *canp) { osalDbgCheck(canp != NULL); osalSysLock(); osalDbgAssert((canp->state == CAN_STOP) || (canp->state == CAN_READY), "invalid state"); /* The low level driver is stopped.*/ can_lld_stop(canp); canp->config = NULL; canp->state = CAN_STOP; /* Threads waiting on CAN APIs are notified that the driver has been stopped in order to not have stuck threads.*/ osalThreadDequeueAllI(&canp->rxqueue, MSG_RESET); osalThreadDequeueAllI(&canp->txqueue, MSG_RESET); osalOsRescheduleS(); osalSysUnlock(); } /** * @brief Can frame transmission attempt. * @details The specified frame is queued for transmission, if the hardware * queue is full then the function fails. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * @param[in] ctfp pointer to the CAN frame to be transmitted * @return The operation result. * @retval false Frame transmitted. * @retval true Mailbox full. * * @iclass */ bool canTryTransmitI(CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp) { osalDbgCheckClassI(); osalDbgCheck((canp != NULL) && (ctfp != NULL) && (mailbox <= (canmbx_t)CAN_TX_MAILBOXES)); osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), "invalid state"); /* If the RX mailbox is full then the function fails.*/ if (!can_lld_is_tx_empty(canp, mailbox)) { return true; } /* Transmitting frame.*/ can_lld_transmit(canp, mailbox, ctfp); return false; } /** * @brief Can frame receive attempt. * @details The function tries to fetch a frame from a mailbox. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * @param[out] crfp pointer to the buffer where the CAN frame is copied * @return The operation result. * @retval false Frame fetched. * @retval true Mailbox empty. * * @iclass */ bool canTryReceiveI(CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp) { osalDbgCheckClassI(); osalDbgCheck((canp != NULL) && (crfp != NULL) && (mailbox <= (canmbx_t)CAN_RX_MAILBOXES)); osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), "invalid state"); /* If the RX mailbox is empty then the function fails.*/ if (!can_lld_is_rx_nonempty(canp, mailbox)) { return true; } /* Fetching the frame.*/ can_lld_receive(canp, mailbox, crfp); return false; } /** * @brief Can frame transmission. * @details The specified frame is queued for transmission, if the hardware * queue is full then the invoking thread is queued. * @note Trying to transmit while in sleep mode simply enqueues the thread. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * @param[in] ctfp pointer to the CAN frame
/*
* 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.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct DeminoutPass : public Pass {
DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { }
void help() YS_OVERRIDE
{
log("\n");
log(" deminout [options] [selection]\n");
log("\n");
log("\"Demote\" inout ports to input or output ports, if possible.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-bits") {
// flag_bits = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
bool keep_running = true;
while (keep_running)
{
keep_running = false;
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
pool<SigBit> bits_written, bits_used, bits_inout, bits_tribuf;
dict<SigBit, int> bits_numports;
for (auto wire : module->wires())
if (wire->port_id)
for (auto bit : sigmap(wire))
bits_numports[bit]++;
for (auto cell : module->cells())
for (auto &conn : cell->connections())
{
bool cellport_out = cell->output(conn.first) || !cell->known();
bool cellport_in = cell->input(conn.first) || !cell->known();
if (cellport_out && cellport_in)
for (auto bit : sigmap(conn.second))
bits_inout.insert(bit);
if (cellport_out)
for (auto bit : sigmap(conn.second))
bits_written.insert(bit);
if (cellport_in)
for (auto bit : sigmap(conn.second))
bits_used.insert(bit);
if (conn.first == ID::Y && cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_TBUF_), ID($tribuf)))
{
bool tribuf = cell->type.in(ID($_TBUF_), ID($tribuf));
if (!tribuf) {
for (auto &c : cell->connections()) {
if (!c.first.in(ID::A, ID::B))
continue;
for (auto b : sigmap(c.second))
if (b == State::Sz)
tribuf = true;
}
}
if (tribuf)
for (auto bit : sigmap(conn.second))
bits_tribuf.insert(bit);
}
}
for (auto wire : module->selected_wires())
if (wire->port_input && wire->port_output)
{
bool new_input = false;
bool new_output = false;
for (auto bit : sigmap(wire))
{
if (bits_numports[bit] > 1 || bits_inout.count(bit))
new_input = true, new_output = true;
if (!bit.wire)
new_output = true;
if (bits_written.count(bit)) {
new_output = true;
if (bits_tribuf.count(bit))
goto tribuf_bit;
} else {
tribuf_bit:
new_input = true;
}
}
if (new_input != new_output) {
log("Demoting inout port %s.%s to %s.\n", log_id(module), log_id(wire), new_input ? "input" : "output");
wire->port_input = new_input;
wire->port_output = new_output;
keep_running = true;
}
}
}
}
}
} DeminoutPass;
PRIVATE_NAMESPACE_END