/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Claire Xenia Wolf * * 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/satgen.h" #include #include #include #include #ifdef YOSYS_ENABLE_ZLIB #include PRIVATE_NAMESPACE_BEGIN #define GZ_BUFFER_SIZE 8192 void decompress_gzip(const std::string &filename, std::stringstream &out) { char buffer[GZ_BUFFER_SIZE]; int bytes_read; gzFile gzf = gzopen(filename.c_str(), "rb"); while(!gzeof(gzf)) { bytes_read = gzread(gzf, reinterpret_cast(buffer), GZ_BUFFER_SIZE); out.write(buffer, bytes_read); } gzclose(gzf); } /* An output stream that uses a stringbuf to buffer data internally, using zlib to write gzip-compressed data every time the stream is flushed. */ class gzip_ostream : public std::ostream { public: gzip_ostream() : std::ostream(nullptr) { rdbuf(&outbuf); } bool open(const std::string &filename) { return outbuf.open(filename); } private: class gzip_streambuf : public std::stringbuf { public: gzip_streambuf() { }; bool open(const std::string &filename) { gzf = gzopen(filename.c_str(), "wb"); return gzf != nullptr; } virtual int sync() override { gzwrite(gzf, reinterpret_cast(str().c_str()), unsigned(str().size())); str(""); return 0; } virtual ~gzip_streambuf() { sync(); gzclose(gzf); } private: gzFile gzf = nullptr; } outbuf; }; PRIVATE_NAMESPACE_END #endif YOSYS_NAMESPACE_BEGIN #define MAX_REG_COUNT 1000 bool echo_mode = false; Pass *first_queued_pass; Pass *current_pass; std::map frontend_register; std::map pass_register; std::map backend_register; std::vector Frontend::next_args; Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help) { next_queued_pass = first_queued_pass; first_queued_pass = this; call_counter = 0; runtime_ns = 0; } void Pass::run_register() { log_assert(pass_register.count(pass_name) == 0); pass_register[pass_name] = this; } void Pass::init_register() { vector added_passes; while (first_queued_pass) { added_passes.push_back(first_queued_pass); first_queued_pass->run_register(); first_queued_pass = first_queued_pass->next_queued_pass; } for (auto added_pass : added_passes) added_pass->on_register(); } void Pass::done_register() { for (auto &it : pass_register) it.second->on_shutdown(); frontend_register.clear(); pass_register.clear(); backend_register.clear(); log_assert(first_queued_pass == NULL); } void Pass::on_register() { } void Pass::on_shutdown() { } Pass::~Pass() { } Pass::pre_post_exec_state_t Pass::pre_execute() { pre_post_exec_state_t state; call_counter++; state.begin_ns = PerformanceTimer::query(); state.parent_pass = current_pass; current_pass = this; clear_flags(); return state; } void Pass::post_execute(Pass::pre_post_exec_state_t state) { IdString::checkpoint(); log_suppressed(); int64_t time_ns = PerformanceTimer::query() - state.begin_ns; runtime_ns += time_ns; current_pass = state.parent_pass; if (current_pass) current_pass->runtime_ns -= time_ns; } void Pass::help() { log("\n"); log("No help message for command `%s'.\n", pass_name.c_str()); log("\n"); } void Pass::clear_flags() { } void Pass::cmd_log_args(const std::vector &args) { if (args.size() <= 1) return; log("Full command line:"); for (size_t i = 0; i < args.size(); i++) log(" %s", args[i].c_str()); log("\n"); } void Pass::cmd_error(const std::vector &args, size_t argidx, std::string msg) { std::string command_text; int error_pos = 0; for (size_t i = 0; i < args.size(); i++) { if (i < argidx) error_pos += args[i].size() + 1; command_text = command_text + (command_text.empty() ? "" : " ") + args[i]; } log("\nSyntax error in command `%s':\n", command_text.c_str()); help(); log_cmd_error("Command syntax error: %s\n> %s\n> %*s^\n", msg.c_str(), command_text.c_str(), error_pos, ""); } void Pass::extra_args(std::vector args, size_t argidx, RTLIL::Design *design, bool select) { for (; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg.compare(0, 1, "-") == 0) cmd_error(args, argidx, "Unknown option or option in arguments."); if (!select) cmd_error(args, argidx, "Extra argument."); handle_extra_select_args(this, args, argidx, args.size(), design); break; } // cmd_log_args(args); } void Pass::call(RTLIL::Design *design, std::string command) { std::vector args; std::string cmd_buf = command; std::string tok = next_token(cmd_buf, " \t\r\n", true); if (tok.empty()) return; if (tok[0] == '!') { #if !defined(YOSYS_DISABLE_SPAWN) cmd_buf = command.substr(command.find('!') + 1); while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) cmd_buf.resize(cmd_buf.size()-1); log_header(design, "Shell command: %s\n", cmd_buf.c_str()); int retCode = run_command(cmd_buf); if (retCode != 0) log_cmd_error("Shell command returned error code %d.\n", retCode); return; #else log_cmd_error("Shell is not available.\n"); #endif } while (!tok.empty()) { if (tok[0] == '#') { int stop; for (stop = 0; stop < GetSize(cmd_buf); stop++) if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n') break; cmd_buf = cmd_buf.substr(stop); } else if (tok.back() == ';') { int num_semikolon = 0; while (!tok.empty() && tok.back() == ';') tok.resize(tok.size()-1), num_semikolon++; if (!tok.empty()) args.push_back(tok); call(design, args); args.clear(); if (num_semikolon == 2) call(design, "clean"); if (num_semikolon == 3) call(design, "clean -purge"); } else args.push_back(tok); bool found_nl = false; for (auto c : cmd_buf) { if (c == ' ' || c == '\t') continue; if (c == '\r' || c == '\n') found_nl = true; break; } if (found_nl) { call(design, args); args.clear(); } tok = next_token(cmd_buf, " \t\r\n", true); } call(design, args); } void Pass::call(RTLIL::Design *design, std::vector args) { if (args.size() == 0 || args[0][0] == '#' || args[0][0] == ':') return; if (echo_mode) { log("%s", create_prompt(design, 0)); for (size_t i = 0; i < args.size(); i++) log("%s%s", i ? " " : "", args[i].c_str()); log("\n"); } if (pass_register.count(args[0]) == 0) log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str()); if (pass_register[args[0]]->experimental_flag) log_experimental("%s", args[0].c_str()); size_t orig_sel_stack_pos = design->selection_stack.size(); auto state = pass_register[args[0]]->pre_execute(); pass_register[args[0]]->execute(args, design); pass_register[args[0]]->post_execute(state); while (design->selection_stack.size() > orig_sel_stack_pos) design->selection_stack.pop_back(); } void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command) { std::string backup_selected_active_module = design->selected_active_module; design->selected_active_module.clear(); design->selection_stack.push_back(selection); Pass::call(design, command); design->selection_stack.pop_back(); design->selected_active_module = backup_selected_active_module; } void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector args) { std::string backup_selected_active_module = design->selected_active_module; design->selected_active_module.clear(); design->selection_stack.push_back(selection); Pass::call(design, args); design->selection_stack.pop_back(); design->selected_active_module = backup_selected_active_module; } void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command) { std::string backup_selected_active_module = design->selected_active_module; design->selected_active_module = module->name.str(); design->selection_stack.push_back(RTLIL::Selection(false)); design->selection_stack.back().select(module); Pass::call(design, command); design->selection_stack.pop_back(); design->selected_active_module = backup_selected_active_module; } void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector args) { std::string backup_selected_active_module = design->selected_active_module; design->selected_active_module = module->name.str(); design->selection_stack.push_back(RTLIL::Selection(false)); design->selection_stack.back().select(module); Pass::call(design, args); design->selection_stack.pop_back(); design->selected_active_module = backup_selected_active_module; } bool ScriptPass::check_label(std::string label, std::string info) { if (active_design == nullptr) { log("\n"); if (info.empty()) log(" %s:\n", label.c_str()); else log(" %s: %s\n", label.c_str(), info.c_str()); return true; } else { if (!active_run_from.empty() && active_run_from == active_run_to) { block_active = (label == active_run_from); } else { if (label == active_run_from) block_active = true; if (label == active_run_to) block_active = false; } return block_active; } } void ScriptPass::run(std::string command, std::string info) { if (active_design == nullptr) { if (info.empty()) log(" %s\n", command.c_str()); else log(" %s %s\n", command.c_str(), info.c_str()); } else { Pass::call(active_design, command); active_design->check(); } } void ScriptPass::run_nocheck(std::string command, std::string info) { if (active_design == nullptr) { if (info.empty()) log(" %s\n", command.c_str()); else log(" %s %s\n", command.c_str(), info.c_str()); } else { Pass::call(active_design, command); } } void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) { help_mode = false; active_design = design; block_active = run_from.empty(); active_run_from = run_from; active_run_to = run_to; script(); } void ScriptPass::help_script() { clear_flags(); help_mode = true; active_design = nullptr; block_active = true; active_run_from.clear(); active_run_to.clear(); script(); } Frontend::Frontend(std::string name, std::string short_help) : Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help), frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) { } void Frontend::run_register() { log_assert(pass_register.count(pass_name) == 0); pass_register[pass_name] = this; log_assert(frontend_register.count(frontend_name) == 0); frontend_register[frontend_name] = this; } Frontend::~Frontend() { } void Frontend::execute(std::vector args, RTLIL::Design *design) { log_assert(next_args.empty()); do { std::istream *f = NULL; next_args.clear(); auto state = pre_execute(); execute(f, std::string(), args, design); post_execute(state); args = next_args; delete f; } while (!args.empty()); } FILE *Frontend::current_script_file = NULL; std::string Frontend::last_here_document; void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector args, size_t argidx, bool bin_input) { bool called_with_fp = f != NULL; next_args.clear(); if (argidx < args.size()) { std::string arg = args[argidx]; if (arg.compare(0, 1, "-") == 0) cmd_error(args, argidx, "Unknown option or option in arguments."); if (f != NULL) cmd_error(args, argidx, "Extra filename argument in direct file mode."); filename = arg; //Accommodate heredocs with EOT marker spaced out from "<<", e.g. "<< EOT" vs. "< 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r')) break; } size_t indent = buffer.find_first_not_of(" \t\r\n"); if (indent != std::string::npos && buffer.compare(indent, eot_marker.size(), eot_marker) == 0) break; last_here_document += buffer; } f = new std::istringstream(last_here_document); } else { rewrite_filename(filename); vector filenames = glob_filename(filename); filename = filenames.front(); if (GetSize(filenames) > 1) { next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); next_args.insert(next_args.end(), filenames.begin()+1, filenames.end()); } std::ifstream *ff = new std::ifstream; ff->open(filename.c_str(), bin_input ? std::ifstream::binary : std::ifstream::in); yosys_input_files.insert(filename); if (ff->fail()) delete ff; else f = ff; if (f != NULL) { // Check for gzip magic unsigned char magic[3]; int n = 0; while (n < 3) { int c = ff->get(); if (c != EOF) { magic[n] = (unsigned char) c; } n++; } if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { #ifdef YOSYS_ENABLE_ZLIB log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); if (magic[2] != 8) log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n", filename.c_str(), unsigned(magic[2])); delete ff; std::stringstream *df = new std::stringstream(); decompress_gzip(filename, *df); f = df; #else log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); #endif } else { ff->clear(); ff->seekg(0, std::ios::beg); } } } if (f == NULL) log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); for (size_t i = argidx+1; i < args.size(); i++) if (args[i].compare(0, 1, "-") == 0) cmd_error(args, i, "Found option, expected arguments."); if (argidx+1 < args.size()) { if (next_args.empty()) next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); next_args.insert(next_args.end(), args.begin()+argidx+1, args.end()); args.erase(args.begin()+argidx+1, args.end()); } } if (f == NULL) cmd_error(args, argidx, "No filename given."); if (called_with_fp) args.push_back(filename); args[0] = pass_name; // cmd_log_args(args); } void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command) { std::vector args; char *s = strdup(command.c_str()); for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n
// Ultrascale and Ultrascale Plus block RAM mapping.

