SigSpec B = st.sigB;
B.extend_u0(16, b_signed);
- SigSpec CD;
- bool CD_signed = false;
- if (st.muxAB != st.addAB) {
- if (st.muxA)
- CD = st.muxA->getPort("\\B");
- else if (st.muxB)
- CD = st.muxB->getPort("\\A");
- else log_abort();
- CD_signed = a_signed && b_signed; // TODO: Do muxes have [AB]_SIGNED?
- }
- else if (st.addAB) {
- if (st.addA)
- CD = st.addAB->getPort("\\B");
- else if (st.addB)
- CD = st.addAB->getPort("\\A");
- else log_abort();
- CD_signed = st.sigO_signed;
- }
- CD.extend_u0(32, CD_signed);
+ SigSpec CD = st.sigCD;
+ CD.extend_u0(32, st.sigCD_signed);
cell->setPort("\\A", A);
cell->setPort("\\B", B);
// SB_MAC16 Output Interface
- SigSpec O_lo = (st.ffO_lo ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH)).extract(0,16);
- if (GetSize(O_lo) < 16)
- O_lo.append(pm.module->addWire(NEW_ID, 16-GetSize(O_lo)));
- SigSpec O_hi = (st.ffO_hi ? st.sigO : (st.addAB ? st.addAB->getPort("\\Y") : st.sigH)).extract(16,16);
- if (GetSize(O_hi) < 16)
- O_hi.append(pm.module->addWire(NEW_ID, 16-GetSize(O_hi)));
-
- SigSpec O{O_hi,O_lo};
- cell->setPort("\\O", O);
+ cell->setPort("\\O", st.sigO);
bool accum = false;
if (st.addAB) {
- if (st.addA)
- accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == O);
- else if (st.addB)
- accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == O);
- else log_abort();
- if (accum)
- log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
- else
- log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
+ if (st.addA)
+ accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == st.sigO);
+ else if (st.addB)
+ accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == st.sigO);
+ else log_abort();
+ if (accum)
+ log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
+ else
+ log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
} else {
pm.autoremove(st.mul);
pm.autoremove(st.ffH);
pm.autoremove(st.addAB);
- if (st.ffO_lo)
- st.ffO_lo->connections_.at("\\Q").replace(O.extract(0,16), pm.module->addWire(NEW_ID, 16));
- if (st.ffO_hi)
- st.ffO_hi->connections_.at("\\Q").replace(O.extract(16,16), pm.module->addWire(NEW_ID, 16));
+ if (st.ffO_lo) {
+ SigSpec O = st.sigO.extract(0,16);
+ st.ffO_lo->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O)));
+ }
+ if (st.ffO_hi) {
+ SigSpec O = st.sigO.extract(16,16);
+ st.ffO_hi->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O)));
+ }
}
struct Ice40DspPass : public Pass {
endcode
match muxA
- if sigCD.empty()
select muxA->type.in($mux)
select nusers(port(muxA, \A)) == 2
index <SigSpec> port(muxA, \A) === sigO
endmatch
match muxB
- if sigCD.empty()
if !muxA
select muxB->type.in($mux)
select nusers(port(muxB, \B)) == 2
optional
endmatch
-code muxAB sigCD sigCD_signed sigO
- muxAB = addAB;
- if (muxA) {
+code muxAB
+ if (muxA)
muxAB = muxA;
- sigCD = port(muxAB, \B);
- }
- if (muxB) {
+ else if (muxB)
muxAB = muxB;
- sigCD = port(muxAB, \A);
- }
- if (muxA || muxB) {
- sigO = port(muxAB, \Y);
- sigCD_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool();
- }
endcode
match ffO_lo
optional
endmatch
-code clock clock_pol sigO
+code clock clock_pol sigO sigCD sigCD_signed
if (ffO_lo || ffO_hi) {
if (ffO_lo) {
SigBit c = port(ffO_lo, \CLK).as_bit();
if (port(ffO_hi, \Q) != sigO.extract(16,16))
sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q));
}
+
+ // Loading value into output register is not
+ // supported unless using accumulator
+ if (muxAB && sigCD != sigO) {
+ if (muxAB != addAB)
+ reject;
+
+ if (muxA)
+ sigCD = port(muxAB, \B);
+ else if (muxB)
+ sigCD = port(muxAB, \A);
+ else log_abort();
+ sigCD_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool();
+ }
}
endcode