mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	More comments, cleanup
This commit is contained in:
		
							parent
							
								
									7de9c33931
								
							
						
					
					
						commit
						6d68972619
					
				
					 2 changed files with 109 additions and 42 deletions
				
			
		|  | @ -425,22 +425,42 @@ endcode | |||
| 
 | ||||
| // ####################### | ||||
| 
 | ||||
| // Subpattern for matching against input registers, based on knowledge of the | ||||
| //   'Q' input. | ||||
| // At a high level: | ||||
| //   (1) Starting from a $dff cell that (partially or fully) drives the given | ||||
| //       'Q' argument | ||||
| //   (2) Match for a $mux cell implementing synchronous reset semantics --- | ||||
| //       one that exclusively drives the 'D' input of the $dff, with one of its | ||||
| //       $mux inputs being fully zero | ||||
| //   (3) Match for a $mux cell implement clock enable semantics --- one that | ||||
| //       exclusively drives the 'D' input of the $dff (or the other input of | ||||
| //       the reset $mux) and where one of this $mux's inputs is connected to | ||||
| //       the 'Q' output of the $dff | ||||
| subpattern in_dffe | ||||
| arg argD argQ clock | ||||
| 
 | ||||
| code | ||||
| 	dff = nullptr; | ||||
| 	for (auto c : argQ.chunks()) { | ||||
| 	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; | ||||
| 		Const init = c.wire->attributes.at(\init, State::Sx); | ||||
| 		if (!init.is_fully_undef() && !init.is_fully_zero()) | ||||
| 			reject; | ||||
| 		// Abandon matches when 'Q' has a non-zero init attribute set | ||||
| 		// (not supported by DSP48E1) | ||||
| 		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 | ||||
| 
 | ||||
| // (1) Starting from a $dff cell that (partially or fully) drives the given | ||||
| //     'Q' argument | ||||
| match ff | ||||
| 	select ff->type.in($dff) | ||||
| 	// DSP48E1 does not support clock inversion | ||||
|  | @ -453,14 +473,12 @@ match ff | |||
| 	filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) | ||||
| 	filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ | ||||
| 
 | ||||
| 	filter clock == SigBit() || port(ff, \CLK) == clock | ||||
| 
 | ||||
| 	set ffoffset offset | ||||
| endmatch | ||||
| 
 | ||||
| code argQ argD | ||||
| { | ||||
| 	if (clock != SigBit() && port(ff, \CLK) != clock) | ||||
| 		reject; | ||||
| 
 | ||||
| 	SigSpec Q = port(ff, \Q); | ||||
| 	dff = ff; | ||||
| 	dffclock = port(ff, \CLK); | ||||
|  | @ -472,9 +490,11 @@ code argQ argD | |||
| 	//   has two (ff, ffrstmux) users | ||||
| 	if (nusers(dffD) > 2) | ||||
| 		argD = SigSpec(); | ||||
| } | ||||
| endcode | ||||
| 
 | ||||
| // (2) Match for a $mux cell implementing synchronous reset semantics --- | ||||
| //     exclusively drives the 'D' input of the $dff, with one of the $mux | ||||
| //     inputs being fully zero | ||||
| match ffrstmux | ||||
| 	if !argD.empty() | ||||
| 	select ffrstmux->type.in($mux) | ||||
|  | @ -506,6 +526,10 @@ code argD | |||
| 		dffrstmux = nullptr; | ||||
| endcode | ||||
| 
 | ||||
| // (3) Match for a $mux cell implement clock enable semantics --- one that | ||||
| //     exclusively drives the 'D' input of the $dff (or the other input of | ||||
| //     the reset $mux) and where one of this $mux's inputs is connected to | ||||
| //     the 'Q' output of the $dff | ||||
| match ffcemux | ||||
| 	if !argD.empty() | ||||
| 	select ffcemux->type.in($mux) | ||||
|  | @ -530,16 +554,32 @@ endcode | |||
| 
 | ||||
| // ####################### | ||||
| 
 | ||||
