diff --git a/ice40/arch.h b/ice40/arch.h index e67f2aa9..98361132 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -141,6 +141,7 @@ static const int max_switch_bits = 5; NPNR_PACKED_STRUCT(struct SwitchInfoPOD { int32_t num_bits; + int32_t bel; int8_t x, y; ConfigBitPOD cbits[max_switch_bits]; }); @@ -613,7 +614,16 @@ struct Arch : BaseCtx bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + int switch_idx = chip_info->pip_data[pip.index].switch_index; + + if (switches_locked[switch_idx] != IdString()) + return false; + + int bel_idx = chip_info->bits_info->switches[switch_idx].bel; + if (bel_idx >= 0 && bel_to_cell[bel_idx] != IdString()) + return false; + + return true; } IdString getBoundPipNet(PipId pip) const diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index d0d6b205..8b00e878 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -221,8 +221,21 @@ std::string tagTileType(TileType &tile) NPNR_ASSERT(false); } } + +static BelPin get_one_bel_pin(const Context *ctx, WireId wire) +{ + auto pins = ctx->getWireBelPins(wire); + NPNR_ASSERT(pins.begin() != pins.end()); + return *pins.begin(); +} + void write_asc(const Context *ctx, std::ostream &out) { + + static const std::vector lut_perm = { + 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, + }; + // [y][x][row][col] const ChipInfoPOD &ci = *ctx->chip_info; const BitstreamInfoPOD &bi = *ci.bits_info; @@ -262,12 +275,50 @@ void write_asc(const Context *ctx, std::ostream &out) if (ctx->pip_to_net[pip.index] != IdString()) { const PipInfoPOD &pi = ci.pip_data[pip.index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; - for (int i = 0; i < swi.num_bits; i++) { - bool val = (pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0; - int8_t &cbit = config.at(swi.y).at(swi.x).at(swi.cbits[i].row).at(swi.cbits[i].col); - if (bool(cbit) != 0) - NPNR_ASSERT(false); - cbit = val; + int sw_bel_idx = swi.bel; + if (sw_bel_idx >= 0) { + const BelInfoPOD &beli = ci.bel_data[sw_bel_idx]; + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; + 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)); + 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: + lut_init = 2; + break; + case PIN_I1: + lut_init = 4; + break; + case PIN_I2: + lut_init = 16; + break; + case PIN_I3: + lut_init = 256; + break; + default: + NPNR_ASSERT_FALSE("bad feedthru LUT input"); + } + std::vector lc(20, false); + for (int i = 0; i < 16; i++) { + if ((lut_init >> i) & 0x1) + lc.at(lut_perm.at(i)) = true; + } + + for (int i = 0; i < 20; i++) + set_config(ti, config.at(beli.y).at(beli.x), "LC_" + std::to_string(beli.z), lc.at(i), i); + } else { + for (int i = 0; i < swi.num_bits; i++) { + bool val = (pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0; + int8_t &cbit = config.at(swi.y).at(swi.x).at(swi.cbits[i].row).at(swi.cbits[i].col); + if (bool(cbit) != 0) + NPNR_ASSERT(false); + cbit = val; + } } } } @@ -295,9 +346,7 @@ void write_asc(const Context *ctx, std::ostream &out) bool carry_enable = get_param_or_def(cell.second.get(), ctx->id("CARRY_ENABLE")); std::vector lc(20, false); // From arachne-pnr - static std::vector lut_perm = { - 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, - }; + for (int i = 0; i < 16; i++) { if ((lut_init >> i) & 0x1) lc.at(lut_perm.at(i)) = true; diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 3f9f4e65..a0d7f03c 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -271,6 +271,16 @@ def pipdelay(src_idx, dst_idx, db): if re.match(r"ram/(MASK|RADDR|WADDR|WDATA)_", dst[2]): return db["InMux.I.O"] + if re.match(r"lutff_\d+/out", dst[2]): + if re.match(r"lutff_\d+/in_0", src[2]): + return db["LogicCell40.in0.lcout"] + if re.match(r"lutff_\d+/in_1", src[2]): + return db["LogicCell40.in1.lcout"] + if re.match(r"lutff_\d+/in_2", src[2]): + return db["LogicCell40.in2.lcout"] + if re.match(r"lutff_\d+/in_3", src[2]): + return db["LogicCell40.in3.lcout"] + print(src, dst, src_idx, dst_idx, src_type, dst_type, file=sys.stderr) assert 0 @@ -316,12 +326,12 @@ with open(args.filename, "r") as f: if line[0] == ".buffer": mode = ("buffer", int(line[3]), int(line[1]), int(line[2])) - switches.append((line[3], int(line[1]), int(line[2]), line[4:])) + switches.append((int(line[1]), int(line[2]), line[4:], -1)) continue if line[0] == ".routing": mode = ("routing", int(line[3]), int(line[1]), int(line[2])) - switches.append((line[3], int(line[1]), int(line[2]), line[4:])) + switches.append((int(line[1]), int(line[2]), line[4:], -1)) continue if line[0] == ".io_tile": @@ -499,6 +509,22 @@ def add_wire(x, y, name): wire_names_r[wire_idx] = wname wire_segments[wire_idx] = dict() +def add_switch(x, y, bel=-1): + switches.append((x, y, [], bel)) + +def add_pip(src, dst): + x, y, _, _ = switches[-1] + + if src not in wire_downhill: + wire_downhill[src] = set() + wire_downhill[src].add(dst) + + if dst not in wire_uphill: + wire_uphill[dst] = set() + wire_uphill[dst].add(src) + + pip_xy[(src, dst)] = (x, y, 0, len(switches) - 1) + # Add virtual padin wires for i in range(8): add_wire(0, 0, "padin_%d" % i) @@ -555,6 +581,13 @@ def add_bel_lc(x, y, z): if wire_lout is not None: add_bel_output(bel, wire_lout, "LO") + # route-through LUTs + add_switch(x, y, bel) + add_pip(wire_in_0, wire_out) + add_pip(wire_in_1, wire_out) + add_pip(wire_in_2, wire_out) + add_pip(wire_in_3, wire_out) + def add_bel_io(x, y, z): bel = len(bel_name) bel_name.append("X%d/Y%d/io%d" % (x, y, z)) @@ -1050,7 +1083,7 @@ for info in pipinfo: switchinfo = [] for switch in switches: - dst, x, y, bits = switch + x, y, bits, bel = switch bitlist = [] for b in bits: m = cbit_re.match(b) @@ -1060,11 +1093,13 @@ for switch in switches: si["x"] = x si["y"] = y si["bits"] = bitlist + si["bel"] = bel switchinfo.append(si) bba.l("switch_data_%s" % dev_name, "SwitchInfoPOD") for info in switchinfo: bba.u32(len(info["bits"]), "num_bits") + bba.u32(info["bel"], "bel") bba.u8(info["x"], "x") bba.u8(info["y"], "y") for i in range(5): diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 0798862a..924fe964 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -696,11 +696,30 @@ void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, { float x1, y1, x2, y2; - if (getWireXY_main(src, x1, y1) && getWireXY_main(dst, x2, y2)) + if (getWireXY_main(src, x1, y1) && getWireXY_main(dst, x2, y2)) { pipGfx(g, x, y, x1, y1, x2, y2, main_swbox_x1, main_swbox_y1, main_swbox_x2, main_swbox_y2, style); + return; + } - if (getWireXY_local(src, x1, y1) && getWireXY_local(dst, x2, y2)) + if (getWireXY_local(src, x1, y1) && getWireXY_local(dst, x2, y2)) { pipGfx(g, x, y, x1, y1, x2, y2, local_swbox_x1, local_swbox_y1, local_swbox_x2, local_swbox_y2, style); + return; + } + + if (TILE_WIRE_LUTFF_0_IN_0 <= src && src <= TILE_WIRE_LUTFF_7_IN_3 && TILE_WIRE_LUTFF_0_OUT <= dst && dst <= TILE_WIRE_LUTFF_7_OUT) { + int lut_idx = (src - TILE_WIRE_LUTFF_0_IN_0) / 4; + int in_idx = (src - TILE_WIRE_LUTFF_0_IN_0) % 4; + + GraphicElement el; + el.type = GraphicElement::TYPE_ARROW; + el.style = style; + el.x1 = x + logic_cell_x1; + el.x2 = x + logic_cell_x2; + el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * in_idx) + lut_idx * logic_cell_pitch; + el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 + lut_idx * logic_cell_pitch; + g.push_back(el); + return; + } if (src == TILE_WIRE_CARRY_IN && dst == TILE_WIRE_CARRY_IN_MUX) { GraphicElement el; @@ -711,6 +730,7 @@ void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, el.y1 = y + 0.01; el.y2 = y + 0.02; g.push_back(el); + return; } }