aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/src/hal_i2c.c
blob: 0ed77eeaf46f74ed57f30fb9c5ec1500ea8ff1e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/*
    ChibiOS - Copyright (C) 2006..2016 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.
*/
/*
   Concepts and parts of this file have been contributed by Uladzimir Pylinsky
   aka barthess.
 */

/**
 * @file    i2c.c
 * @brief   I2C Driver code.
 *
 * @addtogroup I2C
 * @{
 */
#include "hal.h"

#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)

/*===========================================================================*/
/* Driver local definitions.                                                 */
/*===========================================================================*/

/*===========================================================================*/
/* Driver exported variables.                                                */
/*===========================================================================*/

/*===========================================================================*/
/* Driver local variables and types.                                         */
/*===========================================================================*/

/*===========================================================================*/
/* Driver local functions.                                                   */
/*===========================================================================*/

/*===========================================================================*/
/* Driver exported functions.                                                */
/*===========================================================================*/

/**
 * @brief   I2C Driver initialization.
 * @note    This function is implicitly invoked by @p halInit(), there is
 *          no need to explicitly initialize the driver.
 *
 * @init
 */
void i2cInit(void) {

  i2c_lld_init();
}

/**
 * @brief   Initializes the standard part of a @p I2CDriver structure.
 *
 * @param[out] i2cp     pointer to the @p I2CDriver object
 *
 * @init
 */
void i2cObjectInit(I2CDriver *i2cp) {

  i2cp->state  = I2C_STOP;
  i2cp->config = NULL;

#if I2C_USE_MUTUAL_EXCLUSION == TRUE
  osalMutexObjectInit(&i2cp->mutex);
#endif

#if defined(I2C_DRIVER_EXT_INIT_HOOK)
  I2C_DRIVER_EXT_INIT_HOOK(i2cp);
#endif
}

/**
 * @brief   Configures and activates the I2C peripheral.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] config    pointer to the @p I2CConfig object
 *
 * @api
 */
void i2cStart(I2CDriver *i2cp, const I2CConfig *config) {

  osalDbgCheck((i2cp != NULL) && (config != NULL));
  osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
                (i2cp->state == I2C_LOCKED), "invalid state");

  osalSysLock();
  i2cp->config = config;
  i2c_lld_start(i2cp);
  i2cp->state = I2C_READY;
  osalSysUnlock();
}

/**
 * @brief   Deactivates the I2C peripheral.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 *
 * @api
 */
void i2cStop(I2CDriver *i2cp) {

  osalDbgCheck(i2cp != NULL);
  osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
                (i2cp->state == I2C_LOCKED), "invalid state");

  osalSysLock();
  i2c_lld_stop(i2cp);
  i2cp->state = I2C_STOP;
  osalSysUnlock();
}

/**
 * @brief   Returns the errors mask associated to the previous operation.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @return              The errors mask.
 *
 * @api
 */
i2cflags_t i2cGetErrors(I2CDriver *i2cp) {

  osalDbgCheck(i2cp != NULL);

  return i2c_lld_get_errors(i2cp);
}

/**
 * @brief   Sends data via the I2C bus.
 * @details Function designed to realize "read-through-write" transfer
 *          paradigm. If you want transmit data without any further read,
 *          than set @b rxbytes field to 0.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address (7 bits) without R/W bit
 * @param[in] txbuf     pointer to transmit buffer
 * @param[in] txbytes   number of bytes to be transmitted
 * @param[out] rxbuf    pointer to receive buffer
 * @param[in] rxbytes   number of bytes to be received, set it to 0 if
 *                      you want transmit only
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 *
 * @return              The operation status.
 * @retval MSG_OK       if the function succeeded.
 * @retval MSG_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval MSG_TIMEOUT  if a timeout occurred before operation end.
 *
 * @api
 */
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
                               i2caddr_t addr,
                               const uint8_t *txbuf,
                               size_t txbytes,
                               uint8_t *rxbuf,
                               size_t rxbytes,
                               systime_t timeout) {
  msg_t rdymsg;

  osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
               (txbytes > 0U) && (txbuf != NULL) &&
               ((rxbytes == 0U) || ((rxbytes > 0U) && (rxbuf != NULL))) &&
               (timeout != TIME_IMMEDIATE));

  osalDbgAssert(i2cp->state == I2C_READY, "not ready");

  osalSysLock();
  i2cp->errors = I2C_NO_ERROR;
  i2cp->state = I2C_ACTIVE_TX;
  rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes,
                                           rxbuf, rxbytes, timeout);
  if (rdymsg == MSG_TIMEOUT) {
    i2cp->state = I2C_LOCKED;
  }
  else {
    i2cp->state = I2C_READY;
  }
  osalSysUnlock();
  return rdymsg;
}

