aboutsummaryrefslogtreecommitdiffstats
path: root/ice40/bitstream.cc
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-08-04 18:08:07 +0200
committerDavid Shah <davey1576@gmail.com>2018-08-04 18:23:48 +0200
commit67347573c29c150c248c40e1145642323183c8ff (patch)
tree1c4616f8b8327e1fedece8573e478d2b6b2d081d /ice40/bitstream.cc
parent8aaf8456708a1d508b607f3fe1f06953ab14911b (diff)
downloadnextpnr-67347573c29c150c248c40e1145642323183c8ff.tar.gz
nextpnr-67347573c29c150c248c40e1145642323183c8ff.tar.bz2
nextpnr-67347573c29c150c248c40e1145642323183c8ff.zip
ice40: Bitstream gen for LUT permutation
Signed-off-by: David Shah <davey1576@gmail.com>
Diffstat (limited to 'ice40/bitstream.cc')
-rw-r--r--ice40/bitstream.cc86
1 files changed, 78 insertions, 8 deletions
diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc
index 8b00e878..40bd3e1f 100644
--- a/ice40/bitstream.cc
+++ b/ice40/bitstream.cc
@@ -229,6 +229,24 @@ static BelPin get_one_bel_pin(const Context *ctx, WireId wire)
return *pins.begin();
}
+// Permute LUT init value given map (LUT input -> ext input)
+unsigned permute_lut(unsigned orig_init, const std::unordered_map<int, int> &input_permute) {
+ unsigned new_init = 0;
+
+ for (int i = 0; i < 16; i++) {
+ int permute_address = 0;
+ for (int j = 0; j < 4; j++) {
+ if ((i >> j) & 0x1)
+ permute_address |= (1 << input_permute.at(j));
+ }
+ if ((orig_init >> i) & 0x1) {
+ new_init |= (1 << permute_address);
+ }
+ }
+
+ return new_init;
+}
+
void write_asc(const Context *ctx, std::ostream &out)
{
@@ -282,22 +300,33 @@ void write_asc(const Context *ctx, std::ostream &out)
BelId sw_bel;
sw_bel.index = sw_bel_idx;
NPNR_ASSERT(ctx->getBelType(sw_bel) == TYPE_ICESTORM_LC);
- BelPin input = get_one_bel_pin(ctx, ctx->getPipSrcWire(pip));
+
+ if (ci.wire_data[ctx->getPipDstWire(pip).index].type == WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT)
+ continue; // Permutation pips
BelPin output = get_one_bel_pin(ctx, ctx->getPipDstWire(pip));
- NPNR_ASSERT(input.bel == sw_bel);
NPNR_ASSERT(output.bel == sw_bel && output.pin == PIN_O);
unsigned lut_init;
- switch (input.pin) {
- case PIN_I0:
+
+ WireId permWire;
+ for (auto permPip : ctx->getPipsUphill(ctx->getPipSrcWire(pip))) {
+ if (ctx->getBoundPipNet(permPip) != IdString()) {
+ permWire = ctx->getPipSrcWire(permPip);
+ }
+ }
+ NPNR_ASSERT(permWire != WireId());
+ std::string dName = ci.wire_data[permWire.index].name.get();
+
+ switch (dName.back()) {
+ case '0':
lut_init = 2;
break;
- case PIN_I1:
+ case '1':
lut_init = 4;
break;
- case PIN_I2:
+ case '2':
lut_init = 16;
break;
- case PIN_I3:
+ case '3':
lut_init = 256;
break;
default:
@@ -345,8 +374,49 @@ void write_asc(const Context *ctx, std::ostream &out)
bool set_noreset = get_param_or_def(cell.second.get(), ctx->id("SET_NORESET"));
bool carry_enable = get_param_or_def(cell.second.get(), ctx->id("CARRY_ENABLE"));
std::vector<bool> lc(20, false);
- // From arachne-pnr
+ // Discover permutation
+ std::unordered_map<int, int> input_perm;
+ std::set<int> unused;
+ for (int i = 0; i < 4; i++)
+ unused.insert(i);
+ for (int i = 0; i < 4; i++) {
+ WireId lut_wire = ctx->getBelPinWire(bel, PortPin(PIN_I0+i));
+ for (auto pip : ctx->getPipsUphill(lut_wire)) {
+ if (ctx->getBoundPipNet(pip) != IdString()) {
+ std::string name = ci.wire_data[ctx->getPipSrcWire(pip).index].name.get();
+ switch(name.back()) {
+ case '0':
+ input_perm[i] = 0;
+ unused.erase(0);
+ break;
+ case '1':
+ input_perm[i] = 1;
+ unused.erase(1);
+ break;
+ case '2':
+ input_perm[i] = 2;
+ unused.erase(2);
+ break;
+ case '3':
+ input_perm[i] = 3;
+ unused.erase(3);
+ break;
+ default:
+ NPNR_ASSERT_FALSE("failed to determine LUT permutation");
+ }
+ break;
+ }
+ }
+ }
+ for (int i = 0; i < 4; i++) {
+ if (!input_perm.count(i)) {
+ NPNR_ASSERT(!unused.empty());
+ input_perm[i] = *(unused.begin());
+ unused.erase(input_perm[i]);
+ }
+ }
+ lut_init = permute_lut(lut_init, input_perm);
for (int i = 0; i < 16; i++) {
if ((lut_init >> i) & 0x1)
lc.at(lut_perm.at(i)) = true;