File: microchip_dsp_CREG.pmg

package info (click to toggle)
yosys 0.52-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 69,796 kB
  • sloc: ansic: 696,955; cpp: 239,736; python: 14,617; yacc: 3,529; sh: 2,175; makefile: 1,945; lex: 697; perl: 445; javascript: 323; tcl: 162; vhdl: 115
file content (168 lines) | stat: -rw-r--r-- 5,479 bytes parent folder | download
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// ISC License
// 
// Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
// 
// 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.


// This file describes the second of three pattern matcher setups that
//   forms the `microchip_dsp` pass described in microchip_dsp.cc
// At a high level, it works as follows:
//   (1) Starting from a DSP cell that (a) doesn't have a CREG already,
//       and (b) uses the 'C' port
//   (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
//       (attached to at most two $mux cells that implement clock-enable or
//        reset functionality, using a subpattern discussed below)
// Notes:
//   - Running CREG packing after microchip_dsp_pack is necessary since there is no
//     guarantee that the cell ordering corresponds to the "expected" case (i.e.
//     the order in which they appear in the source) thus the possiblity existed
//     where a register got packed as a CREG into a downstream DSP, while it should
//     have otherwise been a PREG of an upstream DSP that had not been visited.
//     yet.
//   - The reason this is separated out from the microchip_dsp.pmg file is
//     for efficiency --- each *.pmg file creates a class of the same basename,
//     which when constructed, creates a custom database tailored to the
//     pattern(s) contained within. Since the pattern in this file must be
//     executed after the pattern contained in microchip_dsp.pmg, it is necessary
//     to reconstruct this database. Separating the two patterns into
//     independent files causes two smaller, more specific, databases.

pattern microchip_dsp_packC

udata <std::function<SigSpec(const SigSpec&)>> unextend
state <SigBit> clock
state <SigSpec> sigC sigP
state <Cell*> ffC

// Variables used for subpatterns
state <SigSpec> argQ argD
state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
udata <Cell*> dff

// (1) Starting from a DSP cell that (a) doesn't have a CREG already,
//     and (b) uses the 'C' port
match dsp
	select dsp->type.in(\MACC_PA)
	select port(dsp, \C_BYPASS, SigSpec()).is_fully_ones()
	select nusers(port(dsp, \C, SigSpec())) > 1
endmatch

code sigC sigP clock
	//helper function to remove unused bits
	unextend = [](const SigSpec &sig) {
		int i;
		for (i = GetSize(sig)-1; i > 0; i--)
			if (sig[i] != sig[i-1])
				break;
		// Do not remove non-const sign bit
		if (sig[i].wire)
			++i;
		return sig.extract(0, i);
	};
	sigC = unextend(port(dsp, \C, SigSpec()));

	SigSpec P = port(dsp, \P);

	// Only care about those bits that are used
	int i;
	for (i = GetSize(P)-1; i >= 0; i--)
		if (nusers(P[i]) > 1)
			break;
	i++;
	log_assert(nusers(P.extract_end(i)) <= 1);
	sigP = P.extract(0, i);

	clock = port(dsp, \CLK, SigBit());
endcode

// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
//     (attached to at most two $mux cells that implement clock-enable or
//      reset functionality, using the in_dffe subpattern)
code argQ ffC sigC clock
	argQ = sigC;
	subpattern(in_dffe);
	if (dff) {
		ffC = dff;
		clock = dffclock;
		sigC = dffD;
	}
endcode

code
	if (ffC)
		accept;
endcode

// #######################

// Subpattern for matching against input registers, based on knowledge of the
//   'Q' input.
subpattern in_dffe
arg argQ clock

code
	dff = nullptr;
	if (argQ.empty())
		reject;
	for (const auto &c : argQ.chunks()) {
		// Abandon matches when 'Q' is a constant
		if (!c.wire)
			reject;
		// Abandon matches when 'Q' has the keep attribute set
		if (c.wire->get_bool_attribute(\keep))
			reject;
		// Abandon matches when 'Q' has a non-zero init attribute set
		Const init = c.wire->attributes.at(\init, Const());
		if (!init.empty())
			for (auto b : init.extract(c.offset, c.width))
				if (b != State::Sx && b != State::S0)
					reject;
	}
endcode

match ff
	select ff->type.in($dff, $dffe, $sdff, $sdffe, $adff, $adffe)
	// does not support clock inversion
	select param(ff, \CLK_POLARITY).as_bool()

	slice offset GetSize(port(ff, \D))
	index <SigBit> port(ff, \Q)[offset] === argQ[0]

	// Check that the rest of argQ is present
	filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
	filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ

	filter clock == SigBit() || port(ff, \CLK)[0] == clock
endmatch

code argQ
	// Check that reset value, if present, is fully 0.
	bool noResetFlop = ff->type.in($dff, $dffe);
	bool srstZero = ff->type.in($sdff, $sdffe) && param(ff, \SRST_VALUE).is_fully_zero();
	bool arstZero = ff->type.in($adff, $adffe) && param(ff, \ARST_VALUE).is_fully_zero();
	bool resetLegal = noResetFlop || srstZero || arstZero;
	if (resetLegal)
	{
		SigSpec Q = port(ff, \Q);
		dff = ff;
		dffclock = port(ff, \CLK);
		dffD = argQ;
		SigSpec D = port(ff, \D);
		argQ = Q;
		dffD.replace(argQ, D);
	}
	
endcode