/**
 * @brief   Receives data from the I2C bus.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address (7 bits) without R/W bit
 * @param[out] rxbuf    pointer to receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 *
 * @return              The operation status.
 * @retval MSG_OK       if the function succeeded.
 * @retval MSG_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval MSG_TIMEOUT  if a timeout occurred before operation end.
 *
 * @api
 */
msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
                              i2caddr_t addr,
                              uint8_t *rxbuf,
                              size_t rxbytes,
                              systime_t timeout){

  msg_t rdymsg;

  osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
               (rxbytes > 0U) && (rxbuf != NULL) &&
               (timeout != TIME_IMMEDIATE));

  osalDbgAssert(i2cp->state == I2C_READY, "not ready");

  osalSysLock();
  i2cp->errors = I2C_NO_ERROR;
  i2cp->state = I2C_ACTIVE_RX;
  rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout);
  if (rdymsg == MSG_TIMEOUT) {
    i2cp->state = I2C_LOCKED;
  }
  else {
    i2cp->state = I2C_READY;
  }
  osalSysUnlock();
  return rdymsg;
}

#if (I2C_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
/**
 * @brief   Gains exclusive access to the I2C bus.
 * @details This function tries to gain ownership to the I2C bus, if the bus
 *          is already being used then the invoking thread is queued.
 * @pre     In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
 *          must be enabled.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 *
 * @api
 */
void i2cAcquireBus(I2CDriver *i2cp) {

  osalDbgCheck(i2cp != NULL);

  osalMutexLock(&i2cp->mutex);
}

/**
 * @brief   Releases exclusive access to the I2C bus.
 * @pre     In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
 *          must be enabled.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 *
 * @api
 */
void i2cReleaseBus(I2CDriver *i2cp) {

  osalDbgCheck(i2cp != NULL);

  osalMutexUnlock(&i2cp->mutex);
}
#endif /* I2C_USE_MUTUAL_EXCLUSION == TRUE */

#endif /* HAL_USE_I2C == TRUE */

/** @} */
t-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *                2019  Eddie Hung <eddie@fpgeh.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.
 *
 */

// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf

// https://stackoverflow.com/a/46137633
#ifdef _MSC_VER
#include <stdlib.h>
#define __builtin_bswap32 _byteswap_ulong
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define __builtin_bswap32 OSSwapInt32
#endif
#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "aigerparse.h"

YOSYS_NAMESPACE_BEGIN

inline int32_t from_big_endian(int32_t i32) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
	return __builtin_bswap32(i32);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
	return i32;
#else
#error "Unknown endianness"
#endif
}

#define log_debug2(...) ;
//#define log_debug2(...) log_debug(__VA_ARGS__)

struct ConstEvalAig
{
	RTLIL::Module *module;
	dict<RTLIL::SigBit, RTLIL::State> values_map;
	dict<RTLIL::SigBit, RTLIL::Cell*> sig2driver;
	dict<SigBit, pool<RTLIL::SigBit>> sig2deps;

	ConstEvalAig(RTLIL::Module *module) : module(module)
	{
		for (auto &it : module->cells_) {
			if (!yosys_celltypes.cell_known(it.second->type))
				continue;
			for (auto &it2 : it.second->connections())
				if (yosys_celltypes.cell_output(it.second->type, it2.first)) {
					auto r YS_ATTRIBUTE(unused) = sig2driver.insert(std::make_pair(it2.second, it.second));
					log_assert(r.second);
				}
		}
	}

	void clear()
	{
		values_map.clear();
		sig2deps.clear();
	}

	void set(RTLIL::SigBit sig, RTLIL::State value)
	{
		auto it = values_map.find(sig);
#ifndef NDEBUG
		if (it != values_map.end()) {
			RTLIL::State current_val = it->second;
			log_assert(current_val == value);
		}
#endif
		if (it != values_map.end())
			it->second = value;
		else
			values_map[sig] = value;
	}

	void set_incremental(RTLIL::SigSpec sig, RTLIL::Const value)
	{
		log_assert(GetSize(sig) == GetSize(value));

		for (int i = 0; i < GetSize(sig); i++) {
			auto it = values_map.find(sig[i]);
			if (it != values_map.end()) {
				RTLIL::State current_val = it->second;
				if (current_val != value[i])
					for (auto dep : sig2deps[sig[i]])
						values_map.erase(dep);
				it->second = value[i];
			}
			else
				values_map[sig[i]] = value[i];
		}
	}

	void compute_deps(RTLIL::SigBit output, const pool<RTLIL::SigBit> &inputs)
	{
		sig2deps[output].insert(output);

		RTLIL::Cell *cell = sig2driver.at(output);
		RTLIL::SigBit sig_a = cell->getPort("\\A");
		sig2deps[sig_a].reserve(sig2deps[sig_a].size() + sig2deps[output].size()); // Reserve so that any invalidation
											   // that may occur does so here, and
											   // not mid insertion (below)
		sig2deps[sig_a].insert(sig2deps[output].begin(), sig2deps[output].end());
		if (!inputs.count(sig_a))
			compute_deps(sig_a, inputs);

		if (cell->type == "$_AND_") {
			RTLIL::SigSpec sig_b = cell->getPort("\\B");
			sig2deps[sig_b].reserve(sig2deps[sig_b].size() + sig2deps[output].size()); // Reserve so that any invalidation
												   // that may occur does so here, and
												   // not mid insertion (below)
			sig2deps[sig_b].insert(sig2deps[output].begin(), sig2deps[output].end());

			if (!inputs.count(sig_b))
				compute_deps(sig_b, inputs);
		}
		else if (cell->type == "$_NOT_") {
		}
		else log_abort();
	}

