aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/ice40/ice40_ffssr.cc
blob: 9afbc0fce7c52b06abd3675c648fd037796d62b0 (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
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

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

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct Ice40FfssrPass : public Pass {
	Ice40FfssrPass() : Pass("ice40_ffssr", "iCE40: merge synchronous set/reset into FF cells") { }
	virtual void help()
	{
		log("\n");
		log("    ice40_ffssr [options] [selection]\n");
		log("\n");
		log("Merge synchronous set/reset $_MUX_ cells into iCE40 FFs.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			// if (args[argidx] == "-singleton") {
			// 	singleton_mode = true;
			// 	continue;
			// }
			break;
		}
		extra_args(args, argidx, design);

		pool<IdString> sb_dff_types;
		sb_dff_types.insert("\\SB_DFF");
		sb_dff_types.insert("\\SB_DFFE");
		sb_dff_types.insert("\\SB_DFFN");
		sb_dff_types.insert("\\SB_DFFNE");

		for (auto module : design->selected_modules())
		{
			log("Merging set/reset $_MUX_ cells into SB_FFs in %s.\n", log_id(module));

			SigMap sigmap(module);
			dict<SigBit, Cell*> sr_muxes;
			vector<Cell*> ff_cells;

			for (auto cell : module->selected_cells())
			{
				if (sb_dff_types.count(cell->type)) {
					ff_cells.push_back(cell);
					continue;
				}

				if (cell->type != "$_MUX_")
					continue;

				SigBit bit_a = sigmap(cell->getPort("\\A"));
				SigBit bit_b = sigmap(cell->getPort("\\B"));

				if (bit_a.wire == nullptr || bit_b.wire == nullptr)
					sr_muxes[sigmap(cell->getPort("\\Y"))] = cell;
			}

			for (auto cell : ff_cells)
			{
				SigSpec sig_d = cell->getPort("\\D");

				if (GetSize(sig_d) < 1)
					continue;

				SigBit bit_d = sigmap(sig_d[0]);

				if (sr_muxes.count(bit_d) == 0)
					continue;

				Cell *mux_cell = sr_muxes.at(bit_d);
				SigBit bit_a = sigmap(mux_cell->getPort("\\A"));
				SigBit bit_b = sigmap(mux_cell->getPort("\\B"));
				SigBit bit_s = sigmap(mux_cell->getPort("\\S"));

				log("  Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
						log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));

				SigBit sr_val, sr_sig;
				if (bit_a.wire == nullptr) {
					bit_d = bit_b;
					sr_val = bit_a;
					sr_sig = module->NotGate(NEW_ID, bit_s);
				} else {
					log_assert(bit_b.wire == nullptr);
					bit_d = bit_a;
					sr_val = bit_b;
					sr_sig = bit_s;
				}

				if (sr_val == State::S1) {
					cell->type = cell->type.str() + "SS";
					cell->setPort("\\S", sr_sig);
					cell->setPort("\\D", bit_d);
				} else {
					cell->type = cell->type.str() + "SR";
					cell->setPort("\\R", sr_sig);
					cell->setPort("\\D", bit_d);
				}
			}
		}
	}
} Ice40FfssrPass;

PRIVATE_NAMESPACE_END
="p">; while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) cpu_relax(); outb(ch, early_serial_base + TXR); return timeout ? 0 : -1; } static void early_serial_write(struct console *con, const char *s, unsigned n) { while (*s && n-- > 0) { early_serial_putc(*s); if (*s == '\n') early_serial_putc('\r'); s++; } } #define DEFAULT_BAUD 9600 static __init void early_serial_init(char *s) { unsigned char c; unsigned divisor; unsigned baud = DEFAULT_BAUD; char *e; if (*s == ',') ++s; if (*s) { unsigned port; if (!strncmp(s,"0x",2)) { early_serial_base = simple_strtoul(s, &e, 16); } else { static int bases[] = { 0x3f8, 0x2f8 }; if (!strncmp(s,"ttyS",4)) s += 4; port = simple_strtoul(s, &e, 10); if (port > 1 || s == e) port = 0; early_serial_base = bases[port]; } s += strcspn(s, ","); if (*s == ',') s++; } outb(0x3, early_serial_base + LCR); /* 8n1 */ outb(0, early_serial_base + IER); /* no interrupt */ outb(0, early_serial_base + FCR); /* no fifo */ outb(0x3, early_serial_base + MCR); /* DTR + RTS */ if (*s) { baud = simple_strtoul(s, &e, 0); if (baud == 0 || s == e) baud = DEFAULT_BAUD; } divisor = 115200 / baud; c = inb(early_serial_base + LCR); outb(c | DLAB, early_serial_base + LCR); outb(divisor & 0xff, early_serial_base + DLL); outb((divisor >> 8) & 0xff, early_serial_base + DLH); outb(c & ~DLAB, early_serial_base + LCR); } #else /* CONFIG_XEN */ #undef SCREEN_INFO #define SCREEN_INFO screen_info extern struct screen_info screen_info; static void early_serial_write(struct console *con, const char *s, unsigned count) { int n; while (count > 0) { n = HYPERVISOR_console_io(CONSOLEIO_write, count, (char *)s); if (n <= 0) break; count -= n; s += n; } } static __init void early_serial_init(char *s) { } /* * No early VGA console on Xen, as we do not have convenient ISA-space * mappings. Someone should fix this for domain 0. For now, use fake serial. */ #define early_vga_console early_serial_console #endif static struct console early_serial_console = { .name = "earlyser", .write = early_serial_write, .flags = CON_PRINTBUFFER, .index = -1, }; /* Console interface to a host file on AMD's SimNow! */ static int simnow_fd; enum { MAGIC1 = 0xBACCD00A, MAGIC2 = 0xCA110000, XOPEN = 5, XWRITE = 4, }; static noinline long simnow(long cmd, long a, long b, long c) { long ret; asm volatile("cpuid" : "=a" (ret) : "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); return ret; } void __init simnow_init(char *str) { char *fn = "klog"; if (*str == '=') fn = ++str; /* error ignored */ simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644); } static void simnow_write(struct console *con, const char *s, unsigned n) { simnow(XWRITE, simnow_fd, (unsigned long)s, n); } static struct console simnow_console = { .name = "simnow", .write = simnow_write, .flags = CON_PRINTBUFFER, .index = -1, }; /* Direct interface for emergencies */ struct console *early_console = &early_vga_console; static int early_console_initialized = 0; void early_printk(const char *fmt, ...) { char buf[512]; int n; va_list ap; va_start(ap,fmt); n = vscnprintf(buf,512,fmt,ap); early_console->write(early_console,buf,n); va_end(ap); } static int __initdata keep_early; int __init setup_early_printk(char *opt) { char *space; char buf[256]; if (early_console_initialized) return -1; strlcpy(buf,opt,sizeof(buf)); space = strchr(buf, ' '); if (space) *space = 0; if (strstr(buf,"keep")) keep_early = 1; if (!strncmp(buf, "serial", 6)) { early_serial_init(buf + 6); early_console = &early_serial_console; } else if (!strncmp(buf, "ttyS", 4)) { early_serial_init(buf); early_console = &early_serial_console; } else if (!strncmp(buf, "vga", 3) && SCREEN_INFO.orig_video_isVGA == 1) { max_xpos = SCREEN_INFO.orig_video_cols; max_ypos = SCREEN_INFO.orig_video_lines; early_console = &early_vga_console; } else if (!strncmp(buf, "simnow", 6)) { simnow_init(buf + 6); early_console = &simnow_console; keep_early = 1; } early_console_initialized = 1; register_console(early_console); return 0; } void __init disable_early_printk(void) { if (!early_console_initialized || !early_console) return; if (!keep_early) { printk("disabling early console\n"); unregister_console(early_console); early_console_initialized = 0; } else { printk("keeping early console\n"); } } __setup("earlyprintk=", setup_early_printk);