mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	
						commit
						6da543a61a
					
				
					 18 changed files with 381 additions and 55 deletions
				
			
		| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
Coarse arithmetics
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
.. todo:: Add information about `$alu`, `$fa`, and `$lcu` cells.
 | 
			
		||||
.. todo:: Add information about `$alu`, `$fa`, `$macc_v2`, and `$lcu` cells.
 | 
			
		||||
 | 
			
		||||
The `$macc` cell type represents a generalized multiply and accumulate
 | 
			
		||||
operation. The cell is purely combinational. It outputs the result of summing up
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ show -color maroon3 @new_cells -notitle -format dot -prefix rdata_memrdv2 o:rdat
 | 
			
		|||
# ========================================================
 | 
			
		||||
 | 
			
		||||
alumacc
 | 
			
		||||
select -set new_cells t:$alu t:$macc
 | 
			
		||||
select -set new_cells t:$alu t:$macc_v2
 | 
			
		||||
show -color maroon3 @new_cells -notitle -format dot -prefix rdata_alumacc o:rdata %ci*
 | 
			
		||||
 | 
			
		||||
# ========================================================
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -523,7 +523,7 @@ That brings us to the fourth and final part for the iCE40 synthesis flow:
 | 
			
		|||
   :name: synth_coarse4
 | 
			
		||||
 | 
			
		||||
Where before each type of arithmetic operation had its own cell, e.g. `$add`, we
 | 
			
		||||
now want to extract these into `$alu` and `$macc` cells which can help identify
 | 
			
		||||
now want to extract these into `$alu` and `$macc_v2` cells which can help identify
 | 
			
		||||
opportunities for reusing logic.  We do this by running `alumacc`, which we can
 | 
			
		||||
see produce the following changes in our example design:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -453,7 +453,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
 | 
			
		||||
	// FIXME: $lut $sop $alu $lcu $macc $fa
 | 
			
		||||
	// FIXME: $lut $sop $alu $lcu $macc $macc_v2 $fa
 | 
			
		||||
	// FIXME: $mul $div $mod $divfloor $modfloor $pow $slice $concat $bweqx
 | 
			
		||||
	// FIXME: $lut $sop $alu $lcu $macc $fa $logic_and $logic_or $bwmux
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,6 +144,7 @@ struct CellTypes
 | 
			
		|||
 | 
			
		||||
		setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);
 | 
			
		||||
		setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);
 | 
			
		||||
		setup_type(ID($macc_v2), {ID::A, ID::B, ID::C}, {ID::Y}, true);
 | 
			
		||||
		setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -310,7 +310,7 @@ struct ConstEval
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (cell->type == ID($macc))
 | 
			
		||||
		else if (cell->type.in(ID($macc), ID($macc_v2)))
 | 
			
		||||
		{
 | 
			
		||||
			Macc macc;
 | 
			
		||||
			macc.from_cell(cell);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -276,3 +276,11 @@ X(Y)
 | 
			
		|||
X(Y_WIDTH)
 | 
			
		||||
X(area)
 | 
			
		||||
X(capacitance)
 | 
			
		||||
X(NPRODUCTS)
 | 
			
		||||
X(NADDENDS)
 | 
			
		||||
X(PRODUCT_NEGATED)
 | 
			
		||||
X(ADDEND_NEGATED)
 | 
			
		||||
X(A_WIDTHS)
 | 
			
		||||
X(B_WIDTHS)
 | 
			
		||||
X(C_WIDTHS)
 | 
			
		||||
X(C_SIGNED)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										160
									
								
								kernel/macc.h
									
										
									
									
									
								
							
							
						
						
									
										160
									
								
								kernel/macc.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -82,7 +82,7 @@ struct Macc
 | 
			
		|||
		new_ports.swap(ports);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void from_cell(RTLIL::Cell *cell)
 | 
			
		||||
	void from_cell_v1(RTLIL::Cell *cell)
 | 
			
		||||
	{
 | 
			
		||||
		RTLIL::SigSpec port_a = cell->getPort(ID::A);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -136,52 +136,128 @@ struct Macc
 | 
			
		|||
		log_assert(port_a_cursor == GetSize(port_a));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void to_cell(RTLIL::Cell *cell) const
 | 
			
		||||
	void from_cell(RTLIL::Cell *cell)
 | 
			
		||||
	{
 | 
			
		||||
		RTLIL::SigSpec port_a;
 | 
			
		||||
		std::vector<RTLIL::State> config_bits;
 | 
			
		||||
		int max_size = 0, num_bits = 0;
 | 
			
		||||
		if (cell->type == ID($macc)) {
 | 
			
		||||
			from_cell_v1(cell);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		log_assert(cell->type == ID($macc_v2));
 | 
			
		||||
 | 
			
		||||
		for (auto &port : ports) {
 | 
			
		||||
			max_size = max(max_size, GetSize(port.in_a));
 | 
			
		||||
			max_size = max(max_size, GetSize(port.in_b));
 | 
			
		||||
		RTLIL::SigSpec port_a = cell->getPort(ID::A);
 | 
			
		||||
		RTLIL::SigSpec port_b = cell->getPort(ID::B);
 | 
			
		||||
		RTLIL::SigSpec port_c = cell->getPort(ID::C);
 | 
			
		||||
 | 
			
		||||
		ports.clear();
 | 
			
		||||
 | 
			
		||||
		int nproducts = cell->getParam(ID::NPRODUCTS).as_int();
 | 
			
		||||
		const Const &product_neg = cell->getParam(ID::PRODUCT_NEGATED);
 | 
			
		||||
		const Const &a_widths = cell->getParam(ID::A_WIDTHS);
 | 
			
		||||
		const Const &b_widths = cell->getParam(ID::B_WIDTHS);
 | 
			
		||||
		const Const &a_signed = cell->getParam(ID::A_SIGNED);
 | 
			
		||||
		const Const &b_signed = cell->getParam(ID::B_SIGNED);
 | 
			
		||||
		int ai = 0, bi = 0;
 | 
			
		||||
		for (int i = 0; i < nproducts; i++) {
 | 
			
		||||
			port_t term;
 | 
			
		||||
 | 
			
		||||
			log_assert(a_signed[i] == b_signed[i]);
 | 
			
		||||
			term.is_signed = (a_signed[i] == State::S1);
 | 
			
		||||
			int a_width = a_widths.extract(16 * i, 16).as_int(false);
 | 
			
		||||
			int b_width = b_widths.extract(16 * i, 16).as_int(false);
 | 
			
		||||
 | 
			
		||||
			term.in_a = port_a.extract(ai, a_width);
 | 
			
		||||
			ai += a_width;
 | 
			
		||||
			term.in_b = port_b.extract(bi, b_width);
 | 
			
		||||
			bi += b_width;
 | 
			
		||||
			term.do_subtract = (product_neg[i] == State::S1);
 | 
			
		||||
 | 
			
		||||
			ports.push_back(term);
 | 
			
		||||
		}
 | 
			
		||||
		log_assert(port_a.size() == ai);
 | 
			
		||||
		log_assert(port_b.size() == bi);
 | 
			
		||||
 | 
			
		||||
		int naddends = cell->getParam(ID::NADDENDS).as_int();
 | 
			
		||||
		const Const &addend_neg = cell->getParam(ID::ADDEND_NEGATED);
 | 
			
		||||
		const Const &c_widths = cell->getParam(ID::C_WIDTHS);
 | 
			
		||||
		const Const &c_signed = cell->getParam(ID::C_SIGNED);
 | 
			
		||||
		int ci = 0;
 | 
			
		||||
		for (int i = 0; i < naddends; i++) {
 | 
			
		||||
			port_t term;
 | 
			
		||||
 | 
			
		||||
			term.is_signed = (c_signed[i] == State::S1);
 | 
			
		||||
			int c_width = c_widths.extract(16 * i, 16).as_int(false);
 | 
			
		||||
 | 
			
		||||
			term.in_a = port_c.extract(ci, c_width);
 | 
			
		||||
			ci += c_width;
 | 
			
		||||
			term.do_subtract = (addend_neg[i] == State::S1);
 | 
			
		||||
 | 
			
		||||
			ports.push_back(term);
 | 
			
		||||
		}
 | 
			
		||||
		log_assert(port_c.size() == ci);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void to_cell(RTLIL::Cell *cell)
 | 
			
		||||
	{
 | 
			
		||||
		cell->type = ID($macc_v2);
 | 
			
		||||
 | 
			
		||||
		int nproducts = 0, naddends = 0;
 | 
			
		||||
		Const a_signed, b_signed, a_widths, b_widths, product_negated;
 | 
			
		||||
		Const c_signed, c_widths, addend_negated;
 | 
			
		||||
		SigSpec a, b, c;
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < (int) ports.size(); i++) {
 | 
			
		||||
			SigSpec term_a = ports[i].in_a, term_b = ports[i].in_b;
 | 
			
		||||
 | 
			
		||||
			if (term_b.empty()) {
 | 
			
		||||
				// addend
 | 
			
		||||
				c_widths.append(Const(term_a.size(), 16));
 | 
			
		||||
				c_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
 | 
			
		||||
				addend_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
 | 
			
		||||
				c.append(term_a);
 | 
			
		||||
				naddends++;
 | 
			
		||||
			} else {
 | 
			
		||||
				// product
 | 
			
		||||
				a_widths.append(Const(term_a.size(), 16));
 | 
			
		||||
				b_widths.append(Const(term_b.size(), 16));
 | 
			
		||||
				a_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
 | 
			
		||||
				b_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
 | 
			
		||||
				product_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
 | 
			
		||||
				a.append(term_a);
 | 
			
		||||
				b.append(term_b);
 | 
			
		||||
				nproducts++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		while (max_size)
 | 
			
		||||
			num_bits++, max_size /= 2;
 | 
			
		||||
		if (a_signed.empty())
 | 
			
		||||
			a_signed = {RTLIL::Sx};
 | 
			
		||||
		if (b_signed.empty())
 | 
			
		||||
			b_signed = {RTLIL::Sx};
 | 
			
		||||
		if (c_signed.empty())
 | 
			
		||||
			c_signed = {RTLIL::Sx};
 | 
			
		||||
		if (a_widths.empty())
 | 
			
		||||
			a_widths = {RTLIL::Sx};
 | 
			
		||||
		if (b_widths.empty())
 | 
			
		||||
			b_widths = {RTLIL::Sx};
 | 
			
		||||
		if (c_widths.empty())
 | 
			
		||||
			c_widths = {RTLIL::Sx};
 | 
			
		||||
		if (product_negated.empty())
 | 
			
		||||
			product_negated = {RTLIL::Sx};
 | 
			
		||||
		if (addend_negated.empty())
 | 
			
		||||
			addend_negated = {RTLIL::Sx};
 | 
			
		||||
 | 
			
		||||
		log_assert(num_bits < 16);
 | 
			
		||||
		config_bits.push_back(num_bits & 1 ? State::S1 : State::S0);
 | 
			
		||||
		config_bits.push_back(num_bits & 2 ? State::S1 : State::S0);
 | 
			
		||||
		config_bits.push_back(num_bits & 4 ? State::S1 : State::S0);
 | 
			
		||||
		config_bits.push_back(num_bits & 8 ? State::S1 : State::S0);
 | 
			
		||||
 | 
			
		||||
		for (auto &port : ports)
 | 
			
		||||
		{
 | 
			
		||||
			if (GetSize(port.in_a) == 0)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			config_bits.push_back(port.is_signed ? State::S1 : State::S0);
 | 
			
		||||
			config_bits.push_back(port.do_subtract ? State::S1 : State::S0);
 | 
			
		||||
 | 
			
		||||
			int size_a = GetSize(port.in_a);
 | 
			
		||||
			for (int i = 0; i < num_bits; i++)
 | 
			
		||||
				config_bits.push_back(size_a & (1 << i) ? State::S1 : State::S0);
 | 
			
		||||
 | 
			
		||||
			int size_b = GetSize(port.in_b);
 | 
			
		||||
			for (int i = 0; i < num_bits; i++)
 | 
			
		||||
				config_bits.push_back(size_b & (1 << i) ? State::S1 : State::S0);
 | 
			
		||||
 | 
			
		||||
			port_a.append(port.in_a);
 | 
			
		||||
			port_a.append(port.in_b);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cell->setPort(ID::A, port_a);
 | 
			
		||||
		cell->setPort(ID::B, {});
 | 
			
		||||
		cell->setParam(ID::CONFIG, config_bits);
 | 
			
		||||
		cell->setParam(ID::CONFIG_WIDTH, GetSize(config_bits));
 | 
			
		||||
		cell->setParam(ID::A_WIDTH, GetSize(port_a));
 | 
			
		||||
		cell->setParam(ID::B_WIDTH, 0);
 | 
			
		||||
		cell->setParam(ID::NPRODUCTS, nproducts);
 | 
			
		||||
		cell->setParam(ID::PRODUCT_NEGATED, product_negated);
 | 
			
		||||
		cell->setParam(ID::NADDENDS, naddends);
 | 
			
		||||
		cell->setParam(ID::ADDEND_NEGATED, addend_negated);
 | 
			
		||||
		cell->setParam(ID::A_SIGNED, a_signed);
 | 
			
		||||
		cell->setParam(ID::B_SIGNED, b_signed);
 | 
			
		||||
		cell->setParam(ID::C_SIGNED, c_signed);
 | 
			
		||||
		cell->setParam(ID::A_WIDTHS, a_widths);
 | 
			
		||||
		cell->setParam(ID::B_WIDTHS, b_widths);
 | 
			
		||||
		cell->setParam(ID::C_WIDTHS, c_widths);
 | 
			
		||||
		cell->setPort(ID::A, a);
 | 
			
		||||
		cell->setPort(ID::B, b);
 | 
			
		||||
		cell->setPort(ID::C, c);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool eval(RTLIL::Const &result) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -540,6 +540,12 @@ void RTLIL::Const::bitvectorize() const {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RTLIL::Const::append(const RTLIL::Const &other) {
 | 
			
		||||
	bitvectorize();
 | 
			
		||||
	bitvectype& bv = get_bits();
 | 
			
		||||
	bv.insert(bv.end(), other.begin(), other.end());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RTLIL::State RTLIL::Const::const_iterator::operator*() const {
 | 
			
		||||
	if (auto bv = parent.get_if_bits())
 | 
			
		||||
		return (*bv)[idx];
 | 
			
		||||
| 
						 | 
				
			
			@ -1461,6 +1467,40 @@ namespace {
 | 
			
		|||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (cell->type == ID($macc_v2)) {
 | 
			
		||||
				if (param(ID::NPRODUCTS) < 0)
 | 
			
		||||
					error(__LINE__);
 | 
			
		||||
				if (param(ID::NADDENDS) < 0)
 | 
			
		||||
					error(__LINE__);
 | 
			
		||||
				param_bits(ID::PRODUCT_NEGATED, max(param(ID::NPRODUCTS), 1));
 | 
			
		||||
				param_bits(ID::ADDEND_NEGATED, max(param(ID::NADDENDS), 1));
 | 
			
		||||
				param_bits(ID::A_SIGNED, max(param(ID::NPRODUCTS), 1));
 | 
			
		||||
				param_bits(ID::B_SIGNED, max(param(ID::NPRODUCTS), 1));
 | 
			
		||||
				param_bits(ID::C_SIGNED, max(param(ID::NADDENDS), 1));
 | 
			
		||||
				if (cell->getParam(ID::A_SIGNED) != cell->getParam(ID::B_SIGNED))
 | 
			
		||||
					error(__LINE__);
 | 
			
		||||
				param_bits(ID::A_WIDTHS, max(param(ID::NPRODUCTS) * 16, 1));
 | 
			
		||||
				param_bits(ID::B_WIDTHS, max(param(ID::NPRODUCTS) * 16, 1));
 | 
			
		||||
				param_bits(ID::C_WIDTHS, max(param(ID::NADDENDS) * 16, 1));
 | 
			
		||||
				const Const &a_width = cell->getParam(ID::A_WIDTHS);
 | 
			
		||||
				const Const &b_width = cell->getParam(ID::B_WIDTHS);
 | 
			
		||||
				const Const &c_width = cell->getParam(ID::C_WIDTHS);
 | 
			
		||||
				int a_width_sum = 0, b_width_sum = 0, c_width_sum = 0;
 | 
			
		||||
				for (int i = 0; i < param(ID::NPRODUCTS); i++) {
 | 
			
		||||
					a_width_sum += a_width.extract(16 * i, 16).as_int(false);
 | 
			
		||||
					b_width_sum += b_width.extract(16 * i, 16).as_int(false);
 | 
			
		||||
				}
 | 
			
		||||
				for (int i = 0; i < param(ID::NADDENDS); i++) {
 | 
			
		||||
					c_width_sum += c_width.extract(16 * i, 16).as_int(false);
 | 
			
		||||
				}
 | 
			
		||||
				port(ID::A, a_width_sum);
 | 
			
		||||
				port(ID::B, b_width_sum);
 | 
			
		||||
				port(ID::C, c_width_sum);
 | 
			
		||||
				port(ID::Y, param(ID::Y_WIDTH));
 | 
			
		||||
				check_expected();
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (cell->type == ID($logic_not)) {
 | 
			
		||||
				param_bool(ID::A_SIGNED);
 | 
			
		||||
				port(ID::A, param(ID::A_WIDTH));
 | 
			
		||||
| 
						 | 
				
			
			@ -4093,6 +4133,11 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (type == ID($macc_v2)) {
 | 
			
		||||
		parameters[ID::Y_WIDTH] = GetSize(connections_[ID::Y]);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool signedness_ab = !type.in(ID($slice), ID($concat), ID($macc));
 | 
			
		||||
 | 
			
		||||
	if (connections_.count(ID::A)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -738,6 +738,8 @@ public:
 | 
			
		|||
	bool empty() const;
 | 
			
		||||
	void bitvectorize() const;
 | 
			
		||||
 | 
			
		||||
	void append(const RTLIL::Const &other);
 | 
			
		||||
 | 
			
		||||
	class const_iterator {
 | 
			
		||||
	private:
 | 
			
		||||
		const Const& parent;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -740,7 +740,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
 | 
			
		|||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cell->type == ID($macc))
 | 
			
		||||
	if (cell->type.in(ID($macc), ID($macc_v2)))
 | 
			
		||||
	{
 | 
			
		||||
		std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
 | 
			
		||||
		std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -218,7 +218,7 @@ struct BoothPassWorker {
 | 
			
		|||
 | 
			
		||||
				log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool());
 | 
			
		||||
				is_signed = cell->getParam(ID::A_SIGNED).as_bool();
 | 
			
		||||
			} else if (cell->type == ID($macc)) {
 | 
			
		||||
			} else if (cell->type.in(ID($macc), ID($macc_v2))) {
 | 
			
		||||
				Macc macc;
 | 
			
		||||
				macc.from_cell(cell);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -403,7 +403,7 @@ struct MaccmapPass : public Pass {
 | 
			
		|||
 | 
			
		||||
		for (auto mod : design->selected_modules())
 | 
			
		||||
		for (auto cell : mod->selected_cells())
 | 
			
		||||
			if (cell->type == ID($macc)) {
 | 
			
		||||
			if (cell->type.in(ID($macc), ID($macc_v2))) {
 | 
			
		||||
				log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type));
 | 
			
		||||
				maccmap(mod, cell, unmap_mode);
 | 
			
		||||
				mod->remove(cell);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -554,8 +554,8 @@ struct TechmapWorker
 | 
			
		|||
 | 
			
		||||
							if (extmapper_name == "maccmap") {
 | 
			
		||||
								log("Creating %s with maccmap.\n", log_id(extmapper_module));
 | 
			
		||||
								if (extmapper_cell->type != ID($macc))
 | 
			
		||||
									log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type));
 | 
			
		||||
								if (!extmapper_cell->type.in(ID($macc), ID($macc_v2)))
 | 
			
		||||
									log_error("The maccmap mapper can only map $macc/$macc_v2 (not %s) cells!\n", log_id(extmapper_cell->type));
 | 
			
		||||
								maccmap(extmapper_module, extmapper_cell);
 | 
			
		||||
								extmapper_module->remove(extmapper_cell);
 | 
			
		||||
							}
 | 
			
		||||
| 
						 | 
				
			
			@ -600,8 +600,8 @@ struct TechmapWorker
 | 
			
		|||
						}
 | 
			
		||||
 | 
			
		||||
						if (extmapper_name == "maccmap") {
 | 
			
		||||
							if (cell->type != ID($macc))
 | 
			
		||||
								log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type));
 | 
			
		||||
							if (!cell->type.in(ID($macc), ID($macc_v2)))
 | 
			
		||||
								log_error("The maccmap mapper can only map $macc/$macc_v2 (not %s) cells!\n", log_id(cell->type));
 | 
			
		||||
							maccmap(module, cell);
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1207,6 +1207,120 @@ end
 | 
			
		|||
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
// --------------------------------------------------------
 | 
			
		||||
//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
			
		||||
//-
 | 
			
		||||
//-     $macc_v2 (A, B, C, Y)
 | 
			
		||||
//* group arith
 | 
			
		||||
//-
 | 
			
		||||
//- Multiply and add.
 | 
			
		||||
//- This cell represents a generic fused multiply-add operation, it supersedes the
 | 
			
		||||
//- earlier $macc cell.
 | 
			
		||||
//-
 | 
			
		||||
module \$macc_v2 (A, B, C, Y);
 | 
			
		||||
 | 
			
		||||
parameter NPRODUCTS = 0;
 | 
			
		||||
parameter NADDENDS = 0;
 | 
			
		||||
parameter A_WIDTHS = 16'h0000;
 | 
			
		||||
parameter B_WIDTHS = 16'h0000;
 | 
			
		||||
parameter C_WIDTHS = 16'h0000;
 | 
			
		||||
parameter Y_WIDTH = 0;
 | 
			
		||||
 | 
			
		||||
parameter PRODUCT_NEGATED = 1'bx;
 | 
			
		||||
parameter ADDEND_NEGATED = 1'bx;
 | 
			
		||||
parameter A_SIGNED = 1'bx;
 | 
			
		||||
parameter B_SIGNED = 1'bx;
 | 
			
		||||
parameter C_SIGNED = 1'bx;
 | 
			
		||||
 | 
			
		||||
function integer sum_widths1;
 | 
			
		||||
	input [(16*NPRODUCTS)-1:0] widths;
 | 
			
		||||
	integer i;
 | 
			
		||||
	begin
 | 
			
		||||
		sum_widths1 = 0;
 | 
			
		||||
		for (i = 0; i < NPRODUCTS; i++) begin
 | 
			
		||||
			sum_widths1 = sum_widths1 + widths[16*i+:16];
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function integer sum_widths2;
 | 
			
		||||
	input [(16*NADDENDS)-1:0] widths;
 | 
			
		||||
	integer i;
 | 
			
		||||
	begin
 | 
			
		||||
		sum_widths2 = 0;
 | 
			
		||||
		for (i = 0; i < NADDENDS; i++) begin
 | 
			
		||||
			sum_widths2 = sum_widths2 + widths[16*i+:16];
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
input [sum_widths1(A_WIDTHS)-1:0] A; // concatenation of LHS factors
 | 
			
		||||
input [sum_widths1(B_WIDTHS)-1:0] B; // concatenation of RHS factors
 | 
			
		||||
input [sum_widths2(C_WIDTHS)-1:0] C; // concatenation of summands
 | 
			
		||||
output reg [Y_WIDTH-1:0] Y; // output sum
 | 
			
		||||
 | 
			
		||||
integer i, j, ai, bi, ci, aw, bw, cw;
 | 
			
		||||
reg [Y_WIDTH-1:0] product;
 | 
			
		||||
reg [Y_WIDTH-1:0] addend, oper_a, oper_b;
 | 
			
		||||
 | 
			
		||||
always @* begin
 | 
			
		||||
	Y = 0;
 | 
			
		||||
	ai = 0;
 | 
			
		||||
	bi = 0;
 | 
			
		||||
	for (i = 0; i < NPRODUCTS; i = i+1)
 | 
			
		||||
	begin
 | 
			
		||||
		aw = A_WIDTHS[16*i+:16];
 | 
			
		||||
		bw = B_WIDTHS[16*i+:16];
 | 
			
		||||
 | 
			
		||||
		oper_a = 0;
 | 
			
		||||
		oper_b = 0;
 | 
			
		||||
		for (j = 0; j < Y_WIDTH && j < aw; j = j + 1)
 | 
			
		||||
			oper_a[j] = A[ai + j];
 | 
			
		||||
		for (j = 0; j < Y_WIDTH && j < bw; j = j + 1)
 | 
			
		||||
			oper_b[j] = B[bi + j];
 | 
			
		||||
		// A_SIGNED[i] == B_SIGNED[i] as RTLIL invariant
 | 
			
		||||
		if (A_SIGNED[i] && B_SIGNED[i]) begin
 | 
			
		||||
			for (j = aw; j > 0 && j < Y_WIDTH; j = j + 1)
 | 
			
		||||
				oper_a[j] = oper_a[j - 1];
 | 
			
		||||
			for (j = bw; j > 0 && j < Y_WIDTH; j = j + 1)
 | 
			
		||||
				oper_b[j] = oper_b[j - 1];
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		product = oper_a * oper_b;
 | 
			
		||||
 | 
			
		||||
		if (PRODUCT_NEGATED[i])
 | 
			
		||||
			Y = Y - product;
 | 
			
		||||
		else
 | 
			
		||||
			Y = Y + product;
 | 
			
		||||
 | 
			
		||||
		ai = ai + aw;
 | 
			
		||||
		bi = bi + bw;
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	ci = 0;
 | 
			
		||||
	for (i = 0; i < NADDENDS; i = i+1)
 | 
			
		||||
	begin
 | 
			
		||||
		cw = C_WIDTHS[16*i+:16];
 | 
			
		||||
 | 
			
		||||
		addend = 0;
 | 
			
		||||
		for (j = 0; j < Y_WIDTH && j < cw; j = j + 1)
 | 
			
		||||
			addend[j] = C[ci + j];
 | 
			
		||||
		if (C_SIGNED[i]) begin
 | 
			
		||||
			for (j = cw; j > 0 && j < Y_WIDTH; j = j + 1)
 | 
			
		||||
				addend[j] = addend[j - 1];
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if (ADDEND_NEGATED[i])
 | 
			
		||||
			Y = Y - addend;
 | 
			
		||||
		else
 | 
			
		||||
			Y = Y + addend;
 | 
			
		||||
 | 
			
		||||
		ci = ci + cw;
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
// --------------------------------------------------------
 | 
			
		||||
//* ver 2
 | 
			
		||||
//* title Divider
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -290,7 +290,7 @@ module _90_alu (A, B, CI, BI, X, Y, CO);
 | 
			
		|||
endmodule
 | 
			
		||||
 | 
			
		||||
(* techmap_maccmap *)
 | 
			
		||||
(* techmap_celltype = "$macc" *)
 | 
			
		||||
(* techmap_celltype = "$macc $macc_v2" *)
 | 
			
		||||
module _90_macc;
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										61
									
								
								tests/alumacc/basic.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								tests/alumacc/basic.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
read_verilog <<EOF
 | 
			
		||||
module gate(input signed [2:0] a1, input signed [2:0] b1,
 | 
			
		||||
			input [1:0] a2, input [3:0] b2, input c, input d, output signed [3:0] y);
 | 
			
		||||
  wire signed [3:0] ab1;
 | 
			
		||||
  assign ab1 = a1 * b1;
 | 
			
		||||
  assign y = ab1 + a2*b2 + c + d + 1;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
prep
 | 
			
		||||
equiv_opt -assert alumacc
 | 
			
		||||
design -load postopt
 | 
			
		||||
stat
 | 
			
		||||
design -save save
 | 
			
		||||
equiv_opt -assert maccmap
 | 
			
		||||
design -load save
 | 
			
		||||
equiv_opt -assert maccmap -unmap
 | 
			
		||||
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module gate(input signed [2:0] a1, input signed [1:0] b1, output signed [3:0] y);
 | 
			
		||||
  assign y = a1 * b1;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
prep
 | 
			
		||||
equiv_opt -assert alumacc
 | 
			
		||||
design -load postopt
 | 
			
		||||
stat
 | 
			
		||||
design -save save
 | 
			
		||||
equiv_opt -assert maccmap
 | 
			
		||||
design -load save
 | 
			
		||||
equiv_opt -assert maccmap -unmap
 | 
			
		||||
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module gate(input [2:0] a, input [1:0] b, output [3:0] y);
 | 
			
		||||
  assign y = a * b;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
prep
 | 
			
		||||
equiv_opt -assert alumacc
 | 
			
		||||
design -load postopt
 | 
			
		||||
stat
 | 
			
		||||
design -save save
 | 
			
		||||
equiv_opt -assert maccmap
 | 
			
		||||
design -load save
 | 
			
		||||
equiv_opt -assert maccmap -unmap
 | 
			
		||||
 | 
			
		||||
design -reset
 | 
			
		||||
read_verilog <<EOF
 | 
			
		||||
module gate(input [2:0] a, input [1:0] b, input [1:0] c, output [3:0] y);
 | 
			
		||||
  assign y = a * b - c;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
prep
 | 
			
		||||
equiv_opt -assert alumacc
 | 
			
		||||
design -load postopt
 | 
			
		||||
stat
 | 
			
		||||
design -save save
 | 
			
		||||
equiv_opt -assert maccmap
 | 
			
		||||
design -load save
 | 
			
		||||
equiv_opt -assert maccmap -unmap
 | 
			
		||||
							
								
								
									
										19
									
								
								tests/alumacc/macc_infer_n_unmap.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/alumacc/macc_infer_n_unmap.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
read_verilog <<EOF
 | 
			
		||||
module gate(input signed [2:0] a1, input signed [2:0] b1,
 | 
			
		||||
			input [1:0] a2, input [3:0] b2, input c, input d, output signed [3:0] y);
 | 
			
		||||
  wire signed [3:0] ab1;
 | 
			
		||||
  assign ab1 = a1 * b1;
 | 
			
		||||
  assign y = ab1 + a2*b2 + c + d + 1;
 | 
			
		||||
endmodule
 | 
			
		||||
EOF
 | 
			
		||||
prep
 | 
			
		||||
 | 
			
		||||
design -save gold
 | 
			
		||||
alumacc
 | 
			
		||||
opt_clean
 | 
			
		||||
select -assert-count 1 t:$macc_v2
 | 
			
		||||
maccmap -unmap
 | 
			
		||||
design -copy-from gold -as gold gate
 | 
			
		||||
equiv_make gold gate equiv
 | 
			
		||||
equiv_induct equiv
 | 
			
		||||
equiv_status -assert equiv
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue