#!/bin/sh # # qemu configure script (c) 2003 Fabrice Bellard # # set temporary file name if test ! -z "$TMPDIR" ; then TMPDIR1="${TMPDIR}" elif test ! -z "$TEMPDIR" ; then TMPDIR1="${TEMPDIR}" else TMPDIR1="/tmp" fi TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c" TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o" TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}" TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S" # default parameters prefix="" static="no" libdir="lib" cross_prefix="" cc="gcc" host_cc="gcc" ar="ar" make="make" strip="strip" cpu=`uname -m` target_list="target-i386-dm" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" ;; armv4l) cpu="armv4l" ;; alpha) cpu="alpha" ;; "Power Macintosh"|ppc|ppc64) cpu="powerpc" ;; mips) cpu="mips" ;; s390) cpu="s390" ;; sparc) cpu="sparc" ;; sparc64) cpu="sparc64" ;; ia64) cpu="ia64" ;; m68k) cpu="m68k" ;; x86_64|amd64) cpu="amd64" libdir="lib64" ;; *) cpu="unknown" ;; esac gprof="no" bigendian="no" mingw32="no" EXESUF="" gdbstub="no" slirp="no" adlib="no" oss="no" fmod="no" fmod_lib="" fmod_inc="" # OS specific targetos=`uname -s` case $targetos in MINGW32*) mingw32="yes" ;; FreeBSD) bsd="yes" oss="yes" ;; NetBSD) bsd="yes" oss="yes" ;; OpenBSD) bsd="yes" oss="yes" ;; Darwin) bsd="yes" darwin="yes" ;; *) oss="yes" ;; esac if [ "$bsd" = "yes" ] ; then if [ ! "$darwin" = "yes" ] ; then make="gmake" fi target_list="i386-softmmu ppc-softmmu sparc-softmmu" fi # find source path # XXX: we assume an absolute path is given when launching configure, # except in './configure' case. source_path=${0%configure} source_path=${source_path%/} source_path_used="yes" if test -z "$source_path" -o "$source_path" = "." ; then source_path=`pwd` source_path_used="no" fi for opt do case "$opt" in --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` ;; --interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2` ;; --source-path=*) source_path=`echo $opt | cut -d '=' -f 2` ;; --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` ;; --cc=*) cc=`echo $opt | cut -d '=' -f 2` ;; --make=*) make=`echo $opt | cut -d '=' -f 2` ;; --extra-cflags=*) CFLAGS="${opt#--extra-cflags=}" ;; --extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}" ;; --extra-libs=*) extralibs=${opt#--extra-libs=} ;; --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` ;; --target-list=*) target_list=${opt#--target-list=} ;; --enable-gprof) gprof="yes" ;; --static) static="yes" ;; --disable-sdl) sdl="no" ;; --enable-fmod) fmod="yes" ;; --fmod-lib=*) fmod_lib=${opt#--fmod-lib=} ;; --fmod-inc=*) fmod_inc=${opt#--fmod-inc=} ;; --disable-vnc) vnc="no" ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ;; --disable-slirp) slirp="no" ;; --enable-adlib) adlib="yes" ;; esac done # Checking for CFLAGS if test -z "$CFLAGS"; then CFLAGS="-O2" fi cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" if test "$mingw32" = "yes" ; then target_list="i386-softmmu ppc-softmmu sparc-softmmu" EXESUF=".exe" gdbstub="no" oss="no" fi if test -z "$cross_prefix" ; then # --- # big/little endian test cat > $TMPC << EOF #include int main(int argc, char ** argv){ volatile uint32_t i=0x01234567; return (*((uint8_t*)(&i))) == 0x67; } EOF if $cc -o $TMPE $TMPC 2>/dev/null ; then $TMPE && bigendian="yes" else echo big/little test failed fi else # if cross compiling, cannot launch a program, so make a static guess if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then bigendian="yes" fi fi # check gcc options support cat > $TMPC < /dev/null ; then have_gcc3_options="yes" fi ########################################## # VNC probe if test -z "$vnc"; then if libvncserver-config --version >& /dev/null; then vnc=yes else vnc=no fi fi ########################################## # SDL probe sdl_too_old=no if test -z "$sdl" ; then sdl_config="sdl-config" sdl=no sdl_static=no if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then # win32 cross compilation case sdl_config="i386-mingw32msvc-sdl-config" sdl=yes else # normal SDL probe cat > $TMPC << EOF #include #undef main /* We don't want SDL to override our main() */ int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } EOF if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /dev/null ; then _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` if test "$_sdlversion" -lt 121 ; then sdl_too_old=yes else sdl=yes fi # static link with sdl ? if test "$sdl" = "yes" ; then aa="no" `$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes" sdl_static_libs=`$sdl_config --static-libs` if [ "$aa" = "yes" ] ; then sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`" fi if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then sdl_static=yes fi fi # static link fi # sdl compile test fi # cross compilation fi # -z $sdl if test x"$1" = x"-h" -o x"$1" = x"--help" ; then cat << EOF Usage: configure [options] Options: [defaults in brackets after descriptions] EOF echo "Standard options:" echo " --help print this message" echo " --prefix=PREFIX install in PREFIX [$prefix]" echo " --interp-prefix=PREFIX where to find shared libraries, etc." echo " use %M for cpu name [$interp_prefix]" echo " --target-list=LIST set target list [$target_list]" echo " --disable-vnc disable vnc support (else configure checks" echo " for libvncserver-config in your PATH)" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" echo " --cc=CC use C compiler CC [$cc]" echo " --make=MAKE use specified make [$make]" echo " --static enable static build [$static]" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" echo " --enable-fmod enable FMOD audio output driver" echo " --fmod-lib path to FMOD library" echo " --fmod-inc path to FMOD includes" echo "" echo "NOTE: The object files are build at the place where configure is launched" exit 1 fi #installroot=$source_path/../../dist/install installroot= if test "$mingw32" = "yes" ; then if test -z "$prefix" ; then prefix="/c/Program Files/Qemu" fi mandir="$prefix" datadir="$prefix" docdir="$prefix" bindir="$prefix" configdir="" else if test -z "$prefix" ; then prefix="usr/local" fi mandir="$installroot/$prefix/share/man" datadir="$installroot/$prefix/share/xen/qemu" docdir="$installroot/$prefix/share/doc/qemu" bindir="$installroot/$prefix/bin" configdir="$installroot/etc/xen" fi echo "Install prefix $prefix" echo "BIOS directory $datadir" echo "binary directory $bindir" if test "$mingw32" = "no" ; then echo "Manual directory $mandir" fi echo "Source path $source_path" echo "C compiler $cc" echo "make $make" echo "host CPU $cpu" echo "host big endian $bigendian" echo "target list $target_list" echo "gprof enabled $gprof" echo "static build $static" echo "VNC support $vnc" echo "SDL support $sdl" echo "SDL static link $sdl_static" echo "mingw32 support $mingw32" echo "Adlib support $adlib" echo -n "FMOD support $fmod" if test $fmod = "yes"; then echo -n " (lib='$fmod_lib' include='$fmod_inc')" fi echo "" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support" fi if test "$sdl_static" = "no"; then echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output" fi config_mak="config-host.mak" config_h="config-host.h" #echo "Creating $config_mak and $config_h" echo "# Automatically generated by configure - do not modify" > $config_mak echo "/* Automatically generated by configure - do not modify */" > $config_h echo "prefix=$prefix" >> $config_mak echo "bindir=$bindir" >> $config_mak echo "mandir=$mandir" >> $config_mak echo "datadir=$datadir" >> $config_mak echo "docdir=$docdir" >> $config_mak echo "configdir=$configdir" >> $config_mak echo "LIBDIR=$libdir" >> $config_mak echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h echo "MAKE=$make" >> $config_mak echo "CC=$cc" >> $config_mak if test "$have_gcc3_options" = "yes" ; then echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak fi echo "HOST_CC=$host_cc" >> $config_mak echo "AR=$ar" >> $config_mak echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak echo "CFLAGS=$CFLAGS" >> $config_mak echo "LDFLAGS=$LDFLAGS" >> $config_mak echo "EXESUF=$EXESUF" >> $config_mak if test "$bigendian" = "yes" ; then echo "WORDS_BIGENDIAN=yes" >> $config_mak echo "#define WORDS_BIGENDIAN 1" >> $config_h fi if test "$mingw32" = "yes" ; then echo "CONFIG_WIN32=yes" >> $config_mak echo "#define CONFIG_WIN32 1" >> $config_h elif test -f "/usr/include/byteswap.h" ; then echo "#define HAVE_BYTESWAP_H 1" >> $config_h fi if test "$darwin" = "yes" ; then echo "CONFIG_DARWIN=yes" >> $config_mak echo "#define CONFIG_DARWIN 1" >> $config_h fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak echo "#define CONFIG_GDBSTUB 1" >> $config_h fi if test "$gprof" = "yes" ; then echo "TARGET_GPROF=yes" >> $config_mak echo "#define HAVE_GPROF 1" >> $config_h fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=yes" >> $config_mak echo "#define CONFIG_STATIC 1" >> $config_h fi if test "$slirp" = "yes" ; then echo "CONFIG_SLIRP=yes" >> $config_mak echo "#define CONFIG_SLIRP 1" >> $config_h fi if test "$adlib" = "yes" ; then echo "CONFIG_ADLIB=yes" >> $config_mak echo "#define CONFIG_ADLIB 1" >> $config_h fi if test "$oss" = "yes" ; then echo "CONFIG_OSS=yes" >> $config_mak echo "#define CONFIG_OSS 1" >> $config_h fi if test "$fmod" = "yes" ; then echo "CONFIG_FMOD=yes" >> $config_mak echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak echo "#define CONFIG_FMOD 1" >> $config_h fi echo -n "VERSION=" >>$config_mak head $source_path/VERSION >>$config_mak echo "" >>$config_mak echo -n "#define QEMU_VERSION \"" >> $config_h head $source_path/VERSION >> $config_h echo "\"" >> $config_h echo "SRC_PATH=$source_path" >> $config_mak echo "TARGET_DIRS=$target_list" >> $config_mak # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "#define O_LARGEFILE 0" >> $config_h echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h echo "#define _BSD 1" >> $config_h fi if test "$vnc" = "yes"; then echo "CONFIG_VNC=yes" >> $config_mak vnc_cflags=`libvncserver-config --cflags` if [ -z $vnc_cflags ]; then vnc_cflags="/usr/include" fi echo "VNC_CFLAGS=$vnc_cflags" >> $config_mak fi if test "$sdl" = "yes"; then echo "CONFIG_SDL=yes" >> $config_mak echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak fi for target in $target_list; do target_dir="$target" config_mak=$target_dir/config.mak config_h=$target_dir/config.h target_cpu=`echo $target | cut -d '-' -f 2` [ "$target_cpu" = "ppc" ] && target_bigendian=yes target_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then target_softmmu="yes" fi #for support 256M guest target_softmmu="yes" target_user_only="no" if expr $target : '.*-user' > /dev/null ; then target_user_only="yes" fi #echo "Creating $config_mak, $config_h and $target_dir/Makefile" mkdir -p $target_dir if test "$target" = "arm-user" ; then mkdir -p $target_dir/nwfpe fi if test "$target_user_only" = "no" ; then mkdir -p $target_dir/slirp fi #ln -sf $source_path/Makefile.target $target_dir/Makefile echo "# Automatically generated by configure - do not modify" > $config_mak echo "/* Automatically generated by configure - do not modify */" > $config_h echo "include ../config-host.mak" >> $config_mak echo "#include \"../config-host.h\"" >> $config_h echo "TARGET_ARCH=i386" >> $config_mak echo "#define TARGET_ARCH \"i386\"" >> $config_h echo "#define TARGET_I386 1" >> $config_h interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h fi if test "$target_softmmu" = "yes" ; then echo "CONFIG_SOFTMMU=yes" >> $config_mak echo "#define CONFIG_SOFTMMU 1" >> $config_h fi if test "$target_user_only" = "yes" ; then echo "CONFIG_USER_ONLY=yes" >> $config_mak echo "#define CONFIG_USER_ONLY 1" >> $config_h fi if test "$target_user_only" = "no"; then if test "$vnc" = "yes"; then echo "#define CONFIG_VNC 1" >> $config_h echo "CONFIG_VNC=yes" >> $config_mak echo "VNC_CFLAGS=`libvncserver-config --cflags`" >> $config_mak echo "VNC_LIBS=`libvncserver-config --libs`" >> $config_mak fi fi # sdl defines if test "$sdl" = "yes" -a "$target_user_only" = "no"; then if test "$target_softmmu" = "no" -o "$static" = "yes"; then sdl1=$sdl_static else sdl1=$sdl fi if test "$sdl1" = "yes" ; then echo "#define CONFIG_SDL 1" >> $config_h echo "CONFIG_SDL=yes" >> $config_mak if test "$target_softmmu" = "no" -o "$static" = "yes"; then echo "SDL_LIBS=$sdl_static_libs" >> $config_mak else echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak fi echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak if [ "${aa}" = "yes" ] ; then echo -n " `aalib-config --cflags`" >> $config_mak ; fi echo "" >> $config_mak fi fi done # for target in $targets # build tree in object directory if source path is different from current one if test "$source_path_used" = "yes" ; then DIRS="tests" FILES="Makefile tests/Makefile" for dir in $DIRS ; do mkdir -p $dir done for f in $FILES ; do ln -sf $source_path/$f $f done fi rm -f $TMPO $TMPC $TMPE $TMPS 343' href='#n343'>343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
/*
 *  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.
 *
 *  ---
 *
 *  A simple and straightforward verilog backend.
 *
 *  Note that RTLIL processes can't always be mapped easily to a Verilog
 *  process. Therefore this frontend should only be used to export a
 *  Verilog netlist (i.e. after the "proc" pass has converted all processes
 *  to logic networks and registers).
 *
 */