| // Subpattern for matching against output registers, based on knowledge of the | ||||
| //   'D' input. | ||||
| // At a high level: | ||||
| //   (1) Starting from an optional $mux cell that implements clock enable | ||||
| //       semantics --- one where the given 'D' argument (partially or fully) | ||||
| //       drives one of its two inputs | ||||
| //   (2) Starting from, or continuing onto, another optional $mux cell that | ||||
| //       implements synchronous reset semantics --- one where the given 'D' | ||||
| //       argument (or the clock enable $mux output) drives one of its two inputs | ||||
| //       and where the other input is fully zero | ||||
| //   (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the | ||||
| //       output of the previous clock enable or reset $mux cells) | ||||
| subpattern out_dffe | ||||
| arg argD argQ clock | ||||
| 
 | ||||
| code | ||||
| 	dff = nullptr; | ||||
| 	for (auto c : argD.chunks()) | ||||
| 		// Abandon matches when 'D' has the keep attribute set | ||||
| 		if (c.wire->get_bool_attribute(\keep)) | ||||
| 			reject; | ||||
| endcode | ||||
| 
 | ||||
| // (1) Starting from an optional $mux cell that implements clock enable | ||||
| //     semantics --- one where the given 'D' argument (partially or fully) | ||||
| //     drives one of its two inputs | ||||
| match ffcemux | ||||
| 	select ffcemux->type.in($mux) | ||||
| 	// ffcemux output must have two users: ffcemux and ff.D | ||||
|  | @ -578,6 +618,10 @@ code argD argQ | |||
| 	} | ||||
| endcode | ||||
| 
 | ||||
| // (2) Starting from, or continuing onto, another optional $mux cell that | ||||
| //     implements synchronous reset semantics --- one where the given 'D' | ||||
| //     argument (or the clock enable $mux output) drives one of its two inputs | ||||
| //     and where the other input is fully zero | ||||
| match ffrstmux | ||||
| 	select ffrstmux->type.in($mux) | ||||
| 	// ffrstmux output must have two users: ffrstmux and ff.D | ||||
|  | @ -616,6 +660,8 @@ code argD argQ | |||
| 	} | ||||
| endcode | ||||
| 
 | ||||
| // (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the | ||||
| //     output of the previous clock enable or reset $mux cells) | ||||
| match ff | ||||
| 	select ff->type.in($dff) | ||||
| 	// DSP48E1 does not support clock inversion | ||||
|  | @ -632,32 +678,30 @@ match ff | |||
| 	// Check that FF.Q is connected to CE-mux | ||||
| 	filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ | ||||
| 
 | ||||
| 	filter clock == SigBit() || port(ff, \CLK) == clock | ||||
| 
 | ||||
| 	set ffoffset offset | ||||
| endmatch | ||||
| 
 | ||||
| code argQ | ||||
| 	if (ff) { | ||||
| 		if (clock != SigBit() && port(ff, \CLK) != clock) | ||||
| 			reject; | ||||
| 
 | ||||
| 		SigSpec D = port(ff, \D); | ||||
| 		SigSpec Q = port(ff, \Q); | ||||
| 		if (!ffcemux) { | ||||
| 			argQ = argD; | ||||
| 			argQ.replace(D, Q); | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto c : argQ.chunks()) { | ||||
| 			Const init = c.wire->attributes.at(\init, State::Sx); | ||||
| 			if (!init.is_fully_undef() && !init.is_fully_zero()) | ||||
| 				reject; | ||||
| 		} | ||||
| 
 | ||||
| 		dff = ff; | ||||
| 		dffQ = argQ; | ||||
| 		dffclock = port(ff, \CLK); | ||||
| 	SigSpec D = port(ff, \D); | ||||
| 	SigSpec Q = port(ff, \Q); | ||||
| 	if (!ffcemux) { | ||||
| 		argQ = argD; | ||||
| 		argQ.replace(D, Q); | ||||
| 	} | ||||
| 	// No enable/reset mux possible without flop | ||||
| 	else if (dffcemux || dffrstmux) | ||||
| 		reject; | ||||
| 
 | ||||
| 	// Abandon matches when 'Q' has a non-zero init attribute set | ||||
| 	// (not supported by DSP48E1) | ||||
| 	for (auto c : argQ.chunks()) { | ||||
| 		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; | ||||
| 	} | ||||
| 
 | ||||
| 	dff = ff; | ||||
| 	dffQ = argQ; | ||||
| 	dffclock = port(ff, \CLK); | ||||
| endcode | ||||
|  |  | |||
|  | @ -77,7 +77,7 @@ 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 a subpattern discussed below) | ||||
| //      reset functionality, using the in_dffe subpattern) | ||||
| code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock | ||||
| 	argQ = sigC; | ||||
| 	subpattern(in_dffe); | ||||
|  | @ -103,22 +103,41 @@ endcode | |||
| 
 | ||||
| // ####################### | ||||
| 
 | ||||
| // Subpattern for matching against input registers, based on knowledge of the | ||||
| //   'Q' input. | ||||
| // At a high level: | ||||
| //   (1) Starting from a $dff cell that (partially or fully) drives the given | ||||
| //       'Q' argument | ||||
| //   (2) Match for a $mux cell implementing synchronous reset semantics --- | ||||
| //       one that exclusively drives the 'D' input of the $dff, with one of its | ||||
| //       $mux inputs being fully zero | ||||
| //   (3) Match for a $mux cell implement clock enable semantics --- one that | ||||
| //       exclusively drives the 'D' input of the $dff (or the other input of | ||||
| //       the reset $mux) and where one of this $mux's inputs is connected to | ||||
| //       the 'Q' output of the $dff | ||||
| subpattern in_dffe | ||||
| arg argD argQ clock | ||||
| 
 | ||||
| code | ||||
| 	dff = nullptr; | ||||
| 	for (auto c : argQ.chunks()) { | ||||
| 	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; | ||||
| 		Const init = c.wire->attributes.at(\init, State::Sx); | ||||
| 		if (!init.is_fully_undef() && !init.is_fully_zero()) | ||||
| 			reject; | ||||
| 		// Abandon matches when 'Q' has a non-zero init attribute set | ||||
| 		// (not supported by DSP48E1) | ||||
| 		Const init = c.wire->attributes.at(\init, Const()); | ||||
| 		for (auto b : init.extract(c.offset, c.width)) | ||||
| 			if (b != State::Sx && b != State::S0) | ||||
| 				reject; | ||||
| 	} | ||||
| endcode | ||||
| 
 | ||||
| // (1) Starting from a $dff cell that (partially or fully) drives the given | ||||
| //     'Q' argument | ||||
| match ff | ||||
| 	select ff->type.in($dff) | ||||
| 	// DSP48E1 does not support clock inversion | ||||
|  | @ -131,14 +150,12 @@ match ff | |||
| 	filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ) | ||||
| 	filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ | ||||
| 
 | ||||
| 	filter clock == SigBit() || port(ff, \CLK) == clock | ||||
| 
 | ||||
| 	set ffoffset offset | ||||
| endmatch | ||||
| 
 | ||||
| code argQ argD | ||||
| { | ||||
| 	if (clock != SigBit() && port(ff, \CLK) != clock) | ||||
| 		reject; | ||||
| 
 | ||||
| 	SigSpec Q = port(ff, \Q); | ||||
| 	dff = ff; | ||||
| 	dffclock = port(ff, \CLK); | ||||
|  | @ -150,9 +167,11 @@ code argQ argD | |||
| 	//   has two (ff, ffrstmux) users | ||||
| 	if (nusers(dffD) > 2) | ||||
| 		argD = SigSpec(); | ||||
| } | ||||
| endcode | ||||
| 
 | ||||
| // (2) Match for a $mux cell implementing synchronous reset semantics --- | ||||
| //     exclusively drives the 'D' input of the $dff, with one of the $mux | ||||
| //     inputs being fully zero | ||||
| match ffrstmux | ||||
| 	if !argD.empty() | ||||
| 	select ffrstmux->type.in($mux) | ||||
|  | @ -184,6 +203,10 @@ code argD | |||
| 		dffrstmux = nullptr; | ||||
| endcode | ||||
| 
 | ||||
| // (3) Match for a $mux cell implement clock enable semantics --- one that | ||||
| //     exclusively drives the 'D' input of the $dff (or the other input of | ||||
| //     the reset $mux) and where one of this $mux's inputs is connected to | ||||
| //     the 'Q' output of the $dff | ||||
| match ffcemux | ||||
| 	if !argD.empty() | ||||
| 	select ffcemux->type.in($mux) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue