// Certain arithmetic operations between a signal of width n and a constant can be directly mapped // to a single k-LUT (where n <= k). This is preferable to normal alumacc techmapping process // because for many targets, arithmetic techmapping creates hard logic (such as carry cells) which often // cannot be optimized further. // // TODO: Currently, only comparisons with 1-bit output are mapped. Potentially, all arithmetic cells // with n <= k inputs should be techmapped in this way, because this shortens the critical path // from n to 1 by avoiding carry chains. (* techmap_celltype = "$lt $le $gt $ge" *) module _90_lut_cmp_ (A, B, Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; parameter A_WIDTH = 0; parameter B_WIDTH = 0; parameter Y_WIDTH = 0; (* force_downto *) input [A_WIDTH-1:0] A; (* force_downto *) input [B_WIDTH-1:0] B; (* force_downto *) output [Y_WIDTH-1:0] Y; parameter _TECHMAP_CELLTYPE_ = ""; parameter _TECHMAP_CONSTMSK_A_ = 0; parameter _TECHMAP_CONSTVAL_A_ = 0; parameter _TECHMAP_CONSTMSK_B_ = 0; parameter _TECHMAP_CONSTVAL_B_ = 0; function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut; input integer width; input integer operation; input integer swap; input integer sign; input integer operand; integer n, i_var, i_cst, lhs, rhs, o_bit; begin gen_lut = width'b0; for (n = 0; n < (1 << width); n++) begin if (sign) i_var = n[width-1:0]; else i_var = n; i_cst = operand; if (swap) begin lhs = i_cst; rhs = i_var; end else begin lhs = i_var; rhs = i_cst; end if (operation == 0) o_bit = (lhs < rhs); if (operation == 1) o_bit = (lhs <= rhs); if (operation == 2) o_bit = (lhs > rhs); if (operation == 3) o_bit = (lhs >= rhs); gen_lut = gen_lut | (o_bit << n); end end endfunction generate localparam operation = _TECHMAP_CELLTYPE_ == "$lt" ? 0 : _TECHMAP_CELLTYPE_ == "$le" ? 1 : _TECHMAP_CELLTYPE_ == "$gt" ? 2 : _TECHMAP_CELLTYPE_ == "$ge" ? 3 : -1; if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1) wire _TECHMAP_FAIL_ = 1; else if (&_TECHMAP_CONSTMSK_B_) \$lut #( .WIDTH(A_WIDTH), .LUT({ gen_lut(A_WIDTH, operation, 0, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_B_) }) ) _TECHMAP_REPLACE_ ( .A(A), .Y(Y) ); else if (&_TECHMAP_CONSTMSK_A_) \$lut #( .WIDTH(B_WIDTH), .LUT({ gen_lut(B_WIDTH, operation, 1, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_A_) }) ) _TECHMAP_REPLACE_ ( .A(B), .Y(Y) ); else wire _TECHMAP_FAIL_ = 1; endgenerate endmodule root/techlibs/gowin/determine_init.cc
blob: 18a64e45181d6150848a67b7451bc7c199f2ed41 (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
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
 *
 *  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 DetermineInitPass : public Pass {
	DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { }
	void help() YS_OVERRIDE
	{
		log("\n");
		log("    determine_init [selection]\n");
		log("\n");
		log("Determine the init value of cells that doesn't allow unknown init value.\n");
		log("\n");
	}

	Const determine_init(Const init)
	{
		for (int i = 0; i < GetSize(init); i++) {
			if (init[i] != State::S0 && init[i] != State::S1)
				init[i] = State::S0;
		}

		return init;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n");

		extra_args(args, args.size(), design);

		int cnt = 0;
		for (auto module : design->selected_modules())
		{
			for (auto cell : module->selected_cells())
			{
				if (cell->type == ID(RAM16S4))
				{
					cell->setParam(ID(INIT_0), determine_init(cell->getParam(ID(INIT_0))));
					cell->setParam(ID(INIT_1), determine_init(cell->getParam(ID(INIT_1))));
					cell->setParam(ID(INIT_2), determine_init(cell->getParam(ID(INIT_2))));
					cell->setParam(ID(INIT_3), determine_init(cell->getParam(ID(INIT_3))));
					cnt++;
				}
			}
		}
		log_header(design, "Updated %d cells with determined init value.\n", cnt);
	}
} DetermineInitPass;

PRIVATE_NAMESPACE_END