#include "verilog_backend.h"
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <assert.h>
#include <string>
#include <sstream>
#include <set>
#include <map>

namespace {

bool norename, noattr, attr2comment, noexpr;
int auto_name_counter, auto_name_offset, auto_name_digits;
std::map<std::string, int> auto_name_map;

std::set<std::string> reg_wires;

CellTypes reg_ct;
RTLIL::Module *active_module;

void reset_auto_counter_id(const std::string &id, bool may_rename)
{
	const char *str = id.c_str();

	if (*str == '$' && may_rename && !norename)
		auto_name_map[id] = auto_name_counter++;

	if (str[0] != '_' && str[1] != 0)
		return;
	for (int i = 0; str[i] != 0; i++) {
		if (str[i] == '_')
			continue;
		if (str[i] < '0' || str[i] > '9')
			return;
	}

	int num = atoi(str+1);
	if (num >= auto_name_offset)
		auto_name_offset = num + 1;
}

void reset_auto_counter(RTLIL::Module *module)
{
	auto_name_map.clear();
	auto_name_counter = 0;
	auto_name_offset = 0;

	reset_auto_counter_id(module->name, false);

	for (auto it = module->wires.begin(); it != module->wires.end(); it++)
		reset_auto_counter_id(it->second->name, true);

	for (auto it = module->cells.begin(); it != module->cells.end(); it++) {
		reset_auto_counter_id(it->second->name, true);
		reset_auto_counter_id(it->second->type, false);
	}

	for (auto it = module->processes.begin(); it != module->processes.end(); it++)
		reset_auto_counter_id(it->second->name, false);

	auto_name_digits = 1;
	for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
		auto_name_digits++;

	for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
		log("  renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
}

std::string id(std::string internal_id, bool may_rename = true)
{
	const char *str = internal_id.c_str();
	bool do_escape = false;

	if (may_rename && auto_name_map.count(internal_id) != 0) {
		char buffer[100];
		snprintf(buffer, 100, "_%0*d_", auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
		return std::string(buffer);
	}

	if (*str == '\\')
		str++;

	if ('0' <= *str && *str <= '9')
		do_escape = true;

	for (int i = 0; str[i]; i++)
	{
		if ('0' <= str[i] && str[i] <= '9')
			continue;
		if ('a' <= str[i] && str[i] <= 'z')
			continue;
		if ('A' <= str[i] && str[i] <= 'Z')
			continue;
		if (str[i] == '_')
			continue;
		do_escape = true;
		break;
	}

	if (do_escape)
		return "\\" + std::string(str) + " ";
	return std::string(str);
}

bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
{
	sig.optimize();
	if (sig.chunks.size() != 1 || sig.chunks[0].wire == NULL)
		return false;
	if (reg_wires.count(sig.chunks[0].wire->name) == 0)
		return false;
	reg_name = id(sig.chunks[0].wire->name);
	if (sig.width != sig.chunks[0].wire->width)
		if (sig.width == 1)
			reg_name += stringf("[%d]", sig.chunks[0].wire->start_offset +  sig.chunks[0].offset);
		else
			reg_name += stringf("[%d]", sig.chunks[0].wire->start_offset +  sig.chunks[0].offset + sig.chunks[0].width - 1,
					sig.chunks[0].wire->start_offset +  sig.chunks[0].offset);
	return true;
}

void dump_const(FILE *f, RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false)
{
	if (width < 0)
		width = data.bits.size() - offset;
	if (data.str.empty() || width != (int)data.bits.size()) {
		if (width == 32 && !no_decimal) {
			uint32_t val = 0;
			for (int i = offset+width-1; i >= offset; i--) {
				assert(i < (int)data.bits.size());
				if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
					goto dump_bits;
				if (data.bits[i] == RTLIL::S1)
					val |= 1 << (i - offset);
			}
			fprintf(f, "%d", (int)val);
		} else {
	dump_bits:
			fprintf(f, "%d'b", width);
			for (int i = offset+width-1; i >= offset; i--) {
				assert(i < (int)data.bits.size());
				switch (data.bits[i]) {
				case RTLIL::S0: fprintf(f, "0"); break;
				case RTLIL::S1: fprintf(f, "1"); break;
				case RTLIL::Sx: fprintf(f, "x"); break;
				case RTLIL::Sz: fprintf(f, "z"); break;
				case RTLIL::Sa: fprintf(f, "z"); break;
				case RTLIL::Sm: log_error("Found marker state in final netlist.");
				}
			}
		}
	} else {
		fprintf(f, "\"");
		for (size_t i = 0; i < data.str.size(); i++) {
			if (data.str[i] == '\n')
				fprintf(f, "\\n");
			else if (data.str[i] == '\t')
				fprintf(f, "\\t");
			else if (data.str[i] < 32)
				fprintf(f, "\\%03o", data.str[i]);
			else if (data.str[i] == '"')
				fprintf(f, "\\\"");
			else
				fputc(data.str[i], f);
		}
		fprintf(f, "\"");
	}
}

void dump_sigchunk(FILE *f, RTLIL::SigChunk &chunk, bool no_decimal = false)
{
	if (chunk.wire == NULL) {
		dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
	} else {
		if (chunk.width == chunk.wire->width && chunk.offset == 0)
			fprintf(f, "%s", id(chunk.wire->name).c_str());
		else if (chunk.width == 1)
			fprintf(f, "%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
		else
			fprintf(f, "%s[%d:%d]", id(chunk.wire->name).c_str(),
					chunk.offset + chunk.wire->start_offset + chunk.width - 1,
					chunk.offset + chunk.wire->start_offset);
	}
}

void dump_sigspec(FILE *f, RTLIL::SigSpec &sig)
{
	if (sig.chunks.size() == 1) {
		dump_sigchunk(f, sig.chunks[0]);
	} else {
		fprintf(f, "{ ");
		for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
			if (it != sig.chunks.rbegin())
				fprintf(f, ", ");
			dump_sigchunk(f, *it, true);
		}
		fprintf(f, " }");
	}
}

void dump_attributes(FILE *f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
{
	if (noattr)
		return;
	for (auto it = attributes.begin(); it != attributes.end(); it++) {
		fprintf(f, "%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
		if (it->second.bits.size() > 0) {
			fprintf(f, " = ");
			dump_const(f, it->second);
		}
		fprintf(f, " %s%c", attr2comment ? "*/" : "*)", term);
	}
}

void dump_wire(FILE *f, std::string indent, RTLIL::Wire *wire)
{
	dump_attributes(f, indent, wire->attributes);
	if (wire->port_input && !wire->port_output)
		fprintf(f, "%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
	else if (!wire->port_input && wire->port_output)
		fprintf(f, "%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
	else if (wire->port_input && wire->port_output)
		fprintf(f, "%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
	else
		fprintf(f, "%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
	if (wire->width != 1)
		fprintf(f, "[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
	fprintf(f, "%s;\n", id(wire->name).c_str());
}

void dump_memory(FILE *f, std::string indent, RTLIL::Memory *memory)
{
	dump_attributes(f, indent, memory->attributes);
	fprintf(f, "%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
}

void dump_cell_expr_port(FILE *f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
{
	if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
		fprintf(f, "$signed(");
		dump_sigspec(f, cell->connections["\\" + port]);
		fprintf(f, ")");
	} else
		dump_sigspec(f, cell->connections["\\" + port]);
}

std::string cellname(RTLIL::Cell *cell)
{
	if (!norename && cell->name[0] == '$' && reg_ct.cell_known(cell->type) && cell->connections.count("\\Q") > 0)
	{
		RTLIL::SigSpec sig = cell->connections["\\Q"];
		if (sig.width != 1 || sig.is_fully_const())
			goto no_special_reg_name;

		sig.optimize();
		RTLIL::Wire *wire = sig.chunks[0].wire;

		if (wire->name[0] != '\\')
			goto no_special_reg_name;

		std::string cell_name = wire->name;

		size_t pos = cell_name.find('[');
		if (pos != std::string::npos)
			cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
		else
			cell_name = cell_name + "_reg";

		if (wire->width != 1)
			cell_name += stringf("[%d]", wire->start_offset + sig.chunks[0].offset);

		if (active_module && active_module->count_id(cell_name) > 0)
				goto no_special_reg_name;

		return id(cell_name);
	}
	else
	{
no_special_reg_name:
		return id(cell->name).c_str();
	}
}

void dump_cell_expr_uniop(FILE *f, std::string indent, RTLIL::Cell *cell, std::string op)
{
	fprintf(f, "%s" "assign ", indent.c_str());
	dump_sigspec(f, cell->connections["\\Y"]);
	fprintf(f, " = %s ", op.c_str());
	dump_attributes(f, "", cell->attributes, ' ');
	dump_cell_expr_port(f, cell, "A", true);
	fprintf(f, ";\n");
}

void dump_cell_expr_binop(FILE *f, std::string indent, RTLIL::Cell *cell, std::string op)
{
	fprintf(f, "%s" "assign ", indent.c_str());
	dump_sigspec(f, cell->connections["\\Y"]);
	fprintf(f, " = ");
	dump_cell_expr_port(f, cell, "A", true);
	fprintf(f, " %s ", op.c_str());
	dump_attributes(f, "", cell->attributes, ' ');
	dump_cell_expr_port(f, cell, "B", true);
	fprintf(f, ";\n");
}

bool dump_cell_expr(FILE *f, std::string indent, RTLIL::Cell *cell)
{
	if (cell->type == "$_INV_") {
		fprintf(f, "%s" "assign ", indent.c_str());
		dump_sigspec(f, cell->connections["\\Y"]);
		fprintf(f, " = ");
		fprintf(f, "~");
		dump_attributes(f, "", cell->attributes, ' ');
		dump_cell_expr_port(f, cell, "A", false);
		fprintf(f, ";\n");
		return true;
	}

	if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") {
		fprintf(f, "%s" "assign ", indent.c_str());
		dump_sigspec(f, cell->connections["\\Y"]);
		fprintf(f, " = ");
		dump_cell_expr_port(f, cell, "A", false);
		fprintf(f, " ");
		if (cell->type == "$_AND_")
			fprintf(f, "&");
		if (cell->type == "$_OR_")
			fprintf(f, "|");
		if (cell->type == "$_XOR_")
			fprintf(f, "^");
		dump_attributes(f, "", cell->attributes, ' ');
		fprintf(f, " ");
		dump_cell_expr_port(f, cell, "B", false);
		fprintf(f, ";\n");
		return true;
	}

	if (cell->type == "$_MUX_") {
		fprintf(f, "%s" "assign ", indent.c_str());
		dump_sigspec(f, cell->connections["\\Y"]);
		fprintf(f, " = ");
		dump_cell_expr_port(f, cell, "S", false);
		fprintf(f, " ? ");
		dump_attributes(f, "", cell->attributes, ' ');
		dump_cell_expr_port(f, cell, "B", false);
		fprintf(f, " : ");
		dump_cell_expr_port(f, cell, "A", false);
		fprintf(f, ";\n");
		return true;
	}

	if (cell->type.substr(0, 6) == "$_DFF_")
	{
		std::string reg_name = cellname(cell);
		bool out_is_reg_wire = is_reg_wire(cell->connections["\\Q"], reg_name);

		if (!out_is_reg_wire)
			fprintf(f, "%s" "reg %s;\n", indent.c_str(), reg_name.c_str());

		dump_attributes(f, indent, cell->attributes);
		fprintf(f, "%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
		dump_sigspec(f, cell->connections["\\C"]);
		if (cell->type[7] != '_') {
			fprintf(f, " or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
			dump_sigspec(f, cell->connections["\\R"]);
		}
		fprintf(f, ")\n");

		if (cell->type[7] != '_') {
			fprintf(f, "%s" "  if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
			dump_sigspec(f, cell->connections["\\R"]);
			fprintf(f, ")\n");
			fprintf(f, "%s" "    %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
			fprintf(f, "%s" "  else\n", indent.c_str());
		}

		fprintf(f, "%s" "    %s <= ", indent.c_str(), reg_name.c_str());
		dump_cell_expr_port(f, cell, "D", false);
		fprintf(f, ";\n");

		if (!out_is_reg_wire) {
			fprintf(f, "%s" "assign ", indent.c_str());
			dump_sigspec(f, cell->connections["\\Q"]);
			fprintf(f, " = %s;\n", reg_name.c_str());
		}

		return true;
	}

#define HANDLE_UNIOP(_type, _operator) \
	if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
#define HANDLE_BINOP(_type, _operator) \
	if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }

	HANDLE_UNIOP("$not", "~")
	HANDLE_UNIOP("$pos", "+")
	HANDLE_UNIOP("$neg", "-")

	HANDLE_BINOP("$and",  "&")
	HANDLE_BINOP("$or",   "|")
	HANDLE_BINOP("$xor",  "^")
	HANDLE_BINOP("$xnor", "~^")

	HANDLE_UNIOP("$reduce_and",  "&")
	HANDLE_UNIOP("$reduce_or",   "|")
	HANDLE_UNIOP("$reduce_xor",  "^")
	HANDLE_UNIOP("$reduce_xnor", "~^")
	HANDLE_UNIOP("$reduce_bool", "|")

	HANDLE_BINOP("$shl",  "<<")
	HANDLE_BINOP("$shr",  ">>")
	HANDLE_BINOP("$sshl", "<<<")
	HANDLE_BINOP("$sshr", ">>>")

	HANDLE_BINOP("$lt", "<")
	HANDLE_BINOP("$le", "<=")
	HANDLE_BINOP("$eq", "==")
	HANDLE_BINOP("$ne", "!=")
	HANDLE_BINOP("$ge", ">=")
	HANDLE_BINOP("$gt", ">")

	HANDLE_BINOP("$add", "+")
	HANDLE_BINOP("$sub", "-")
	HANDLE_BINOP("$mul", "*")
	HANDLE_BINOP("$div", "/")
	HANDLE_BINOP("$mod", "%")
	HANDLE_BINOP("$pow", "**")

	HANDLE_UNIOP("$logic_not", "!")
	HANDLE_BINOP("$logic_and", "&&")
	HANDLE_BINOP("$logic_or",  "||")

#undef HANDLE_UNIOP
#undef HANDLE_BINOP

	if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$pmux_safe")
	{
		int width = cell->parameters["\\WIDTH"].as_int();
		int s_width = cell->connections["\\S"].width;
		std::string reg_name = cellname(cell);
		fprintf(f, "%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());

		dump_attributes(f, indent, cell->attributes);
		if (!noattr)
			fprintf(f, "%s" "(* parallel_case *)\n", indent.c_str());
		fprintf(f, "%s" "always @*\n", indent.c_str());
		fprintf(f, "%s" "  casez (", indent.c_str());
		dump_sigspec(f, cell->connections["\\S"]);
		fprintf(f, noattr ? ") // synopsys parallel_case\n" : ")\n");

		for (int i = 0; i < s_width; i++)
		{
			fprintf(f, "%s" "    %d'b", indent.c_str(), s_width);

			for (int j = s_width-1; j >= 0; j--)
				fprintf(f, "%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');

			fprintf(f, ":\n");
			fprintf(f, "%s" "      %s = ", indent.c_str(), reg_name.c_str());

			RTLIL::SigSpec s = cell->connections["\\B"].extract(i * width, width);
			dump_sigspec(f, s);
			fprintf(f, ";\n");
		}

		fprintf(f, "%s" "    default:\n", indent.c_str());
		fprintf(f, "%s" "      %s = ", indent.c_str(), reg_name.c_str());
		dump_sigspec(f, cell->connections["\\A"]);
		fprintf(f, ";\n");

		fprintf(f, "%s" "  endcase\n", indent.c_str());
		fprintf(f, "%s" "assign ", indent.c_str());
		dump_sigspec(f, cell->connections["\\Y"]);
		fprintf(f, " = %s;\n", reg_name.c_str());
		return true;
	}

	if (cell->type == "$dff" || cell->type == "$adff")
	{
		RTLIL::SigSpec sig_clk, sig_arst, val_arst;
		bool pol_clk, pol_arst = false;

		sig_clk = cell->connections["\\CLK"];
		pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();

		if (cell->type == "$adff") {
			sig_arst = cell->connections["\\ARST"];
			pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
			val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
		}

		std::string reg_name = cellname(cell);
		bool out_is_reg_wire = is_reg_wire(cell->connections["\\Q"], reg_name);

		if (!out_is_reg_wire)
			fprintf(f, "%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());

		fprintf(f, "%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
		dump_sigspec(f, sig_clk);
		if (cell->type == "$adff") {
			fprintf(f, " or %sedge ", pol_arst ? "pos" : "neg");
			dump_sigspec(f, sig_arst);
		}
		fprintf(f, ")\n");

		if (cell->type == "$adff") {
			fprintf(f, "%s" "  if (%s", indent.c_str(), pol_arst ? "" : "!");
			dump_sigspec(f, sig_arst);
			fprintf(f, ")\n");
			fprintf(f, "%s" "    %s <= ", indent.c_str(), reg_name.c_str());
			dump_sigspec(f, val_arst);
			fprintf(f, ";\n");
			fprintf(f, "%s" "  else\n", indent.c_str());
		}

		fprintf(f, "%s" "    %s <= ", indent.c_str(), reg_name.c_str());
		dump_cell_expr_port(f, cell, "D", false);
		fprintf(f, ";\n");

		if (!out_is_reg_wire) {
			fprintf(f, "%s" "assign ", indent.c_str());
			dump_sigspec(f, cell->connections["\\Q"]);
			fprintf(f, " = %s;\n", reg_name.c_str());
		}

		return true;
	}

	// FIXME: $memrd, $memwr, $mem, $fsm

	return false;
}

void dump_cell(FILE *f, std::string indent, RTLIL::Cell *cell)
{
	if (cell->type[0] == '$' && !noexpr) {
		if (dump_cell_expr(f, indent, cell))
			return;
	}

	dump_attributes(f, indent, cell->attributes);
	fprintf(f, "%s" "%s", indent.c_str(), id(cell->type, false).c_str());

	if (cell->parameters.size() > 0) {
		fprintf(f, " #(");
		for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
			if (it != cell->parameters.begin())
				fprintf(f, ",");
			fprintf(f, "\n%s  .%s(", indent.c_str(), id(it->first).c_str());
			dump_const(f, it->second);
			fprintf(f, ")");
		}
		fprintf(f, "\n%s" ")", indent.c_str());
	}

	std::string cell_name = cellname(cell);
	if (cell_name != id(cell->name))
		fprintf(f, " %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
	else
		fprintf(f, " %s (", cell_name.c_str());

	bool first_arg = true;
	std::set<std::string> numbered_ports;
	for (int i = 1; true; i++) {
		char str[16];
		snprintf(str, 16, "$%d", i);
		for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
			if (it->first != str)
				continue;
			if (!first_arg)
				fprintf(f, ",");
			first_arg = false;
			fprintf(f, "\n%s  ", indent.c_str());
			dump_sigspec(f, it->second);
			numbered_ports.insert(it->first);
			goto found_numbered_port;
		}
		break;
	found_numbered_port:;
	}
	for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
		if (numbered_ports.count(it->first))
			continue;
		if (!first_arg)
			fprintf(f, ",");
		first_arg = false;
		fprintf(f, "\n%s  .%s(", indent.c_str(), id(it->first).c_str());
		if (it->second.width > 0)
			dump_sigspec(f, it->second);
		fprintf(f, ")");
	}
	fprintf(f, "\n%s" ");\n", indent.c_str());
}

void dump_conn(FILE *f, std::string indent, RTLIL::SigSpec &left, RTLIL::SigSpec &right)
{
	fprintf(f, "%s" "assign ", indent.c_str());
	dump_sigspec(f, left);
	fprintf(f, " = ");
	dump_sigspec(f, right);
	fprintf(f, ";\n");
}

void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw);

void dump_case_body(FILE *f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
{
	int number_of_stmts = cs->switches.size() + cs->actions.size();

	if (!omit_trailing_begin && number_of_stmts >= 2)
		fprintf(f, "%s" "begin\n", indent.c_str());

	for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
		if (it->first.width == 0)
			continue;
		fprintf(f, "%s  ", indent.c_str());
		dump_sigspec(f, it->first);
		fprintf(f, " = ");
		dump_sigspec(f, it->second);
		fprintf(f, ";\n");
	}

	for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
		dump_proc_switch(f, indent + "  ", *it);

	if (!omit_trailing_begin && number_of_stmts == 0)
		fprintf(f, "%s  /* empty */;\n", indent.c_str());

	if (omit_trailing_begin || number_of_stmts >= 2)
		fprintf(f, "%s" "end\n", indent.c_str());
}

void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw)
{
	if (sw->signal.width == 0) {
		fprintf(f, "%s" "begin\n", indent.c_str());
		for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
			if ((*it)->compare.size() == 0)
				dump_case_body(f, indent + "  ", *it);
		}
		fprintf(f, "%s" "end\n", indent.c_str());
		return;
	}

	fprintf(f, "%s" "casez (", indent.c_str());
	dump_sigspec(f, sw->signal);
	fprintf(f, ")\n");

	for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
		fprintf(f, "%s  ", indent.c_str());
		if ((*it)->compare.size() == 0)
			fprintf(f, "default");
		else {
			for (size_t i = 0; i < (*it)->compare.size(); i++) {
				if (i > 0)
					fprintf(f, ", ");
				dump_sigspec(f, (*it)->compare[i]);
			}
		}
		fprintf(f, ":\n");
		dump_case_body(f, indent + "    ", *it);
	}

	fprintf(f, "%s" "endcase\n", indent.c_str());
}

void case_body_find_regs(RTLIL::CaseRule *cs)
{
	for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
	for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
		case_body_find_regs(*it2);

	for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
		for (size_t i = 0; i < it->first.chunks.size(); i++)
			if (it->first.chunks[i].wire)
				reg_wires.insert(it->first.chunks[i].wire->name);
	}
}

void dump_process(FILE *f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
{
	if (find_regs) {
		case_body_find_regs(&proc->root_case);
		for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
		for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
			for (size_t i = 0; i < it2->first.chunks.size(); i++)
				if (it2->first.chunks[i].wire)
					reg_wires.insert(it2->first.chunks[i].wire->name);
		}
		return;
	}

	fprintf(f, "%s" "always @* begin\n", indent.c_str());
	dump_case_body(f, indent, &proc->root_case, true);

	std::string backup_indent = indent;

	for (size_t i = 0; i < proc->syncs.size(); i++)
	{
		RTLIL::SyncRule *sync = proc->syncs[i];
		indent = backup_indent;

		if (sync->type == RTLIL::STa) {
			fprintf(f, "%s" "always @* begin\n", indent.c_str());
		} else {
			fprintf(f, "%s" "always @(", indent.c_str());
			if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
				fprintf(f, "posedge ");
			if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
				fprintf(f, "negedge ");
			dump_sigspec(f, sync->signal);
			fprintf(f, ") begin\n");
		}
		std::string ends = indent + "end\n";
		indent += "  ";

		if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
			fprintf(f, "%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
			dump_sigspec(f, sync->signal);
			fprintf(f, ") begin\n");
			ends = indent + "end\n" + ends;
			indent += "  ";
		}

		if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
			for (size_t j = 0; j < proc->syncs.size(); j++) {
				RTLIL::SyncRule *sync2 = proc->syncs[j];
				if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
					fprintf(f, "%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
					dump_sigspec(f, sync2->signal);
					fprintf(f, ") begin\n");
					ends = indent + "end\n" + ends;
					indent += "  ";
				}
			}
		}

		for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
			if (it->first.width == 0)
				continue;
			fprintf(f, "%s  ", indent.c_str());
			dump_sigspec(f, it->first);
			fprintf(f, " <= ");
			dump_sigspec(f, it->second);
			fprintf(f, ";\n");
		}

		fprintf(f, "%s", ends.c_str());
	}
}

void dump_module(FILE *f, std::string indent, RTLIL::Module *module)
{
	reg_wires.clear();
	reset_auto_counter(module);
	active_module = module;

	for (auto it = module->processes.begin(); it != module->processes.end(); it++)
		dump_process(f, indent + "  ", it->second, true);

	if (!noexpr)
	{
		std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
		for (auto &it : module->cells)
		{
			RTLIL::Cell *cell = it.second;
			if (!reg_ct.cell_known(cell->type) || cell->connections.count("\\Q") == 0)
				continue;

			RTLIL::SigSpec sig = cell->connections["\\Q"];
			sig.optimize();

			if (sig.chunks.size() == 1 && sig.chunks[0].wire)
				for (int i = 0; i < sig.chunks[0].width; i++)
					reg_bits.insert(std::pair<RTLIL::Wire*,int>(sig.chunks[0].wire, sig.chunks[0].offset+i));
		}
		for (auto &it : module->wires)
		{
			RTLIL::Wire *wire = it.second;
			for (int i = 0; i < wire->width; i++)
				if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
					goto this_wire_aint_reg;
			reg_wires.insert(wire->name);
		this_wire_aint_reg:;
		}
	}

	dump_attributes(f, indent, module->attributes);
	fprintf(f, "%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
	bool keep_running = true;
	for (int port_id = 1; keep_running; port_id++) {
		keep_running = false;
		for (auto it = module->wires.begin(); it != module->wires.end(); it++) {
			RTLIL::Wire *wire = it->second;
			if (wire->port_id == port_id) {
				if (port_id != 1)
					fprintf(f, ", ");
				fprintf(f, "%s", id(wire->name).c_str());
				keep_running = true;
				continue;
			}
		}
	}
	fprintf(f, ");\n");

	for (auto it = module->wires.begin(); it != module->wires.end(); it++)
		dump_wire(f, indent + "  ", it->second);

	for (auto it = module->memories.begin(); it != module->memories.end(); it++)
		dump_memory(f, indent + "  ", it->second);

	for (auto it = module->cells.begin(); it != module->cells.end(); it++)
		dump_cell(f, indent + "  ", it->second);

	for (auto it = module->processes.begin(); it != module->processes.end(); it++)
		dump_process(f, indent + "  ", it->second);

	for (auto it = module->connections.begin(); it != module->connections.end(); it++)
		dump_conn(f, indent + "  ", it->first, it->second);

	fprintf(f, "%s" "endmodule\n", indent.c_str());
	active_module = NULL;
}

} /* namespace */

struct VerilogBackend : public Backend {
	VerilogBackend() : Backend("verilog") { }
	virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
	{
		log_header("Executing Verilog backend.\n");

		norename = false;
		noattr = false;
		attr2comment = false;
		noexpr = false;

		reg_ct.clear();
		reg_ct.setup_stdcells_mem();
		reg_ct.cell_types.insert("$dff");
		reg_ct.cell_types.insert("$adff");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			std::string arg = args[argidx];
			if (arg == "-norename") {
				norename = true;
				continue;
			}
			if (arg == "-noattr") {
				noattr = true;
				continue;
			}
			if (arg == "-attr2comment") {
				attr2comment = true;
				continue;
			}
			if (arg == "-noexpr") {
				noexpr = true;
				continue;
			}
			break;
		}
		extra_args(f, filename, args, argidx);

		for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
			log("Dumping module `%s'.\n", it->first.c_str());
			if (it != design->modules.begin())
				fprintf(f, "\n");
			dump_module(f, "", it->second);
		}

		reg_ct.clear();
	}
} VerilogBackend;