/* 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_pal.h * @brief I/O Ports Abstraction Layer macros, types and structures. * * @addtogroup PAL * @{ */ #ifndef HAL_PAL_H #define HAL_PAL_H #if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver constants. */ /*===========================================================================*/ /** * @name Pads mode constants * @{ */ /** * @brief After reset state. * @details The state itself is not specified and is architecture dependent, * it is guaranteed to be equal to the after-reset state. It is * usually an input state. */ #define PAL_MODE_RESET 0U /** * @brief Safe state for unconnected pads. * @details The state itself is not specified and is architecture dependent, * it may be mapped on @p PAL_MODE_INPUT_PULLUP, * @p PAL_MODE_INPUT_PULLDOWN or @p PAL_MODE_OUTPUT_PUSHPULL for * example. */ #define PAL_MODE_UNCONNECTED 1U /** * @brief Regular input high-Z pad. */ #define PAL_MODE_INPUT 2U /** * @brief Input pad with weak pull up resistor. */ #define PAL_MODE_INPUT_PULLUP 3U /** * @brief Input pad with weak pull down resistor. */ #define PAL_MODE_INPUT_PULLDOWN 4U /** * @brief Analog input mode. */ #define PAL_MODE_INPUT_ANALOG 5U /** * @brief Push-pull output pad. */ #define PAL_MODE_OUTPUT_PUSHPULL 6U /** * @brief Open-drain output pad. */ #define PAL_MODE_OUTPUT_OPENDRAIN 7U /** @} */ /** * @name Logic level constants * @{ */ /** * @brief Logical low state. */ #define PAL_LOW 0U /** * @brief Logical high state. */ #define PAL_HIGH 1U /** @} */ /** * @name PAL event modes * @{ */ #define PAL_EVENT_MODE_EDGES_MASK 3U /**< @brief Mask of edges field. */ #define PAL_EVENT_MODE_DISABLED 0U /**< @brief Channel disabled. */ #define PAL_EVENT_MODE_RISING_EDGE 1U /**< @brief Rising edge callback. */ #define PAL_EVENT_MODE_FALLING_EDGE 2U /**< @brief Falling edge callback. */ #define PAL_EVENT_MODE_BOTH_EDGES 3U /**< @brief Both edges callback. */ /** @} */ /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ /** * @name PAL configuration options * @{ */ /** * @brief Enables synchronous APIs. * @note Disabling this option saves both code and data space. */ #if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__) #define PAL_USE_CALLBACKS TRUE #endif /** * @brief Enables synchronous APIs. * @note Disabling this option saves both code and data space. */ #if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__) #define PAL_USE_WAIT TRUE #endif /** @} */ /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ /** * @brief Type of a PAL event callback. */ typedef void (*palcallback_t)(void *arg); /** * @brief Type of a PAL event record. */ typedef struct { #if (PAL_USE_WAIT == TRUE) || defined(__DOXYGEN__) /** * @brief Threads queued for an event. */ threads_queue_t threads; #endif #if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) /** * @brief Event callback. */ palcallback_t cb; /** * @brief Event callback argument. */ void *arg; #endif } palevent_t; #include "hal_pal_lld.h" /** * @brief I/O bus descriptor. * @details This structure describes a group of contiguous digital I/O lines * that have to be handled as bus. * @note I/O operations on a bus do not affect I/O lines on the same port but * not belonging to the bus. */ typedef struct { /** * @brief Port identifier. */ ioportid_t portid; /** * @brief Bus mask aligned to port bit 0. * @note The bus mask implicitly define the bus width. A logic AND is * performed on the bus data. */ ioportmask_t mask; /** * @brief Offset, within the port, of the least significant bit of the bus. */ uint_fast8_t offset; } IOBus; /*===========================================================================*/ /* Driver macros. */ /*===========================================================================*/ /** * @brief Port bit helper macro. * @details This macro calculates the mask of a bit within a port. * * @param[in] n bit position within the port * @return The bit mask. */ #if !defined(PAL_PORT_BIT) || defined(__DOXYGEN__) #define PAL_PORT_BIT(n) ((ioportmask_t)(1U << (n))) #endif /** * @brief Bits group mask helper. * @details This macro calculates the mask of a bits group. * * @param[in] width group width * @return The group mask. */ #if !defined(PAL_GROUP_MASK) || defined(__DOXYGEN__) #define PAL_GROUP_MASK(width) ((ioportmask_t)(1U << (width)) - 1U) #endif /** * @brief Data part of a static I/O bus initializer. * @details This macro should be used when statically initializing an I/O bus * that is part of a bigger structure. * * @param[in] name name of the IOBus variable * @param[in] port I/O port descriptor * @param[in] width bus width in bits * @param[in] offset bus bit offset within the port */ #define _IOBUS_DATA(name, port, width, offset) \ {port, PAL_GROUP_MASK(width), offset} /** * @brief Static I/O bus initializer. * * @param[in] name name of the IOBus variable * @param[in] port I/O port descriptor * @param[in] width bus width in bits * @param[in] offset bus bit offset within the port */ #define IOBUS_DECL(name, port, width, offset) \ IOBus name = _IOBUS_DATA(name, port, width, offset) #if (PAL_USE_CALLBACKS == TRUE) || (PAL_USE_WAIT == TRUE) || \ defined(__DOXYGEN__) /** * @name Low level driver helper macros * @{ */ #if ((PAL_USE_CALLBACKS == TRUE) && (PAL_USE_WAIT == TRUE)) || \ defined(__DOXYGEN__) /** * @brief Initializes a PAL event object. * * @param[in] e event index * * @notapi */ #define _pal_init_event(e) \ do { \ osalThreadQueueObjectInit(&_pal_events[e].threads); \ _pal_events[e].cb = NULL; \ _pal_events[e].arg = NULL; \ } while (false) #endif /* (PAL_USE_CALLBACKS == TRUE) && (PAL_USE_WAIT == TRUE) */ #if (PAL_USE_CALLBACKS == TRUE) && (PAL_USE_WAIT == FALSE) #define _pal_init_event(e) \ do { \ _pal_events[e].cb = NULL; \ _pal_events[e].arg = NULL; \ } while (false) #endif /* (PAL_USE_CALLBACKS == TRUE) && (PAL_USE_WAIT == FALSE) */ #if (PAL_USE_CALLBACKS == FALSE) && (PAL_USE_WAIT == TRUE) #define _pal_init_event(e) \ do { \ osalThreadQueueObjectInit(&_pal_events[e].threads); \ } while (false) #endif /* (PAL_USE_CALLBACKS == FALSE) && (PAL_USE_WAIT == TRUE) */ #if ((PAL_USE_CALLBACKS == TRUE) && (PAL_USE_WAIT == TRUE)) || defined(__DOXYGEN__) /** * @brief Clears a PAL event object. * * @param[in] e event index * * @notapi */ #define _pal_clear_event(e) \ do { \ osalThreadDequeueAllI(&_pal_events[pad].threads, MSG_RESET); \ _pal_events[e].cb = NULL; \ _pal_events[e].arg = NULL; \ } while (false) #endif /* (PAL_USE_CALLBACKS == TRUE) && (PAL_USE_WAIT == TRUE) */ #if (PAL_USE_CALLBACKS == TRUE) && (PAL_USE_WAIT == FALSE) #define _pal_clear_event(e) \ do {
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2017 Robert Ou <rqou@robertou.com>
 *
 *  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/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SynthCoolrunner2Pass : public ScriptPass
{
	SynthCoolrunner2Pass() : ScriptPass("synth_coolrunner2", "synthesis for Xilinx Coolrunner-II CPLDs") { }

	void help() override
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_coolrunner2 [options]\n");
		log("\n");
		log("This command runs synthesis for Coolrunner-II CPLDs. This work is experimental.\n");
		log("It is intended to be used with https://github.com/azonenberg/openfpga as the\n");
		log("place-and-route.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module (default='top')\n");
		log("\n");
		log("    -json <file>\n");
		log("        write the design to the specified JSON file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("    -noflatten\n");
		log("        do not flatten design before synthesis\n");
		log("\n");
		log("    -retime\n");
		log("        run 'abc' with '-dff -D 1' options\n");
		log("\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		help_script();
		log("\n");
	}

	string top_opt, json_file;
	bool flatten, retime;

	void clear_flags() override
	{
		top_opt = "-auto-top";
		json_file = "";
		flatten = true;
		retime = false;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) override
	{
		string run_from, run_to;
		clear_flags();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-top" && argidx+1 < args.size()) {
				top_opt = "-top " + args[++argidx];
				continue;
			}
			if (args[argidx] == "-json" && argidx+1 < args.size()) {
				json_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx+1 < args.size()) {
				size_t pos = args[argidx+1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos+1);
				continue;
			}
			if (args[argidx] == "-noflatten") {
				flatten = false;
				continue;
			}
			if (args[argidx] == "-retime") {
				retime = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (!design->full_selection())
			log_cmd_error("This command only operates on fully selected designs!\n");

		log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n");
		log_push();

		run_script(design, run_from, run_to);

		log_pop();
	}

	void script() override
	{
		if (check_label("begin"))
		{
			run("read_verilog -lib +/coolrunner2/cells_sim.v");
			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
		}

		if (flatten && check_label("flatten", "(unless -noflatten)"))
		{
			run("proc");
			run("flatten");
			run("tribuf -logic");
		}

		if (check_label("coarse"))
		{
			run("synth -run coarse");
		}

		if (check_label("fine"))
		{
			run("extract_counter -dir up -allow_arst no");
			run("techmap -map +/coolrunner2/cells_counter_map.v");
			run("clean");
			run("opt -fast -full");
			run("techmap -map +/techmap.v -map +/coolrunner2/cells_latch.v");
			run("opt -fast");
			run("dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib");
		}

		if (check_label("map_tff"))
		{
			// This is quite hacky. By telling abc that it can only use AND and XOR gates, abc will try and use XOR
			// gates "whenever possible." This will hopefully cause toggle flip-flop structures to turn into an XOR
			// connected to a D flip-flop. We then match on these and convert them into XC2 TFF cells.
			run("abc -g AND,XOR");
			run("clean");
			run("extract -map +/coolrunner2/tff_extract.v");
		}

		if (check_label("map_pla"))
		{
			run("abc -sop -I 40 -P 56" + string(retime ? " -dff -D 1" : ""));
			run("clean");
		}

		if (check_label("map_cells"))
		{
			run("dfflibmap -liberty +/coolrunner2/xc2_dff.lib");
			run("dffinit -ff FDCP Q INIT");
			run("dffinit -ff FDCP_N Q INIT");
			run("dffinit -ff FTCP Q INIT");
			run("dffinit -ff FTCP_N Q INIT");
			run("dffinit -ff LDCP Q INIT");
			run("dffinit -ff LDCP_N Q INIT");
			run("coolrunner2_sop");
			run("clean");
			run("iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO");
			run("attrmvcp -attr src -attr LOC t:IOBUFE n:*");
			run("attrmvcp -attr src -attr LOC -driven t:IBUF n:*");
			run("coolrunner2_fixup");
			run("splitnets");
			run("clean");
		}

		if (check_label("check"))
		{
			run("hierarchy -check");
			run("stat");
			run("check -noinit");
		}

		if (check_label("json"))
		{
			if (!json_file.empty() || help_mode)
				run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
		}
	}
} SynthCoolrunner2Pass;

PRIVATE_NAMESPACE_END