	bool eval(RTLIL::Cell *cell)
	{
		RTLIL::SigBit sig_y = cell->getPort("\\Y");
		if (values_map.count(sig_y))
			return true;

		RTLIL::SigBit sig_a = cell->getPort("\\A");
		if (!eval(sig_a))
			return false;

		RTLIL::State eval_ret = RTLIL::Sx;
		if (cell->type == "$_NOT_") {
			if (sig_a == State::S0) eval_ret = State::S1;
			else if (sig_a == State::S1) eval_ret = State::S0;
		}
		else if (cell->type == "$_AND_") {
			if (sig_a == State::S0) {
				eval_ret = State::S0;
				goto eval_end;
			}

			{
				RTLIL::SigBit sig_b = cell->getPort("\\B");
				if (!eval(sig_b))
					return false;
				if (sig_b == State::S0) {
					eval_ret = State::S0;
					goto eval_end;
				}

				if (sig_a != State::S1 || sig_b != State::S1)
					goto eval_end;

				eval_ret = State::S1;
			}
		}
		else log_abort();

eval_end:
		set(sig_y, eval_ret);
		return true;
	}

	bool eval(RTLIL::SigBit &sig)
	{
		auto it = values_map.find(sig);
		if (it != values_map.end()) {
			sig = it->second;
			return true;
		}

		RTLIL::Cell *cell = sig2driver.at(sig);
		if (!eval(cell))
			return false;

		it = values_map.find(sig);
		if (it != values_map.end()) {
			sig = it->second;
			return true;
		}

		return false;
	}
};

AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports)
	: design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports), aiger_autoidx(autoidx++)
{
	module = new RTLIL::Module;
	module->name = module_name;
	if (design->module(module->name))
		log_error("Duplicate definition of module %s!\n", log_id(module->name));
}

void AigerReader::parse_aiger()
{
	std::string header;
	f >> header;
	if (header != "aag" && header != "aig")
		log_error("Unsupported AIGER file!\n");

	// Parse rest of header
	if (!(f >> M >> I >> L >> O >> A))
		log_error("Invalid AIGER header\n");

	// Optional values
	B = C = J = F = 0;
	if (f.peek() != ' ') goto end_of_header;
	if (!(f >> B)) log_error("Invalid AIGER header\n");
	if (f.peek() != ' ') goto end_of_header;
	if (!(f >> C)) log_error("Invalid AIGER header\n");
	if (f.peek() != ' ') goto end_of_header;
	if (!(f >> J)) log_error("Invalid AIGER header\n");
	if (f.peek() != ' ') goto end_of_header;
	if (!(f >> F)) log_error("Invalid AIGER header\n");
end_of_header:

	std::string line;
	std::getline(f, line); // Ignore up to start of next line, as standard
	// says anything that follows could be used for
	// optional sections

	log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);

	line_count = 1;
	piNum = 0;
	flopNum = 0;

	if (header == "aag")
		parse_aiger_ascii();
	else if (header == "aig")
		parse_aiger_binary();
	else
		log_abort();

	RTLIL::Wire* n0 = module->wire(stringf("$aiger%d$0", aiger_autoidx));
	if (n0)
		module->connect(n0, State::S0);

	// Parse footer (symbol table, comments, etc.)
	unsigned l1;
	std::string s;
	for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
		if (c == 'i' || c == 'l' || c == 'o' || c == 'b') {
			f.ignore(1);
			if (!(f >> l1 >> s))
				log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);

			if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
				log_error("Line %u has invalid symbol position!\n", line_count);

			RTLIL::IdString escaped_s = stringf("\\%s", s.c_str());
			RTLIL::Wire* wire;
			if (c == 'i') wire = inputs[l1];
			else if (c == 'l') wire = latches[l1];
			else if (c == 'o') {
				wire = module->wire(escaped_s);
				if (wire) {
					// Could have been renamed by a latch
					module->swap_names(wire, outputs[l1]);
					module->connect(outputs[l1], wire);
					goto next;
				}
				wire = outputs[l1];
			}
			else if (c == 'b') wire = bad_properties[l1];
			else log_abort();

			module->rename(wire, escaped_s);
		}
		else if (c == 'j' || c == 'f') {
			// TODO
		}
		else if (c == 'c') {
			f.ignore(1);
			if (f.peek() == '\r')
				f.ignore(1);
			if (f.peek() == '\n')
				break;
			// Else constraint (TODO)
		}
		else
			log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
next:
		std::getline(f, line); // Ignore up to start of next line
	}

	post_process();
}

static uint32_t parse_xaiger_literal(std::istream &f)
{
	uint32_t l;
	f.read(reinterpret_cast<char*>(&l), sizeof(l));
	if (f.gcount() != sizeof(l))
#if defined(_WIN32) && defined(__MINGW32__)
		log_error("Offset %I64d: unable to read literal!\n", static_cast<int64_t>(f.tellg()));
#else
		log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast<int64_t>(f.tellg()));
#endif
	return from_big_endian(l);
}

RTLIL::Wire* AigerReader::createWireIfNotExists(RTLIL::Module *module, unsigned literal)
{
	const unsigned variable = literal >> 1;
	const bool invert = literal & 1;
	RTLIL::IdString wire_name(stringf("$aiger%d$%d%s", aiger_autoidx, variable, invert ? "b" : ""));
	RTLIL::Wire *wire = module->wire(wire_name);
	if (wire) return wire;
	log_debug2("Creating %s\n", wire_name.c_str());
	wire = module->addWire(wire_name);
	wire->port_input = wire->port_output = false;
	if (!invert) return wire;
	RTLIL::IdString wire_inv_name(stringf("$aiger%d$%d", aiger_autoidx, variable));
	RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
	if (wire_inv) {
		if (module->cell(wire_inv_name)) return wire;
	}
	else {
		log_debug2("Creating %s\n", wire_inv_name.c_str());
		wire_inv = module->addWire(wire_inv_name);
		wire_inv->port_input = wire_inv->port_output = false;
	}

	log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
	module->addNotGate(stringf("$not$aiger%d$%d", aiger_autoidx, variable), wire_inv, wire);

	return wire;
}

void AigerReader::parse_xaiger()
{
	std::string header;
	f >> header;
	if (header != "aag" && header != "aig")
		log_error("Unsupported AIGER file!\n");

	// Parse rest of header
	if (!(f >> M >> I >> L >> O >> A))
		log_error("Invalid AIGER header\n");

	// Optional values
	B = C = J = F = 0;

	std::string line;
	std::getline(f, line); // Ignore up to start of next line, as standard
	// says anything that follows could be used for
	// optional sections

	log_debug("M=%u I=%u L=%u O=%u A=%u\n", M, I, L, O, A);

	line_count = 1;
	piNum = 0;
	flopNum = 0;

	if (header == "aag")
		parse_aiger_ascii();
	else if (header == "aig")
		parse_aiger_binary();
	else
		log_abort();

	RTLIL::Wire* n0 = module->wire(stringf("$aiger%d$0", aiger_autoidx));
	if (n0)
		module->connect(n0, State::S0);

	int c = f.get();
	if (c != 'c')
		log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
	if (f.peek() == '\n')
		f.get();

	dict<int,IdString> box_lookup;
	for (auto m : design->modules()) {
		auto it = m->attributes.find(ID(abc9_box_id));
		if (it == m->attributes.end())
			continue;
		if (m->name.begins_with("$paramod"))
			continue;
		auto id = it->second.as_int();
		auto r = box_lookup.insert(std::make_pair(id, m->name));
		if (!r.second)
			log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n",
					log_id(m), id, log_id(r.first->second));
		log_assert(r.second);
	}

	// Parse footer (symbol table, comments, etc.)
	std::string s;
	for (int c = f.get(); c != EOF; c = f.get()) {
		// XAIGER extensions
		if (c == 'm') {
			uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
			uint32_t lutNum = parse_xaiger_literal(f);
			uint32_t lutSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
			log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
			ConstEvalAig ce(module);
			for (unsigned i = 0; i < lutNum; ++i) {
				uint32_t rootNodeID = parse_xaiger_literal(f);
				uint32_t cutLeavesM = parse_xaiger_literal(f);
				log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
				RTLIL::Wire *output_sig = module->wire(stringf("$aiger%d$%d", aiger_autoidx, rootNodeID));
				log_assert(output_sig);
				uint32_t nodeID;
				RTLIL::SigSpec input_sig;
				for (unsigned j = 0; j < cutLeavesM; ++j) {
					nodeID = parse_xaiger_literal(f);
					log_debug2("\t%u\n", nodeID);
					RTLIL::Wire *wire = module->wire(stringf("$aiger%d$%d", aiger_autoidx, nodeID));
					log_assert(wire);
					input_sig.append(wire);
				}
				// TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size())
				ce.clear();
				ce.compute_deps(output_sig, input_sig.to_sigbit_pool());
				RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size());
				for (int j = 0; j < (1 << cutLeavesM); ++j) {
					int gray = j ^ (j >> 1);
					ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)});
					RTLIL::SigBit o(output_sig);
					bool success YS_ATTRIBUTE(unused) = ce.eval(o);
					log_assert(success);
					log_assert(o.wire == nullptr);
					lut_mask[gray] = o.data;
				}
				RTLIL::Cell *output_cell = module->cell(stringf("$and$aiger%d$%d", aiger_autoidx, rootNodeID));
				log_assert(output_cell);
				module->remove(output_cell);
				module->addLut(stringf("$lut$aiger%d$%d", aiger_autoidx, rootNodeID), input_sig, output_sig, std::move(lut_mask));
			}
		}
		else if (c == 'r') {
			uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
			flopNum = parse_xaiger_literal(f);
			log_debug("flopNum = %u\n", flopNum);
			log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
			f.ignore(flopNum * sizeof(uint32_t));
		}
		else if (c == 'n') {
			parse_xaiger_literal(f);
			f >> s;
			log_debug("n: '%s'\n", s.c_str());
		}
		else if (c == 'h') {
			f.ignore(sizeof(uint32_t));
			uint32_t version YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
			log_assert(version == 1);
			uint32_t ciNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
			log_debug("ciNum = %u\n", ciNum);
			uint32_t coNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
			log_debug("coNum = %u\n", coNum);
			piNum = parse_xaiger_literal(f);
			log_debug("piNum = %u\n", piNum);
			uint32_t poNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
			log_debug("poNum = %u\n", poNum);
			uint32_t boxNum = parse_xaiger_literal(f);
			log_debug("boxNum = %u\n", boxNum);
			for (unsigned i = 0; i < boxNum; i++) {
				f.ignore(2*sizeof(uint32_t));
				uint32_t boxUniqueId = parse_xaiger_literal(f);
				log_assert(boxUniqueId > 0);
				uint32_t oldBoxNum = parse_xaiger_literal(f);
				RTLIL::Cell* cell = module->addCell(stringf("$box%u", oldBoxNum), box_lookup.at(boxUniqueId));
				boxes.emplace_back(cell);
			}
		}
		else if (c == 'a' || c == 'i' || c == 'o' || c == 's') {
			uint32_t dataSize = parse_xaiger_literal(f);
			f.ignore(dataSize);
			log_debug("ignoring '%c'\n", c);
		}
		else {
			break;
		}
	}

	post_process();
}

void AigerReader::parse_aiger_ascii()
{
	std::string line;
	std::stringstream ss;

	unsigned l1, l2, l3;

	// Parse inputs
	int digits = ceil(log10(I));
	for (unsigned i = 1; i <= I; ++i, ++line_count) {
		if (!(f >> l1))
			log_error("Line %u cannot be interpreted as an input!\n", line_count);
		log_debug2("%d is an input\n", l1);
		log_assert(!(l1 & 1)); // Inputs can't be inverted
		RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, l1 >> 1));
		wire->port_input = true;
		module->connect(createWireIfNotExists(module, l1), wire);
		inputs.push_back(wire);
	}

	// Parse latches
	RTLIL::Wire *clk_wire = nullptr;
	if (L > 0 && !clk_name.empty()) {
		clk_wire = module->wire(clk_name);
		log_assert(!clk_wire);
		log_debug2("Creating %s\n", clk_name.c_str());
		clk_wire = module->addWire(clk_name);
		clk_wire->port_input = true;
		clk_wire->port_output = false;
	}
	digits = ceil(log10(L));
	for (unsigned i = 0; i < L; ++i, ++line_count) {
		if (!(f >> l1 >> l2))
			log_error("Line %u cannot be interpreted as a latch!\n", line_count);
		log_debug2("%d %d is a latch\n", l1, l2);
		log_assert(!(l1 & 1));
		RTLIL::Wire *q_wire = module->addWire(stringf("$l%0*d", digits, l1 >> 1));
		module->connect(createWireIfNotExists(module, l1), q_wire);
		RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);

		if (clk_wire)
			module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
		else
			module->addFfGate(NEW_ID, d_wire, q_wire);

		// Reset logic is optional in AIGER 1.9
		if (f.peek() == ' ') {
			if (!(f >> l3))
				log_error("Line %u cannot be interpreted as a latch!\n", line_count);

			if (l3 == 0)
				q_wire->attributes["\\init"] = State::S0;
			else if (l3 == 1)
				q_wire->attributes["\\init"] = State::S1;
			else if (l3 == l1) {
				//q_wire->attributes["\\init"] = RTLIL::Sx;
			}
			else
				log_error("Line %u has invalid reset literal for latch!\n", line_count);
		}
		else {
			// AIGER latches are assumed to be initialized to zero
			q_wire->attributes["\\init"] = State::S0;
		}
		latches.push_back(q_wire);
	}

	// Parse outputs
	for (unsigned i = 0; i < O; ++i, ++line_count) {
		if (!(f >> l1))
			log_error("Line %u cannot be interpreted as an output!\n", line_count);

		log_debug2("%d is an output\n", l1);
		const unsigned variable = l1 >> 1;
		const bool invert = l1 & 1;
		RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
		RTLIL::Wire *wire = module->wire(wire_name);
		if (!wire)
			wire = createWireIfNotExists(module, l1);
		else if (wire->port_input || wire->port_output) {
			RTLIL::Wire *new_wire = module->addWire(NEW_ID);
			module->connect(new_wire, wire);
			wire = new_wire;
		}
		wire->port_output = true;
		outputs.push_back(wire);
	}

	// Parse bad properties
	for (unsigned i = 0; i < B; ++i, ++line_count) {
		if (!(f >> l1))
			log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);

		log_debug2("%d is a bad state property\n", l1);
		RTLIL::Wire *wire = createWireIfNotExists(module, l1);
		wire->port_output = true;
		bad_properties.push_back(wire);
	}

	// TODO: Parse invariant constraints
	for (unsigned i = 0; i < C; ++i, ++line_count)
		std::getline(f, line); // Ignore up to start of next line

	// TODO: Parse justice properties
	for (unsigned i = 0; i < J; ++i, ++line_count)
		std::getline(f, line); // Ignore up to start of next line

	// TODO: Parse fairness constraints
	for (unsigned i = 0; i < F; ++i, ++line_count)
		std::getline(f, line); // Ignore up to start of next line

	// Parse AND
	for (unsigned i = 0; i < A; ++i) {
		if (!(f >> l1 >> l2 >> l3))
			log_error("Line %u cannot be interpreted as an AND!\n", line_count);

		log_debug2("%d %d %d is an AND\n", l1, l2, l3);
		log_assert(!(l1 & 1));
		RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
		RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
		RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
		module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire);
	}
	std::getline(f, line); // Ignore up to start of next line
}

static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
{
	unsigned x = 0, i = 0;
	unsigned char ch;
	while ((ch = f.get()) & 0x80)
		x |= (ch & 0x7f) << (7 * i++);
	return ref - (x | (ch << (7 * i)));
}

void AigerReader::parse_aiger_binary()
{
	unsigned l1, l2, l3;
	std::string line;

	// Parse inputs
	int digits = ceil(log10(I));
	for (unsigned i = 1; i <= I; ++i) {
		log_debug2("%d is an input\n", i);
		RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, i));
		wire->port_input = true;
		module->connect(createWireIfNotExists(module, i << 1), wire);
		inputs.push_back(wire);
	}

	// Parse latches
	RTLIL::Wire *clk_wire = nullptr;
	if (L > 0 && !clk_name.empty()) {
		clk_wire = module->wire(clk_name);
		log_assert(!clk_wire);
		log_debug2("Creating %s\n", clk_name.c_str());
		clk_wire = module->addWire(clk_name);
		clk_wire->port_input = true;
		clk_wire->port_output = false;
	}
	digits = ceil(log10(L));
	l1 = (I+1) * 2;
	for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
		if (!(f >> l2))
			log_error("Line %u cannot be interpreted as a latch!\n", line_count);
		log_debug("%d %d is a latch\n", l1, l2);
		RTLIL::Wire *q_wire = module->addWire(stringf("$l%0*d", digits, l1 >> 1));
		module->connect(createWireIfNotExists(module, l1), q_wire);
		RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);

		if (clk_wire)
			module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
		else
			module->addFf(NEW_ID, d_wire, q_wire);

		// Reset logic is optional in AIGER 1.9
		if (f.peek() == ' ') {
			if (!(f >> l3))
				log_error("Line %u cannot be interpreted as a latch!\n", line_count);

			if (l3 == 0)
				q_wire->attributes["\\init"] = State::S0;
			else if (l3 == 1)
				q_wire->attributes["\\init"] = State::S1;
			else if (l3 == l1) {
				//q_wire->attributes["\\init"] = RTLIL::Sx;
			}
			else
				log_error("Line %u has invalid reset literal for latch!\n", line_count);
		}
		else {
			// AIGER latches are assumed to be initialized to zero
			q_wire->attributes["\\init"] = State::S0;
		}
		latches.push_back(q_wire);
	}

	// Parse outputs
	digits = ceil(log10(O));
	for (unsigned i = 0; i < O; ++i, ++line_count) {
		if (!(f >> l1))
			log_error("Line %u cannot be interpreted as an output!\n", line_count);

		log_debug2("%d is an output\n", l1);
		RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
		wire->port_output = true;
		module->connect(wire, createWireIfNotExists(module, l1));
		outputs.push_back(wire);
	}
	std::getline(f, line); // Ignore up to start of next line

	// Parse bad properties
	for (unsigned i = 0; i < B; ++i, ++line_count) {
		if (!(f >> l1))
			log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);

		log_debug2("%d is a bad state property\n", l1);
		RTLIL::Wire *wire = createWireIfNotExists(module, l1);
		wire->port_output = true;
		bad_properties.push_back(wire);
	}
	if (B > 0)
		std::getline(f, line); // Ignore up to start of next line

	// TODO: Parse invariant constraints
	for (unsigned i = 0; i < C; ++i, ++line_count)
		std::getline(f, line); // Ignore up to start of next line

	// TODO: Parse justice properties
	for (unsigned i = 0; i < J; ++i, ++line_count)
		std::getline(f, line); // Ignore up to start of next line

	// TODO: Parse fairness constraints
	for (unsigned i = 0; i < F; ++i, ++line_count)
		std::getline(f, line); // Ignore up to start of next line

	// Parse AND
	l1 = (I+L+1) << 1;
	for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
		l2 = parse_next_delta_literal(f, l1);
		l3 = parse_next_delta_literal(f, l2);

		log_debug2("%d %d %d is an AND\n", l1, l2, l3);
		log_assert(!(l1 & 1));
		RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
		RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
		RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
		module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire);
	}
}

void AigerReader::post_process()
{
	dict<IdString, std::vector<IdString>> box_ports;
	unsigned ci_count = 0, co_count = 0, flop_count = 0;
	for (auto cell : boxes) {
		RTLIL::Module* box_module = design->module(cell->type);
		log_assert(box_module);

		auto r = box_ports.insert(cell->type);
		if (r.second) {
			// Make carry in the last PI, and carry out the last PO
			//   since ABC requires it this way
			IdString carry_in, carry_out;
			for (const auto &port_name : box_module->ports) {
				auto w = box_module->wire(port_name);
				log_assert(w);
				if (w->get_bool_attribute("\\abc9_carry")) {
					if (w->port_input)
						carry_in = port_name;
					if (w->port_output)
						carry_out = port_name;
				}
				else
					r.first->second.push_back(port_name);
			}
			if (carry_in != IdString()) {
				log_assert(carry_out != IdString());
				r.first->second.push_back(carry_in);
				r.first->second.push_back(carry_out);
			}
		}

		for (auto port_name : box_ports.at(cell->type)) {
			RTLIL::Wire* port = box_module->wire(port_name);
			log_assert(port);
			RTLIL::SigSpec rhs;
			for (int i = 0; i < GetSize(port); i++) {
				RTLIL::Wire* wire = nullptr;
				if (port->port_input) {
					log_assert(co_count < outputs.size());
					wire = outputs[co_count++];
					log_assert(wire);
					log_assert(wire->port_output);
					wire->port_output = false;
				}
				if (port->port_output) {
					log_assert((piNum + ci_count) < inputs.size());
					wire = inputs[piNum + ci_count++];
					log_assert(wire);
					log_assert(wire->port_input);
					wire->port_input = false;
				}
				rhs.append(wire);
			}
			cell->setPort(port_name, rhs);
		}

		if (box_module->attributes.count("\\abc9_flop")) {
			log_assert(co_count < outputs.size());
			Wire *wire = outputs[co_count++];
			log_assert(wire);
			log_assert(wire->port_output);
			wire->port_output = false;

			RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count];
			log_assert(d);
			log_assert(d->port_output);
			d->port_output = false;

			RTLIL::Wire *q = inputs[piNum - flopNum + flop_count];
			log_assert(q);
			log_assert(q->port_input);
			q->port_input = false;

			auto ff = module->addCell(NEW_ID, "$__ABC9_FF_");
			ff->setPort("\\D", d);
			ff->setPort("\\Q", q);
			flop_count++;
			continue;
		}
	}

	dict<RTLIL::IdString, int> wideports_cache;

	if (!map_filename.empty()) {
		std::ifstream mf(map_filename);
		std::string type, symbol;
		int variable, index;
		while (mf >> type >> variable >> index >> symbol) {
			RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
			if (type == "input") {
				log_assert(static_cast<unsigned>(variable) < inputs.size());
				RTLIL::Wire* wire = inputs[variable];
				log_assert(wire);
				log_assert(wire->port_input);
				log_debug("Renaming input %s", log_id(wire));

				if (index == 0) {
					// Cope with the fact that a CI might be identical
					// to a PI (necessary due to ABC); in those cases
					// simply connect the latter to the former
					RTLIL::Wire* existing = module->wire(escaped_s);
					if (!existing)
						module->rename(wire, escaped_s);
					else {
						wire->port_input = false;
						module->connect(wire, existing);
					}
				}
				else if (index > 0) {
					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
					RTLIL::Wire* existing = module->wire(indexed_name);
					if (!existing) {
						module->rename(wire, indexed_name);
						if (wideports)
							wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
					}
					else {
						module->connect(wire, existing);
						wire->port_input = false;
					}
				}
				log_debug(" -> %s\n", log_id(wire));
			}
			else if (type == "output") {
				log_assert(static_cast<unsigned>(variable + co_count) < outputs.size());
				RTLIL::Wire* wire = outputs[variable + co_count];
				log_assert(wire);
				log_assert(wire->port_output);
				if (escaped_s == "$__dummy__") {
					wire->port_output = false;
					continue;
				}
				log_debug("Renaming output %s", log_id(wire));

				if (index == 0) {
					// Cope with the fact that a CO might be identical
					// to a PO (necessary due to ABC); in those cases
					// simply connect the latter to the former
					RTLIL::Wire* existing = module->wire(escaped_s);
					if (!existing) {
						module->rename(wire, escaped_s);
					}
					else {
						wire->port_output = false;
						module->connect(wire, existing);
						wire = existing;
					}
				}
				else if (index > 0) {
					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
					RTLIL::Wire* existing = module->wire(indexed_name);
					if (!existing) {
						module->rename(wire, indexed_name);
						if (wideports)
							wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
					}
					else {
						module->connect(wire, existing);
						wire->port_output = false;
					}
				}
				log_debug(" -> %s\n", log_id(wire));
				int init;
				mf >> init;
				if (init < 2)
					wire->attributes["\\init"] = init;
			}
			else if (type == "box") {
				RTLIL::Cell* cell = module->cell(stringf("$box%d", variable));
				if (cell) { // ABC could have optimised this box away
					module->rename(cell, escaped_s);
					for (const auto &i : cell->connections()) {
						RTLIL::IdString port_name = i.first;
						RTLIL::SigSpec rhs = i.second;
						int index = 0;
						for (auto bit : rhs.bits()) {
							RTLIL::Wire* wire = bit.wire;
							RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name)));
							if (index == 0)
								module->rename(wire, escaped_s);
							else if (index > 0) {
								module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index));
								if (wideports)
									wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
							}
							index++;
						}
					}
				}
			}
			else
				log_error("Symbol type '%s' not recognised.\n", type.c_str());
		}
	}

	for (auto &wp : wideports_cache) {
		auto name = wp.first;
		int width = wp.second + 1;

		RTLIL::Wire *wire = module->wire(name);
		if (wire)
			module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));

		// Do not make ports with a mix of input/output into
		// wide ports
		bool port_input = false, port_output = false;
		for (int i = 0; i < width; i++) {
			RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
			RTLIL::Wire *other_wire = module->wire(other_name);
			if (other_wire) {
				port_input = port_input || other_wire->port_input;
				port_output = port_output || other_wire->port_output;
			}
		}

		wire = module->addWire(name, width);
		wire->port_input = port_input;
		wire->port_output = port_output;

		for (int i = 0; i < width; i++) {
			RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
			RTLIL::Wire *other_wire = module->wire(other_name);
			if (other_wire) {
				other_wire->port_input = false;
				other_wire->port_output = false;
				if (wire->port_input)
					module->connect(other_wire, SigSpec(wire, i));
				else
					module->connect(SigSpec(wire, i), other_wire);
			}
		}
	}

	module->fixup_ports();

	// Insert into a new (temporary) design so that "clean" will only
	// operate (and run checks on) this one module
	RTLIL::Design *mapped_design = new RTLIL::Design;
	mapped_design->add(module);
	Pass::call(mapped_design, "clean");
	mapped_design->modules_.erase(module->name);
	delete mapped_design;

	design->add(module);

	for (auto cell : module->cells().to_vector()) {
		if (cell->type != "$lut") continue;
		auto y_port = cell->getPort("\\Y").as_bit();
		if (y_port.wire->width == 1)
			module->rename(cell, stringf("$lut%s", y_port.wire->name.c_str()));
		else
			module->rename(cell, stringf("$lut%s[%d]", y_port.wire->name.c_str(), y_port.offset));
	}
}

struct AigerFrontend : public Frontend {
	AigerFrontend() : Frontend("aiger", "read AIGER file") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    read_aiger [options] [filename]\n");
		log("\n");
		log("Load module from an AIGER file into the current design.\n");
		log("\n");
		log("    -module_name <module_name>\n");
		log("        Name of module to be created (default: <filename>)\n");
		log("\n");
		log("    -clk_name <wire_name>\n");
		log("        If specified, AIGER latches to be transformed into $_DFF_P_ cells\n");
		log("        clocked by wire of this name. Otherwise, $_FF_ cells will be used.\n");
		log("\n");
		log("    -map <filename>\n");
		log("        read file with port and latch symbols\n");
		log("\n");
		log("    -wideports\n");
		log("        Merge ports that match the pattern 'name[int]' into a single\n");
		log("        multi-bit port 'name'.\n");
		log("\n");
	}
	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		log_header(design, "Executing AIGER frontend.\n");

		RTLIL::IdString clk_name;
		RTLIL::IdString module_name;
		std::string map_filename;
		bool wideports = false;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			std::string arg = args[argidx];
			if (arg == "-module_name" && argidx+1 < args.size()) {
				module_name = RTLIL::escape_id(args[++argidx]);
				continue;
			}
			if (arg == "-clk_name" && argidx+1 < args.size()) {
				clk_name = RTLIL::escape_id(args[++argidx]);