module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
	parameter CLKPOL2 = 1;
	parameter CLKPOL3 = 1;
	parameter [36863:0] INIT = 36864'bx;

	input CLK2;
	input CLK3;

	input [8:0] A1ADDR;
	output [71:0] A1DATA;
	input A1EN;

	input [8:0] B1ADDR;
	input [71:0] B1DATA;
	input [7:0] B1EN;

	wire [15:0] A1ADDR_16 = {A1ADDR, 6'b0};
	wire [15:0] B1ADDR_16 = {B1ADDR, 6'b0};

	wire [7:0] DIP, DOP;
	wire [63:0] DI, DO;

	assign A1DATA = { DOP[7], DO[63:56], DOP[6], DO[55:48], DOP[5], DO[47:40], DOP[4], DO[39:32],
	                  DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };

	assign { DIP[7], DI[63:56], DIP[6], DI[55:48], DIP[5], DI[47:40], DIP[4], DI[39:32],
	         DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;

	RAMB36E2 #(
		.READ_WIDTH_A(72),
		.WRITE_WIDTH_B(72),
		.WRITE_MODE_A("READ_FIRST"),
		.WRITE_MODE_B("READ_FIRST"),
		.DOA_REG(0),
		.DOB_REG(0),
		.IS_CLKARDCLK_INVERTED(!CLKPOL2),
		.IS_CLKBWRCLK_INVERTED(!CLKPOL3),
		`include "brams_init_36.vh"
	) _TECHMAP_REPLACE_ (
		.DOUTBDOUT(DO[63:32]),
		.DOUTADOUT(DO[31:0]),
		.DOUTPBDOUTP(DOP[7:4]),
		.DOUTPADOUTP(DOP[3:0]),
		.DINBDIN(DI[63:32]),
		.DINADIN(DI[31:0]),
		.DINPBDINP(DIP[7:4]),
		.DINPADINP(DIP[3:0]),

		.ADDRARDADDR(A1ADDR_16),
		.CLKARDCLK(CLK2),
		.ENARDEN(A1EN),
		.ADDRENA(|1),
		.REGCEAREGCE(|1),
		.RSTRAMARSTRAM(|0),
		.RSTREGARSTREG(|0),
		.WEA(4'b0),

		.ADDRBWRADDR(B1ADDR_16),
		.CLKBWRCLK(CLK3),
		.ENBWREN(|1),
		.ADDRENB(|1),
		.REGCEB(|1),
		.RSTRAMB(|0),
		.RSTREGB(|0),
		.WEBWE(B1EN),

		.SLEEP(|0)
	);
endmodule

// ------------------------------------------------------------------------

module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
	parameter CLKPOL2 = 1;
	parameter CLKPOL3 = 1;
	parameter [18431:0] INIT = 18432'bx;

	input CLK2;
	input CLK3;

	input [8:0] A1ADDR;
	output [35:0] A1DATA;
	input A1EN;

	input [8:0] B1ADDR;
	input [35:0] B1DATA;
	input [3:0] B1EN;

	wire [13:0] A1ADDR_14 = {A1ADDR, 5'b0};
	wire [13:0] B1ADDR_14 = {B1ADDR, 5'b0};

	wire [3:0] DIP, DOP;
	wire [31:0] DI, DO;

	assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
	assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;

	RAMB18E2 #(
		.READ_WIDTH_A(36),
		.WRITE_WIDTH_B(36),
		.WRITE_MODE_A("READ_FIRST"),
		.WRITE_MODE_B("READ_FIRST"),
		.DOA_REG(0),
		.DOB_REG(0),
		.IS_CLKARDCLK_INVERTED(!CLKPOL2),
		.IS_CLKBWRCLK_INVERTED(!CLKPOL3),
		`include "brams_init_18.vh"
	) _TECHMAP_REPLACE_ (
		.DOUTBDOUT(DO[31:16]),
		.DOUTADOUT(DO[15:0]),
		.DOUTPBDOUTP(DOP[3:2]),
		.DOUTPADOUTP(DOP[1:0]),
		.DINBDIN(DI[31:16]),
		.DINADIN(DI[15:0]),
		.DINPBDINP(DIP[3:2]),
		.DINPADINP(DIP[1:0]),

		.ADDRARDADDR(A1ADDR_14),
		.CLKARDCLK(CLK2),
		.ENARDEN(A1EN),
		.ADDRENA(|1),
		.REGCEAREGCE(|1),
		.RSTRAMARSTRAM(|0),
		.RSTREGARSTREG(|0),
		.WEA(2'b0),

		.ADDRBWRADDR(B1ADDR_14),
		.CLKBWRCLK(CLK3),
		.ENBWREN(|1),
		.ADDRENB(|1),
		.REGCEB(|1),
		.RSTRAMB(|0),
		.RSTREGB(|0),
		.WEBWE(B1EN),

		.SLEEP(|0)
	);
endmodule

// ------------------------------------------------------------------------

module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
	parameter CFG_ABITS = 10;
	parameter CFG_DBITS = 36;
	parameter CFG_ENABLE_B = 4;

	parameter CLKPOL2 = 1;
	parameter CLKPOL3 = 1;
	parameter [36863:0] INIT = 36864'bx;

	input CLK2;
	input CLK3;

	input [CFG_ABITS-1:0] A1ADDR;
	output [CFG_DBITS-1:0] A1DATA;
	input A1EN;

	input [CFG_ABITS-1:0] B1ADDR;
	input [CFG_DBITS-1:0] B1DATA;
	input [CFG_ENABLE_B-1:0] B1EN;

	wire [15:0] A1ADDR_16 = A1ADDR << (15 - CFG_ABITS);
	wire [15:0] B1ADDR_16 = B1ADDR << (15 - CFG_ABITS);
	wire [7:0] B1EN_8 = B1EN;

	wire [3:0] DIP, DOP;
	wire [31:0] DI, DO;

	wire [31:0] DOBDO;
	wire [3:0] DOPBDOP;

	assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
	assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;

	generate if (CFG_DBITS > 8) begin
		RAMB36E2 #(
			.READ_WIDTH_A(CFG_DBITS),
			.READ_WIDTH_B(CFG_DBITS),
			.WRITE_WIDTH_A(CFG_DBITS),
			.WRITE_WIDTH_B(CFG_DBITS),
			.WRITE_MODE_A("READ_FIRST"),
			.WRITE_MODE_B("READ_FIRST"),
			.DOA_REG(0),
			.DOB_REG(0),
			.IS_CLKARDCLK_INVERTED(!CLKPOL2),
			.IS_CLKBWRCLK_INVERTED(!CLKPOL3),
			`include "brams_init_36.vh"
		) _TECHMAP_REPLACE_ (
			.DINADIN(32'hFFFFFFFF),
			.DINPADINP(4'hF),
			.DOUTADOUT(DO[31:0]),
			.DOUTPADOUTP(DOP[3:0]),
			.ADDRARDADDR(A1ADDR_16),
			.CLKARDCLK(CLK2),
			.ENARDEN(A1EN),
			.ADDRENA(|1),
			.REGCEAREGCE(|1),
			.RSTRAMARSTRAM(|0),
			.RSTREGARSTREG(|0),
			.WEA(4'b0),

			.DINBDIN(DI),
			.DINPBDINP(DIP),
			.DOUTBDOUT(DOBDO),
			.DOUTPBDOUTP(DOPBDOP),
			.ADDRBWRADDR(B1ADDR_16),
			.CLKBWRCLK(CLK3),
			.ENBWREN(|1),
			.ADDRENB(|1),
			.REGCEB(|0),
			.RSTRAMB(|0),
			.RSTREGB(|0),
			.WEBWE(B1EN_8),

			.SLEEP(|0)
		);
	end else begin
		RAMB36E2 #(
			.READ_WIDTH_A(CFG_DBITS),
			.READ_WIDTH_B(CFG_DBITS),
			.WRITE_WIDTH_A(CFG_DBITS),
			.WRITE_WIDTH_B(CFG_DBITS),
			.WRITE_MODE_A("READ_FIRST"),
			.WRITE_MODE_B("READ_FIRST"),
			.DOA_REG(0),
			.DOB_REG(0),
			.IS_CLKARDCLK_INVERTED(!CLKPOL2),
			.IS_CLKBWRCLK_INVERTED(!CLKPOL3),
			`include "brams_init_32.vh"
		) _TECHMAP_REPLACE_ (
			.DINADIN(32'hFFFFFFFF),
			.DINPADINP(4'hF),
			.DOUTADOUT(DO[31:0]),
			.DOUTPADOUTP(DOP[3:0]),
			.ADDRARDADDR(A1ADDR_16),
			.CLKARDCLK(CLK2),
			.ENARDEN(A1EN),
			.ADDRENA(|1),
			.REGCEAREGCE(|1),
			.RSTRAMARSTRAM(|0),
			.RSTREGARSTREG(|0),
			.WEA(4'b0),

			.DINBDIN(DI),
			.DINPBDINP(DIP),
			.DOUTBDOUT(DOBDO),
			.DOUTPBDOUTP(DOPBDOP),
			.ADDRBWRADDR(B1ADDR_16),
			.CLKBWRCLK(CLK3),
			.ENBWREN(|1),
			.ADDRENB(|1),
			.REGCEB(|0),
			.RSTRAMB(|0),
			.RSTREGB(|0),
			.WEBWE(B1EN_8),

			.SLEEP(|0)
		);
	end endgenerate
endmodule

// ------------------------------------------------------------------------

module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
	parameter CFG_ABITS = 10;
	parameter CFG_DBITS = 18;
	parameter CFG_ENABLE_B = 2;

	parameter CLKPOL2 = 1;
	parameter CLKPOL3 = 1;
	parameter [18431:0] INIT = 18432'bx;

	input CLK2;
	input CLK3;

	input [CFG_ABITS-1:0] A1ADDR;
	output [CFG_DBITS-1:0] A1DATA;
	input A1EN;

	input [CFG_ABITS-1:0] B1ADDR;
	input [CFG_DBITS-1:0] B1DATA;
	input [CFG_ENABLE_B-1:0] B1EN;

	wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS);
	wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS);
	wire [3:0] B1EN_4 = B1EN;

	wire [1:0] DIP, DOP;
	wire [15:0] DI, DO;

	wire [15:0] DOBDO;
	wire [1:0] DOPBDOP;

	assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
	assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;

	generate if (CFG_DBITS > 8) begin
		RAMB18E2 #(
			.READ_WIDTH_A(CFG_DBITS),
			.READ_WIDTH_B(CFG_DBITS),
			.WRITE_WIDTH_A(CFG_DBITS),
			.WRITE_WIDTH_B(CFG_DBITS),
			.WRITE_MODE_A("READ_FIRST"),
			.WRITE_MODE_B("READ_FIRST"),
			.DOA_REG(0),
			.DOB_REG(0),
			.IS_CLKARDCLK_INVERTED(!CLKPOL2),
			.IS_CLKBWRCLK_INVERTED(!CLKPOL3),
			`include "brams_init_18.vh"
		) _TECHMAP_REPLACE_ (
			.DINADIN(16'hFFFF),
			.DINPADINP(2'b11),
			.DOUTADOUT(DO),
			.DOUTPADOUTP(DOP),
			.ADDRARDADDR(A1ADDR_14),
			.CLKARDCLK(CLK2),
			.ENARDEN(A1EN),
			.ADDRENA(|1),
			.REGCEAREGCE(|1),
			.RSTRAMARSTRAM(|0),
			.RSTREGARSTREG(|0),
			.WEA(2'b0),

			.DINBDIN(DI),
			.DINPBDINP(DIP),
			.DOUTBDOUT(DOBDO),
			.DOUTPBDOUTP(DOPBDOP),
			.ADDRBWRADDR(B1ADDR_14),
			.CLKBWRCLK(CLK3),
			.ENBWREN(|1),
			.ADDRENB(|1),
			.REGCEB(|0),
			.RSTRAMB(|0),
			.RSTREGB(|0),
			.WEBWE(B1EN_4),

			.SLEEP(|0)
		);
	end else begin
		RAMB18E2 #(
			//.RAM_MODE("TDP"),
			.READ_WIDTH_A(CFG_DBITS),
			.READ_WIDTH_B(CFG_DBITS),
			.WRITE_WIDTH_A(CFG_DBITS),
			.WRITE_WIDTH_B(CFG_DBITS),
			.WRITE_MODE_A("READ_FIRST"),
			.WRITE_MODE_B("READ_FIRST"),
			.DOA_REG(0),
			.DOB_REG(0),
			.IS_CLKARDCLK_INVERTED(!CLKPOL2),
			.IS_CLKBWRCLK_INVERTED(!CLKPOL3),
			`include "brams_init_16.vh"
		) _TECHMAP_REPLACE_ (
			.DINADIN(16'hFFFF),
			.DINPADINP(2'b11),
			.DOUTADOUT(DO),
			.DOUTPADOUTP(DOP),
			.ADDRARDADDR(A1ADDR_14),
			.CLKARDCLK(CLK2),
			.ENARDEN(A1EN),
			.ADDRENA(|1),
			.REGCEAREGCE(|1),
			.RSTRAMARSTRAM(|0),
			.RSTREGARSTREG(|0),
			.WEA(2'b0),

			.DINBDIN(DI),
			.DINPBDINP(DIP),
			.DOUTBDOUT(DOBDO),
			.DOUTPBDOUTP(DOPBDOP),
			.ADDRBWRADDR(B1ADDR_14),
			.CLKBWRCLK(CLK3),
			.ENBWREN(|1),
			.ADDRENB(|1),
			.REGCEB(|0),
			.RSTRAMB(|0),
			.RSTREGB(|0),
			.WEBWE(B1EN_4),

			.SLEEP(|0)
		);
	end endgenerate
endmodule