/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford 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/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" #include "kernel/log.h" #include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct Smt2Worker { CellTypes ct; SigMap sigmap; RTLIL::Module *module; bool bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode; dict &mod_stbv_width; int idcounter = 0, statebv_width = 0; std::vector decls, trans, hier, dtmembers; std::map bit_driver; std::set exported_cells, hiercells, hiercells_queue; pool recursive_cells, registers; pool clock_posedge, clock_negedge; vector ex_state_eq, ex_input_eq; std::map> fcache; std::map memarrays; std::map bvsizes; dict ids; const char *get_id(IdString n) { if (ids.count(n) == 0) { std::string str = log_id(n); for (int i = 0; i < GetSize(str); i++) { if (str[i] == '\\') str[i] = '/'; } ids[n] = strdup(str.c_str()); } return ids[n]; } template const char *get_id(T *obj) { return get_id(obj->name); } void makebits(std::string name, int width = 0, std::string comment = std::string()) { std::string decl_str; if (statebv) { if (width == 0) { decl_str = stringf("(define-fun |%s| ((state |%s_s|)) Bool (= ((_ extract %d %d) state) #b1))", name.c_str(), get_id(module), statebv_width, statebv_width); statebv_width += 1; } else { decl_str = stringf("(define-fun |%s| ((state |%s_s|)) (_ BitVec %d) ((_ extract %d %d) state))", name.c_str(), get_id(module), width, statebv_width+width-1, statebv_width); statebv_width += width; } } else if (statedt) { if (width == 0) { decl_str = stringf(" (|%s| Bool)", name.c_str()); } else { decl_str = stringf(" (|%s| (_ BitVec %d))", name.c_str(), width); } } else { if (width == 0) { decl_str = stringf("(declare-fun |%s| (|%s_s|) Bool)", name.c_str(), get_id(module)); } else { decl_str = stringf("(declare-fun |%s| (|%s_s|) (_ BitVec %d))", name.c_str(), get_id(module), width); } } if (!comment.empty()) decl_str += " ; " + comment; if (statedt) dtmembers.push_back(decl_str + "\n"); else decls.push_back(decl_str + "\n"); } Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool wiresmode, bool verbose, bool statebv, bool statedt, bool forallmode, dict &mod_stbv_width, dict>> &mod_clk_cache) : ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode), wiresmode(wiresmode), verbose(verbose), statebv(statebv), statedt(statedt), forallmode(forallmode), mod_stbv_width(mod_stbv_width) { pool noclock; makebits(stringf("%s_is", get_id(module))); for (auto cell : module->cells()) for (auto &conn : cell->connections()) { if (GetSize(conn.second) == 0) continue; bool is_input = ct.cell_input(cell->type, conn.first); bool is_output = ct.cell_output(cell->type, conn.first); if (is_output && !is_input) for (auto bit : sigmap(conn.second)) { if (bit_driver.count(bit)) log_error("Found multiple drivers for %s.\n", log_signal(bit)); bit_driver[bit] = cell; } else if (is_output || !is_input) log_error("Unsupported or unknown directionality on port %s of cell %s.%s (%s).\n", log_id(conn.first), log_id(module), log_id(cell), log_id(cell->type)); if (cell->type.in("$mem") && conn.first.in("\\RD_CLK", "\\WR_CLK")) { SigSpec clk = sigmap(conn.second); for (int i = 0; i < GetSize(clk); i++) { if (clk[i].wire == nullptr) continue; if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_ENABLE" : "\\WR_CLK_ENABLE")[i] != State::S1) continue; if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_POLARITY" : "\\WR_CLK_POLARITY")[i] == State::S1) clock_posedge.insert(clk[i]); else clock_negedge.insert(clk[i]); } } else if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_") && conn.first.in("\\CLK", "\\C")) { bool posedge = (cell->type == "$_DFF_N_") || (cell->type == "$dff" && cell->getParam("\\CLK_POLARITY").as_bool()); for (auto bit : sigmap(conn.second)) { if (posedge) clock_posedge.insert(bit); else clock_negedge.insert(bit); } } else if (mod_clk_cache.count(cell->type) && mod_clk_cache.at(cell->type).count(conn.first)) { for (auto bit : sigmap(conn.second)) { if (mod_clk_cache.at(cell->type).at(conn.first).first) clock_posedge.insert(bit); if (mod_clk_cache.at(cell->type).at(conn.first).second) clock_negedge.insert(bit); } } else { for (auto bit : sigmap(conn.second)) noclock.insert(bit); } } for (auto bit : noclock) { clock_posedge.erase(bit); clock_negedge.erase(bit); } for (auto wire : module->wires()) { if (!wire->port_input || GetSize(wire) != 1) continue; SigBit bit = sigmap(wire); if (clock_posedge.count(bit)) mod_clk_cache[module->name][wire->name].first = true; if (clock_negedge.count(bit)) mod_clk_cache[module->name][wire->name].second = true; } } ~Smt2Worker() { for (auto &it : ids) free(it.second); ids.clear(); } const char *get_id(Module *m) { return get_id(m->name); } const char *get_id(Cell *c) { return get_id(c->name); } const char *get_id(Wire *w) { return get_id(w->name); } void register_bool(RTLIL::SigBit bit, int id) { if (verbose) log("%*s-> register_bool: %s %d\n", 2+2*GetSize(recursive_cells), "", log_signal(bit), id); sigmap.apply(bit); log_assert(fcache.count(bit) == 0); fcache[bit] = std::pair(id, -1); } void register_bv(RTLIL::SigSpec sig, int id) { if (verbose) log("%*s-> register_bv: %s %d\n", 2+2*GetSize(recursive_cells), "", log_signal(sig), id); log_assert(bvmode); sigmap.apply(sig); log_assert(bvsizes.count(id) == 0); bvsizes[id] = GetSize(sig); for (int i = 0; i < GetSize(sig); i++) { log_assert(fcache.count(sig[i]) == 0); fcache[sig[i]] = std::pair(id, i); } } void register_boolvec(RTLIL::SigSpec sig, int id) { if (verbose) log("%*s-> register_boolvec: %s %d\n", 2+2*GetSize(recursive_cells), "", log_signal(sig), id); log_assert(bvmode); sigmap.apply(sig); register_bool(sig[0], id); for (int i = 1; i < GetSize(sig); i++) sigmap.add(sig[i], RTLIL::State::S0); } std::string get_bool(RTLIL::SigBit bit, const char *state_name = "state") { sigmap.apply(bit); if (bit.wire == nullptr) return bit == RTLIL::State::S1 ? "true" : "false"; if (bit_driver.count(bit)) export_cell(bit_driver.at(bit)); sigmap.apply(bit); if (fcache.count(bit) == 0) { if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "", log_signal(bit)); makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(bit)); register_bool(bit, idcounter++); } auto f = fcache.at(bit); if (f.second >= 0) return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, get_id(module), f.first, state_name); return stringf("(|%s#%d| %s)", get_id(module), f.first, state_name); } std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state") { return get_bool(sig.as_bit(), state_name); } std::string get_bv(RTLIL::SigSpec sig, const char *state_name = "state") { log_assert(bvmode); sigmap.apply(sig); std::vector subexpr; SigSpec orig_sig; while (orig_sig != sig) { for (auto bit : sig) if (bit_driver.count(bit)) export_cell(bit_driver.at(bit)); orig_sig = sig; sigmap.apply(sig); } for (int i = 0, j = 1; i < GetSize(sig); i += j, j = 1) { if (sig[i].wire == nullptr) { while (i+j < GetSize(sig) && sig[i+j].wire == nullptr) j++; subexpr.push_back("#b"); for (int k = i+j-1; k >= i; k--) subexpr.back() += sig[k] == RTLIL::State::S1 ? "1" : "0"; continue; } if (fcache.count(sig[i]) && fcache.at(sig[i]).second == -1) { subexpr.push_back(stringf("(ite %s #b1 #b0)", get_bool(sig[i], state_name).c_str())); continue; } if (fcache.count(sig[i])) { auto t1 = fcache.at(sig[i]); while (i+j < GetSize(sig)) { if (fcache.count(sig[i+j]) == 0) break; auto t2 = fcache.at(sig[i+j]); if (t1.first != t2.first) break; if (t1.second+j != t2.second) break; j++; } if (t1.second == 0 && j == bvsizes.at(t1.first)) subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), t1.first, state_name)); else subexpr.push_back(stringf("((_ extract %d %d) (|%s#%d| %s))", t1.second + j - 1, t1.second, get_id(module), t1.first, state_name)); continue; } std::set seen_bits = { sig[i] }; while (i+j < GetSize(sig) && sig[i+j].wire && !fcache.count(sig[i+j]) && !seen_bits.count(sig[i+j])) seen_bits.insert(sig[i+j]), j++; if (verbose) log("%*s-> external bv: %s\n", 2+2*GetSize(recursive_cells), "", log_signal(sig.extract(i, j))); for (auto bit : sig.extract(i, j)) log_assert(bit_driver.count(bit) == 0); makebits(stringf("%s#%d", get_id(module), idcounter), j, log_signal(sig.extract(i, j))); subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), idcounter, state_name)); register_bv(sig.extract(i, j), idcounter++); } if (GetSize(subexpr) > 1) { std::string expr = "", end_str = ""; for (int i = GetSize(subexpr)-1; i >= 0; i--) { if (i > 0) expr += " (concat", end_str += ")"; expr += " " + subexpr[i]; } return expr.substr(1) + end_str; } else { log_assert(GetSize(subexpr) == 1); return subexpr[0]; } } void export_gate(RTLIL::Cell *cell, std::string expr) { RTLIL::SigBit bit = sigmap(cell->getPort("\\Y").as_bit()); std::string processed_expr; for (char ch : expr) { if (ch == 'A') processed_expr += get_bool(cell->getPort("\\A")); else if (ch == 'B') processed_expr += get_bool(cell->getPort("\\B")); else if (ch == 'C') processed_expr += get_bool(cell->getPort("\\C")); else if (ch == 'D') processed_expr += get_bool(cell->getPort("\\D")); else if (ch == 'S') processed_expr += get_bool(cell->getPort("\\S")); else processed_expr += ch; } if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(bit))); register_bool(bit, idcounter++); recursive_cells.erase(cell); } void export_bvop(RTLIL::Cell *cell, std::string expr, char type = 0) { RTLIL::SigSpec sig_a, sig_b; RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); int width = GetSize(sig_y); if (type == 's' || type == 'd' || type == 'b') { width = max(width, GetSize(cell->getPort("\\A"))); if (cell->hasPort("\\B")) width = max(width, GetSize(cell->getPort("\\B"))); } if (cell->hasPort("\\A")) { sig_a = cell->getPort("\\A"); sig_a.extend_u0(width, is_signed); } if (cell->hasPort("\\B")) { sig_b = cell->getPort("\\B"); sig_b.extend_u0(width, is_signed && !(type == 's')); } std::string processed_expr; for (char ch : expr) { if (ch == 'A') processed_expr += get_bv(sig_a); else if (ch == 'B') processed_expr += get_bv(sig_b); else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B")); else if (ch == 'L') processed_expr += is_signed ? "a" : "l"; else if (ch == 'U') processed_expr += is_signed ? "s" : "u"; else processed_expr += ch; } if (width != GetSize(sig_y) && type != 'b') processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str()); if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); if (type == 'b') { decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y))); register_boolvec(sig_y, idcounter++); } else { decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", get_id(module), idcounter, get_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y))); register_bv(sig_y, idcounter++); } recursive_cells.erase(cell); } void export_reduce(RTLIL::Cell *cell, std::string expr, bool identity_val) { RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); std::string processed_expr; for (char ch : expr) if (ch == 'A' || ch == 'B') { RTLIL::SigSpec sig = sigmap(cell->getPort(stringf("\\%c", ch))); for (auto bit : sig) processed_expr += " " + get_bool(bit); if (GetSize(sig) == 1) processed_expr += identity_val ? " true" : " false"; } else processed_expr += ch; if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y))); register_boolvec(sig_y, idcounter++); recursive_cells.erase(cell); } void export_cell(RTLIL::Cell *cell) { if (verbo
`timescale 1ns / 1ps

module testbench;
	parameter integer A0REG = 1;
	parameter integer A1REG = 1;
	parameter integer B0REG = 1;
	parameter integer B1REG = 1;
	parameter integer CREG = 1;
	parameter integer DREG = 1;
	parameter integer MREG = 1;
	parameter integer PREG = 1;
	parameter integer CARRYINREG = 1;
	parameter integer CARRYOUTREG = 1;
	parameter integer OPMODEREG = 1;
	parameter CARRYINSEL = "OPMODE5";
	parameter RSTTYPE = "SYNC";

	reg CLK;
	reg CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE;
	reg RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE;
	reg [17:0] A;
	reg [17:0] B;
	reg [47:0] C;
	reg [17:0] D;
	reg [47:0] PCIN;
	reg [7:0] OPMODE;
	reg CARRYIN;

	output CARRYOUTF, REF_CARRYOUTF;
	output CARRYOUT, REF_CARRYOUT, REF_OLD_CARRYOUT;
	output [35:0] M, REF_M;
	output [47:0] P, REF_P, REF_OLD_P;
	output [17:0] BCOUT, REF_BCOUT, REF_OLD_BCOUT;
	output [47:0] PCOUT, REF_PCOUT, REF_OLD_PCOUT;

	integer errcount = 0;

	reg ERROR_FLAG = 0;

	task clkcycle;
		begin
			#5;
			CLK = ~CLK;
			#10;
			CLK = ~CLK;
			#2;
			ERROR_FLAG = 0;
			if (REF_BCOUT !== BCOUT || REF_OLD_BCOUT != BCOUT) begin
				$display("ERROR at %1t: REF_BCOUT=%b REF_OLD_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, REF_OLD_BCOUT, BCOUT, REF_BCOUT ^ BCOUT);
				errcount = errcount + 1;
				ERROR_FLAG = 1;
			end
			if (REF_M !== M) begin
				$display("ERROR at %1t: REF_M=%b UUT_M=%b DIFF=%b", $time, REF_M, M, REF_M ^ M);
				errcount = errcount + 1;
				ERROR_FLAG = 1;
			end
			if (REF_P !== P || REF_OLD_P != P) begin
				$display("ERROR at %1t: REF_P=%b REF_OLD_P=%b UUT_P=%b DIFF=%b", $time, REF_P, REF_OLD_P, P, REF_P ^ P);
				errcount = errcount + 1;
				ERROR_FLAG = 1;
			end
			if (REF_PCOUT !== PCOUT || REF_OLD_PCOUT != PCOUT) begin
				$display("ERROR at %1t: REF_PCOUT=%b REF_OLD_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, REF_OLD_PCOUT, PCOUT, REF_PCOUT ^ PCOUT);
				errcount = errcount + 1;
				ERROR_FLAG = 1;
			end
			if (REF_CARRYOUT !== CARRYOUT || (REF_OLD_CARRYOUT != CARRYOUT && !CARRYOUTREG)) begin
				$display("ERROR at %1t: REF_CARRYOUT=%b REF_OLD_CARRYOUT=%b UUT_CARRYOUT=%b DIFF=%b", $time, REF_CARRYOUT, REF_OLD_CARRYOUT, CARRYOUT, REF_CARRYOUT ^ CARRYOUT);
				errcount = errcount + 1;
				ERROR_FLAG = 1;
			end
			if (REF_CARRYOUTF !== CARRYOUTF) begin
				$display("ERROR at %1t: REF_CARRYOUTF=%b UUT_CARRYOUTF=%b", $time, REF_CARRYOUTF, CARRYOUTF);
				errcount = errcount + 1;
				ERROR_FLAG = 1;
			end
			#3;
		end
	endtask

	reg config_valid = 0;
	task drc;
		begin
			config_valid = 1;

			if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0;
			if (OPMODE[3:2] == 2'b10 && PREG != 1) config_valid = 0;
		end
	endtask

	initial begin
		$dumpfile("test_dsp48a1_model.vcd");
		$dumpvars(0, testbench);

		#2;
		CLK = 1'b0;
		{CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = 8'b11111111;
		{A, B, C, D, PCIN, OPMODE, CARRYIN} = 0;
		{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 8'b11111111;
		repeat (10) begin
			#10;
			CLK = 1'b1;
			#10;
			CLK = 1'b0;
			#10;
			CLK = 1'b1;
			#10;
			CLK = 1'b0;
		end
		{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 0;

		repeat (10000) begin
			clkcycle;
			config_valid = 0;
			while (!config_valid) begin
				A = $urandom;
				B = $urandom;
				C = {$urandom, $urandom};
				D = $urandom;
				PCIN = {$urandom, $urandom};

				{CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = $urandom | $urandom | $urandom;
				{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
				{CARRYIN, OPMODE} = $urandom;

				drc;
			end
		end

		if (errcount == 0) begin
			$display("All tests passed.");
			$finish;
		end else begin
			$display("Caught %1d errors.", errcount);
			$stop;
		end
	end

	DSP48A #(
		.A0REG              (A0REG),
		.A1REG              (A1REG),
		.B0REG              (B0REG),
		.B1REG              (B1REG),
		.CREG               (CREG),
		.DREG               (DREG),
		.MREG               (MREG),
		.PREG               (PREG),
		.CARRYINREG         (CARRYINREG),
		.OPMODEREG          (OPMODEREG),
		.CARRYINSEL         (CARRYINSEL),
		.RSTTYPE            (RSTTYPE)
	) ref_old (
		.A             (A),
		.B             (B),
		.C             (C),
		.D             (D),
		.PCIN          (PCIN),
		.CARRYIN       (CARRYIN),
		.OPMODE        (OPMODE),
		.BCOUT         (REF_OLD_BCOUT),
		.CARRYOUT      (REF_OLD_CARRYOUT),
		.P             (REF_OLD_P),
		.PCOUT         (REF_OLD_PCOUT),
		.CEA           (CEA),
		.CEB           (CEB),
		.CEC           (CEC),
		.CED           (CED),
		.CEM           (CEM),
		.CEP           (CEP),
		.CECARRYIN     (CECARRYIN),
		.CEOPMODE      (CEOPMODE),
		.CLK           (CLK),
		.RSTA          (RSTA),
		.RSTB          (RSTB),
		.RSTC          (RSTC),
		.RSTD          (RSTD),
		.RSTM          (RSTM),
		.RSTP          (RSTP),
		.RSTCARRYIN    (RSTCARRYIN),
		.RSTOPMODE     (RSTOPMODE)
	);

	DSP48A1 #(
		.A0REG              (A0REG),
		.A1REG              (A1REG),
		.B0REG              (B0REG),
		.B1REG              (B1REG),
		.CREG               (CREG),
		.DREG               (DREG),
		.MREG               (MREG),
		.PREG               (PREG),
		.CARRYINREG         (CARRYINREG),
		.CARRYOUTREG        (CARRYOUTREG),
		.OPMODEREG          (OPMODEREG),
		.CARRYINSEL         (CARRYINSEL),
		.RSTTYPE            (RSTTYPE)
	) ref (
		.A             (A),
		.B             (B),
		.C             (C),
		.D             (D),
		.PCIN          (PCIN),
		.CARRYIN       (CARRYIN),
		.OPMODE        (OPMODE),
		.BCOUT         (REF_BCOUT),
		.CARRYOUTF     (REF_CARRYOUTF),
		.CARRYOUT      (REF_CARRYOUT),
		.P             (REF_P),
		.M             (REF_M),
		.PCOUT         (REF_PCOUT),
		.CEA           (CEA),
		.CEB           (CEB),
		.CEC           (CEC),
		.CED           (CED),
		.CEM           (CEM),
		.CEP           (CEP),
		.CECARRYIN     (CECARRYIN),
		.CEOPMODE      (CEOPMODE),
		.CLK           (CLK),
		.RSTA          (RSTA),
		.RSTB          (RSTB),
		.RSTC          (RSTC),
		.RSTD          (RSTD),
		.RSTM          (RSTM),
		.RSTP          (RSTP),
		.RSTCARRYIN    (RSTCARRYIN),
		.RSTOPMODE     (RSTOPMODE)
	);

	DSP48A1_UUT #(
		.A0REG              (A0REG),
		.A1REG              (A1REG),
		.B0REG              (B0REG),
		.B1REG              (B1REG),
		.CREG               (CREG),
		.DREG               (DREG),
		.MREG               (MREG),
		.PREG               (PREG),
		.CARRYINREG         (CARRYINREG),
		.CARRYOUTREG        (CARRYOUTREG),
		.OPMODEREG          (OPMODEREG),
		.CARRYINSEL         (CARRYINSEL),
		.RSTTYPE            (RSTTYPE)
	) uut (
		.A             (A),
		.B             (B),
		.C             (C),
		.D             (D),
		.PCIN          (PCIN),
		.CARRYIN       (CARRYIN),
		.OPMODE        (OPMODE),
		.BCOUT         (BCOUT),
		.CARRYOUTF     (CARRYOUTF),
		.CARRYOUT      (CARRYOUT),
		.P             (P),
		.M             (M),
		.PCOUT         (PCOUT),
		.CEA           (CEA),
		.CEB           (CEB),
		.CEC           (CEC),
		.CED           (CED),
		.CEM           (CEM),
		.CEP           (CEP),
		.CECARRYIN     (CECARRYIN),
		.CEOPMODE      (CEOPMODE),
		.CLK           (CLK),
		.RSTA          (RSTA),
		.RSTB          (RSTB),
		.RSTC          (RSTC),
		.RSTD          (RSTD),
		.RSTM          (RSTM),
		.RSTP          (RSTP),
		.RSTCARRYIN    (RSTCARRYIN),
		.RSTOPMODE     (RSTOPMODE)
	);
endmodule

module mult_noreg;
	testbench #(
		.A0REG              (0),
		.A1REG              (0),
		.B0REG              (0),
		.B1REG              (0),
		.CREG               (0),
		.DREG               (0),
		.MREG               (0),
		.PREG               (0),
		.CARRYINREG         (0),
		.CARRYOUTREG        (0),
		.OPMODEREG          (0),
		.CARRYINSEL         ("CARRYIN"),
		.RSTTYPE            ("SYNC")
	) testbench ();
endmodule

module mult_allreg;
	testbench #(
		.A0REG              (1),
		.A1REG              (1),
		.B0REG              (1),
		.B1REG              (1),
		.CREG               (1),
		.DREG               (1),
		.MREG               (1),
		.PREG               (1),
		.CARRYINREG         (1),
		.CARRYOUTREG        (1),
		.OPMODEREG          (1),
		.CARRYINSEL         ("OPMODE5"),
		.RSTTYPE            ("SYNC")
	) testbench ();
endmodule

module mult_inreg;
	testbench #(
		.A0REG              (1),
		.A1REG              (1),
		.B0REG              (1),
		.B1REG              (1),
		.CREG               (1),
		.DREG               (1),
		.MREG               (0),
		.PREG               (0),
		.CARRYINREG         (1),
		.CARRYOUTREG        (0),
		.OPMODEREG          (0),
		.CARRYINSEL         ("CARRYIN"),
		.RSTTYPE            ("SYNC")
	) testbench ();
endmodule