1 /* 2 * yosys -- Yosys Open SYnthesis Suite 3 * 4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 */ 19 20 #ifndef MACC_H 21 #define MACC_H 22 23 #include "kernel/yosys.h" 24 25 YOSYS_NAMESPACE_BEGIN 26 27 struct Macc 28 { 29 struct port_t { 30 RTLIL::SigSpec in_a, in_b; 31 bool is_signed, do_subtract; 32 }; 33 34 std::vector<port_t> ports; 35 RTLIL::SigSpec bit_ports; 36 optimizeMacc37 void optimize(int width) 38 { 39 std::vector<port_t> new_ports; 40 RTLIL::SigSpec new_bit_ports; 41 RTLIL::Const off(0, width); 42 43 for (auto &port : ports) 44 { 45 if (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0) 46 continue; 47 48 if (GetSize(port.in_a) < GetSize(port.in_b)) 49 std::swap(port.in_a, port.in_b); 50 51 if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) { 52 bit_ports.append(port.in_a); 53 continue; 54 } 55 56 if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) { 57 RTLIL::Const v = port.in_a.as_const(); 58 if (GetSize(port.in_b)) 59 v = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width); 60 if (port.do_subtract) 61 off = const_sub(off, v, port.is_signed, port.is_signed, width); 62 else 63 off = const_add(off, v, port.is_signed, port.is_signed, width); 64 continue; 65 } 66 67 if (port.is_signed) { 68 while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == port.in_a[GetSize(port.in_a)-2]) 69 port.in_a.remove(GetSize(port.in_a)-1); 70 while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2]) 71 port.in_b.remove(GetSize(port.in_b)-1); 72 } else { 73 while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == State::S0) 74 port.in_a.remove(GetSize(port.in_a)-1); 75 while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == State::S0) 76 port.in_b.remove(GetSize(port.in_b)-1); 77 } 78 79 new_ports.push_back(port); 80 } 81 82 for (auto &bit : bit_ports) 83 if (bit == State::S1) 84 off = const_add(off, RTLIL::Const(1, width), false, false, width); 85 else if (bit != State::S0) 86 new_bit_ports.append(bit); 87 88 if (off.as_bool()) { 89 port_t port; 90 port.in_a = off; 91 port.is_signed = false; 92 port.do_subtract = false; 93 new_ports.push_back(port); 94 } 95 96 new_ports.swap(ports); 97 bit_ports = new_bit_ports; 98 } 99 from_cellMacc100 void from_cell(RTLIL::Cell *cell) 101 { 102 RTLIL::SigSpec port_a = cell->getPort(ID::A); 103 104 ports.clear(); 105 bit_ports = cell->getPort(ID::B); 106 107 std::vector<RTLIL::State> config_bits = cell->getParam(ID::CONFIG).bits; 108 int config_cursor = 0; 109 110 int config_width = cell->getParam(ID::CONFIG_WIDTH).as_int(); 111 log_assert(GetSize(config_bits) >= config_width); 112 113 int num_bits = 0; 114 if (config_bits[config_cursor++] == State::S1) num_bits |= 1; 115 if (config_bits[config_cursor++] == State::S1) num_bits |= 2; 116 if (config_bits[config_cursor++] == State::S1) num_bits |= 4; 117 if (config_bits[config_cursor++] == State::S1) num_bits |= 8; 118 119 int port_a_cursor = 0; 120 while (port_a_cursor < GetSize(port_a)) 121 { 122 log_assert(config_cursor + 2 + 2*num_bits <= config_width); 123 124 port_t this_port; 125 this_port.is_signed = config_bits[config_cursor++] == State::S1; 126 this_port.do_subtract = config_bits[config_cursor++] == State::S1; 127 128 int size_a = 0; 129 for (int i = 0; i < num_bits; i++) 130 if (config_bits[config_cursor++] == State::S1) 131 size_a |= 1 << i; 132 133 this_port.in_a = port_a.extract(port_a_cursor, size_a); 134 port_a_cursor += size_a; 135 136 int size_b = 0; 137 for (int i = 0; i < num_bits; i++) 138 if (config_bits[config_cursor++] == State::S1) 139 size_b |= 1 << i; 140 141 this_port.in_b = port_a.extract(port_a_cursor, size_b); 142 port_a_cursor += size_b; 143 144 if (size_a || size_b) 145 ports.push_back(this_port); 146 } 147 148 log_assert(config_cursor == config_width); 149 log_assert(port_a_cursor == GetSize(port_a)); 150 } 151 to_cellMacc152 void to_cell(RTLIL::Cell *cell) const 153 { 154 RTLIL::SigSpec port_a; 155 std::vector<RTLIL::State> config_bits; 156 int max_size = 0, num_bits = 0; 157 158 for (auto &port : ports) { 159 max_size = max(max_size, GetSize(port.in_a)); 160 max_size = max(max_size, GetSize(port.in_b)); 161 } 162 163 while (max_size) 164 num_bits++, max_size /= 2; 165 166 log_assert(num_bits < 16); 167 config_bits.push_back(num_bits & 1 ? State::S1 : State::S0); 168 config_bits.push_back(num_bits & 2 ? State::S1 : State::S0); 169 config_bits.push_back(num_bits & 4 ? State::S1 : State::S0); 170 config_bits.push_back(num_bits & 8 ? State::S1 : State::S0); 171 172 for (auto &port : ports) 173 { 174 if (GetSize(port.in_a) == 0) 175 continue; 176 177 config_bits.push_back(port.is_signed ? State::S1 : State::S0); 178 config_bits.push_back(port.do_subtract ? State::S1 : State::S0); 179 180 int size_a = GetSize(port.in_a); 181 for (int i = 0; i < num_bits; i++) 182 config_bits.push_back(size_a & (1 << i) ? State::S1 : State::S0); 183 184 int size_b = GetSize(port.in_b); 185 for (int i = 0; i < num_bits; i++) 186 config_bits.push_back(size_b & (1 << i) ? State::S1 : State::S0); 187 188 port_a.append(port.in_a); 189 port_a.append(port.in_b); 190 } 191 192 cell->setPort(ID::A, port_a); 193 cell->setPort(ID::B, bit_ports); 194 cell->setParam(ID::CONFIG, config_bits); 195 cell->setParam(ID::CONFIG_WIDTH, GetSize(config_bits)); 196 cell->setParam(ID::A_WIDTH, GetSize(port_a)); 197 cell->setParam(ID::B_WIDTH, GetSize(bit_ports)); 198 } 199 evalMacc200 bool eval(RTLIL::Const &result) const 201 { 202 for (auto &bit : result.bits) 203 bit = State::S0; 204 205 for (auto &port : ports) 206 { 207 if (!port.in_a.is_fully_const() || !port.in_b.is_fully_const()) 208 return false; 209 210 RTLIL::Const summand; 211 if (GetSize(port.in_b) == 0) 212 summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result)); 213 else 214 summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result)); 215 216 if (port.do_subtract) 217 result = const_sub(result, summand, port.is_signed, port.is_signed, GetSize(result)); 218 else 219 result = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result)); 220 } 221 222 for (auto bit : bit_ports) { 223 if (bit.wire) 224 return false; 225 result = const_add(result, bit.data, false, false, GetSize(result)); 226 } 227 228 return true; 229 } 230 231 Macc(RTLIL::Cell *cell = nullptr) 232 { 233 if (cell != nullptr) 234 from_cell(cell); 235 } 236 }; 237 238 YOSYS_NAMESPACE_END 239 240 #endif 241