mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	abstract: -value MVP, use buffer-normalized mode
This commit is contained in:
		
							parent
							
								
									497a6e0c59
								
							
						
					
					
						commit
						eb8982a937
					
				
					 2 changed files with 121 additions and 62 deletions
				
			
		|  | @ -57,70 +57,70 @@ bool abstract_state(Module* mod, Cell* cell, Wire* enable, bool enable_pol) { | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool abstract_value(Module* mod, Wire* wire, Wire* enable, bool enable_pol) { | ||||
| 	// (void)mod->addMux(NEW_ID,
 | ||||
| 	// 	mux_a,
 | ||||
| 	// 	mux_b,
 | ||||
| 	// 	enable,
 | ||||
| 	// 	abstracted);
 | ||||
| 	// 	cell->setPort(ID::D, SigSpec(abstracted));
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| struct AbstractInitCtx { | ||||
| struct AbstractPortCtx { | ||||
| 	Module* mod; | ||||
| 	SigMap sigmap; | ||||
| 	pool<SigBit> init_bits; | ||||
| 	pool<std::pair<Cell*, IdString>> outs; | ||||
| }; | ||||
| 
 | ||||
| void collect_init_bits_cells(AbstractInitCtx& ctx) { | ||||
| 	// TODO Should this discriminate between FFs and other cells?
 | ||||
| 	for (auto cell : ctx.mod->selected_cells()) { | ||||
| 		// Add all sigbits on all cell outputs to init_bits
 | ||||
| 		for (auto &conn : cell->connections()) { | ||||
| 			if (cell->output(conn.first)) { | ||||
| 				for (auto bit : conn.second) { | ||||
| 					log_debug("init: cell %s output %s\n", cell->name.c_str(), log_signal(bit)); | ||||
| 					ctx.init_bits.insert(ctx.sigmap(bit)); | ||||
| 				} | ||||
| 			} | ||||
| void collect_selected_ports(AbstractPortCtx& ctx) { | ||||
| 	for (Cell* cell : ctx.mod->cells()) { | ||||
| 		for (auto& conn : cell->connections()) { | ||||
| 			// we bufnorm
 | ||||
| 			log_assert(conn.second.is_wire() || conn.second.is_fully_const()); | ||||
| 			if (conn.second.is_wire() && cell->output(conn.first)) | ||||
| 				if (ctx.mod->selected(cell) || ctx.mod->selected(conn.second.as_wire())) | ||||
| 					ctx.outs.insert(std::make_pair(cell, conn.first)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void collect_init_bits_wires(AbstractInitCtx& ctx) { | ||||
| 	for (auto wire : ctx.mod->selected_wires()) { | ||||
| 		auto canonical = ctx.sigmap(wire); | ||||
| 		// Find canonical drivers of all the wire bits and add them to init_bits
 | ||||
| 		for (auto bit : canonical.bits()) { | ||||
| 			log_debug("init: wire %s bit %s\n", wire->name.c_str(), log_signal(bit)); | ||||
| 			ctx.init_bits.insert(ctx.sigmap(bit)); | ||||
| unsigned int abstract_value(Module* mod, Wire* enable, bool enable_pol) { | ||||
| 	AbstractPortCtx ctx {mod, SigMap(mod), {}}; | ||||
| 	collect_selected_ports(ctx); | ||||
| 	unsigned int changed = 0; | ||||
| 	for (auto [cell, port] : ctx.outs) { | ||||
| 		SigSpec sig = cell->getPort(port); | ||||
| 		log_assert(sig.is_wire()); | ||||
| 		Wire* original = mod->addWire(NEW_ID, sig.size()); | ||||
| 		cell->setPort(port, original); | ||||
| 		auto anyseq = mod->Anyseq(NEW_ID, sig.size()); | ||||
| 		// This code differs from abstract_state
 | ||||
| 		// in that we reuse the original signal as the mux output,
 | ||||
| 		// not input
 | ||||
| 		SigSpec mux_a, mux_b; | ||||
| 		if (enable_pol) { | ||||
| 			mux_a = original; | ||||
| 			mux_b = anyseq; | ||||
| 		} else { | ||||
| 			mux_a = anyseq; | ||||
| 			mux_b = original; | ||||
| 		} | ||||
| 		(void)mod->addMux(NEW_ID, | ||||
| 			mux_a, | ||||
| 			mux_b, | ||||
| 			enable, | ||||
| 			sig); | ||||
| 		changed++; | ||||
| 	} | ||||
| 	return changed; | ||||
| } | ||||
| 
 | ||||
| unsigned int abstract_init(Module* mod) { | ||||
| 	AbstractInitCtx ctx {mod, SigMap(mod), pool<SigBit>()}; | ||||
| 	pool<SigBit> init_bits; | ||||
| 	collect_init_bits_cells(ctx); | ||||
| 	collect_init_bits_wires(ctx); | ||||
| 	AbstractPortCtx ctx {mod, SigMap(mod), {}}; | ||||
| 	collect_selected_ports(ctx); | ||||
| 
 | ||||
| 	unsigned int changed = 0; | ||||
| 
 | ||||
| 	for (SigBit bit : ctx.init_bits) { | ||||
| next_sigbit: | ||||
| 		if (!bit.is_wire() || !bit.wire->has_attribute(ID::init)) | ||||
| 	for (auto [cell, port] : ctx.outs) { | ||||
| 		SigSpec sig = cell->getPort(port); | ||||
| 		log_assert(sig.is_wire()); | ||||
| 		if (!sig.as_wire()->has_attribute(ID::init)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		Const init = bit.wire->attributes.at(ID::init); | ||||
| 		std::vector<RTLIL::State>& bits = init.bits(); | ||||
| 		bits[bit.offset] = RTLIL::State::Sx; | ||||
| 		changed++; | ||||
| 
 | ||||
| 		for (auto bit : bits) | ||||
| 			if (bit != RTLIL::State::Sx) | ||||
| 				goto next_sigbit; | ||||
| 		// All bits are Sx, erase init attribute entirely
 | ||||
| 		bit.wire->attributes.erase(ID::init); | ||||
| 		Const init = sig.as_wire()->attributes.at(ID::init); | ||||
| 		sig.as_wire()->attributes.erase(ID::init); | ||||
| 		changed += sig.size(); | ||||
| 	} | ||||
| 	return changed; | ||||
| } | ||||
|  | @ -174,6 +174,7 @@ struct AbstractPass : public Pass { | |||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		design->bufNormalize(true); | ||||
| 		unsigned int changed = 0; | ||||
| 		if ((mode == State) || (mode == Value)) { | ||||
| 			if (!enable_name.length()) | ||||
|  | @ -191,14 +192,13 @@ struct AbstractPass : public Pass { | |||
| 						if (ct.cell_types.count(cell->type)) | ||||
| 							changed += abstract_state(mod, cell, enable_wire, enable_pol); | ||||
| 				} else { | ||||
| 					// Value
 | ||||
| 					for (auto wire : mod->selected_wires()) { | ||||
| 						changed += abstract_value(mod, wire, enable_wire, enable_pol); | ||||
| 					} | ||||
| 					log_cmd_error("Unsupported (TODO)\n"); | ||||
| 					changed += abstract_value(mod, enable_wire, enable_pol); | ||||
| 				} | ||||
| 			} | ||||
| 			log("Abstracted %d cells.\n", changed); | ||||
| 			if (mode == State) | ||||
| 				log("Abstracted %d cells.\n", changed); | ||||
| 			else | ||||
| 				log("Abstracted %d values.\n", changed); | ||||
| 		} else if (mode == Initial) { | ||||
| 			for (auto mod : design->selected_modules()) { | ||||
| 				changed += abstract_init(mod); | ||||
|  | @ -207,6 +207,7 @@ struct AbstractPass : public Pass { | |||
| 		} else { | ||||
| 			log_cmd_error("No mode selected, see help message\n"); | ||||
| 		} | ||||
| 		design->bufNormalize(false); | ||||
| 	} | ||||
| } AbstractPass; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| read_verilog <<EOT | ||||
| 
 | ||||
| module half_clock (CLK, Q); | ||||
| module half_clock (CLK, Q, magic); | ||||
| 	input CLK; | ||||
| 	output reg Q; | ||||
| 	reg magic; | ||||
| 	input magic; | ||||
| 	always @(posedge CLK) | ||||
| 		Q <= ~Q; | ||||
| endmodule | ||||
|  | @ -12,16 +12,16 @@ EOT | |||
| proc | ||||
| # show -prefix before_base | ||||
| abstract -state -enablen magic | ||||
| check | ||||
| check -assert | ||||
| # show -prefix after_base | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog <<EOT | ||||
| module half_clock_en (CLK, E, Q); | ||||
| module half_clock_en (CLK, E, Q, magic); | ||||
| 	input CLK; | ||||
| 	input E; | ||||
| 	output reg Q; | ||||
| 	reg magic; | ||||
| 	input magic; | ||||
| 	always @(posedge CLK) | ||||
|         if (E) | ||||
|             Q <= ~Q; | ||||
|  | @ -33,7 +33,7 @@ opt_expr | |||
| opt_dff | ||||
| # show -prefix before_en | ||||
| abstract -state -enablen magic | ||||
| check | ||||
| check -assert | ||||
| # show -prefix after_en | ||||
| 
 | ||||
| design -reset | ||||
|  | @ -50,9 +50,35 @@ proc | |||
| opt_expr | ||||
| opt_dff | ||||
| dump | ||||
| select -none | ||||
| abstract -init | ||||
| check | ||||
| select -clear | ||||
| check -assert | ||||
| # dump | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog <<EOT | ||||
| module main (input [3:0] baz); | ||||
|   reg foo; | ||||
|   reg bar; | ||||
|   assign foo = bar; | ||||
|   assign bar = baz[0]; | ||||
|   reg aaa = 1'b1; | ||||
|   always @(posedge bar) | ||||
|   	aaa <= ~aaa; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| proc -noopt | ||||
| # show -prefix before_init | ||||
| dump | ||||
| select -none | ||||
| abstract -init | ||||
| select -clear | ||||
| # show -prefix after_init | ||||
| dump | ||||
| check -assert | ||||
| # dump | ||||
| 
 | ||||
| 
 | ||||
| design -reset | ||||
|  | @ -85,6 +111,38 @@ opt_expr | |||
| opt_dff | ||||
| # show -prefix before_a | ||||
| abstract -state -enablen magic | ||||
| check | ||||
| check -assert | ||||
| # show -prefix after_a | ||||
| # opt_clean | ||||
| # opt_clean | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog <<EOT | ||||
| module this_adff (CLK, ARST, D, Q, magic); | ||||
| 
 | ||||
| parameter WIDTH = 2; | ||||
| parameter CLK_POLARITY = 1'b1; | ||||
| parameter ARST_POLARITY = 1'b1; | ||||
| parameter ARST_VALUE = 0; | ||||
| 
 | ||||
| input CLK, ARST, magic; | ||||
| input [WIDTH-1:0] D; | ||||
| output reg [WIDTH-1:0] Q; | ||||
| wire pos_clk = CLK == CLK_POLARITY; | ||||
| wire pos_arst = ARST == ARST_POLARITY; | ||||
| 
 | ||||
| always @(posedge pos_clk, posedge pos_arst) begin | ||||
| 	if (pos_arst) | ||||
| 		Q <= ARST_VALUE; | ||||
| 	else | ||||
| 		Q <= D; | ||||
| end | ||||
| 
 | ||||
| endmodule | ||||
| EOT | ||||
| proc | ||||
| # show -prefix before_value | ||||
| abstract -value -enablen magic | ||||
| check -assert | ||||
| clean | ||||
| # show -prefix after_value | ||||
| # dump | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue