From b1f25d4b33a40666a2f483ee3875074c65c2ac68 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 22 Feb 2021 21:52:39 -0500 Subject: machxo2: Set Pip and Wire delays to reasonable fake values mirroring estimateDelay. --- machxo2/arch.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machxo2/arch.h b/machxo2/arch.h index cdbbe2b2..f5ccb4f6 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -514,7 +514,7 @@ struct Arch : BaseArch return IdStringList(ids); } - DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); } + DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0.01); } WireRange getWires() const override { @@ -587,7 +587,7 @@ struct Arch : BaseArch return wire; } - DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); } + DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0.01); } PipRange getPipsDownhill(WireId wire) const override { -- cgit v1.2.3 From ec239c8c35e24ea12c97bcdaa34425d1269d54ab Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 22 Feb 2021 22:33:47 -0500 Subject: machxo2: Hardcode a rule for emitting U_/D_ or G_ prefixes in ASCII output. --- machxo2/bitstream.cc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index f7e774cf..62d1be75 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -71,9 +71,24 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) name.find("JINCK") != std::string::npos); }; - if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || - prefix7 == "BRANCH_") + if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix7 == "BRANCH_") return basename; + + if (prefix2 == "U_" || prefix2 == "D_") { + // We needded to keep U_ and D_ prefixes to generate the routing + // graph connections properly, but in truth they are not relevant + // outside of the center row of tiles as far as the database is + // concerned. So convert U_/D_ prefixes back to G_ if not in the + // center row. + + // FIXME: This is hardcoded to 1200HC coordinates for now. Perhaps + // add a center row/col field to chipdb? + if (loc.y == 6) + return basename; + else + return "G_" + basename.substr(2); + } + if (loc == wire.location) { // TODO: JINCK is not currently handled by this. if (is_pio_wire(basename)) { -- cgit v1.2.3 From 45c33e9dcfb215493e31dc53a068b5dd1860a367 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 23 Feb 2021 06:51:40 -0500 Subject: machxo2: Add a special case for pips whose config bits are in multiple tiles. --- machxo2/bitstream.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 62d1be75..ed67975a 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -115,9 +115,21 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) static void set_pip(Context *ctx, ChipConfig &cc, PipId pip) { std::string tile = ctx->get_pip_tilename(pip); + std::string tile_type = ctx->chip_info->tiletype_names[ctx->tile_info(pip)->pips_data[pip.index].tile_type].get(); std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip)); std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip)); cc.tiles[tile].add_arc(sink, source); + + // Special case pips whose config bits are spread across tiles. + if (source == "G_PCLKCIBVIQT0" && sink == "G_VPRXCLKI0") { + if (tile_type == "CENTER7") { + cc.tiles[ctx->get_tile_by_type("CENTER8")].add_arc(sink, source); + } else if (tile_type == "CENTER8") { + cc.tiles[ctx->get_tile_by_type("CENTER7")].add_arc(sink, source); + } else { + NPNR_ASSERT_FALSE("Tile does not contain special-cased pip"); + } + } } static std::vector int_to_bitvector(int val, int size) -- cgit v1.2.3 From e625876949795ea3c0bc9b3071cbb45451cc1a16 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 13 Apr 2021 17:37:30 -0400 Subject: machxo2: Add VHDL primitives, demo, and script. --- machxo2/examples/README.md | 1 + machxo2/examples/demo-vhdl.sh | 24 ++++++++++++++++++++++++ machxo2/examples/prims.vhd | 18 ++++++++++++++++++ machxo2/examples/tinyfpga.vhd | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 machxo2/examples/demo-vhdl.sh create mode 100644 machxo2/examples/prims.vhd create mode 100644 machxo2/examples/tinyfpga.vhd diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index 3542da70..545afd26 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -20,6 +20,7 @@ This directory contains a simple example of running `nextpnr-machxo2`: * `demo.sh` creates bitstreams for [TinyFPGA Ax](https://tinyfpga.com/a-series-guide.html) and writes the resulting bitstream to MachXO2's internal flash using [`tinyproga`](https://github.com/tinyfpga/TinyFPGA-A-Programmer). + `demo-vhdl.sh` does the same, except using the [GHDL Yosys Plugin](https://github.com/ghdl/ghdl-yosys-plugin). As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, `mitertest.sh`, and `demo.sh` are subject to change. diff --git a/machxo2/examples/demo-vhdl.sh b/machxo2/examples/demo-vhdl.sh new file mode 100644 index 00000000..4bdab54a --- /dev/null +++ b/machxo2/examples/demo-vhdl.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +if [ $# -lt 1 ]; then + echo "Usage: $0 prefix" + exit -1 +fi + +if ! grep -q "LOC" $1.vhd; then + echo "$1.vhd does not have LOC constraints for tinyfpga_a." + exit -2 +fi + +if [ ! -z ${TRELLIS_DB+x} ]; then + DB_ARG="--db $TRELLIS_DB" +fi + +set -ex + +${YOSYS:-yosys} -p "ghdl --std=08 prims.vhd ${1}.vhd -e; + attrmap -tocase LOC + synth_machxo2 -json ${1}-vhdl.json" +${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json $1-vhdl.json --textcfg $1-vhdl.txt +ecppack --compress $DB_ARG $1-vhdl.txt $1-vhdl.bit +tinyproga -b $1-vhdl.bit diff --git a/machxo2/examples/prims.vhd b/machxo2/examples/prims.vhd new file mode 100644 index 00000000..928d1cea --- /dev/null +++ b/machxo2/examples/prims.vhd @@ -0,0 +1,18 @@ +library ieee; +use ieee.std_logic_1164.all; + +-- We don't have VHDL primitives yet, so declare them in examples for now. +package components is + +component OSCH + generic ( + NOM_FREQ : string := "2.08" + ); + port( + STDBY : in std_logic; + OSC : out std_logic; + SEDSTDBY : out std_logic + ); +end component; + +end components; diff --git a/machxo2/examples/tinyfpga.vhd b/machxo2/examples/tinyfpga.vhd new file mode 100644 index 00000000..29705728 --- /dev/null +++ b/machxo2/examples/tinyfpga.vhd @@ -0,0 +1,38 @@ +library ieee ; +context ieee.ieee_std_context; + +use work.components.all; + +entity top is + port ( + pin1: out std_logic + ); + + attribute LOC: string; + attribute LOC of pin1: signal is "13"; +end; + +architecture arch of top is + signal clk: std_logic; + signal led_timer: unsigned(23 downto 0) := (others=>'0'); +begin + + internal_oscillator_inst: OSCH + generic map ( + NOM_FREQ => "16.63" + ) + port map ( + STDBY => '0', + OSC => clk + ); + + process(clk) + begin + if rising_edge(clk) then + led_timer <= led_timer + 1; + end if; + end process; + + pin1 <= led_timer(led_timer'left); + +end; -- cgit v1.2.3 From 41d09f71871184aabbd7495a485e257fc0450d40 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 30 Jun 2021 15:23:09 -0400 Subject: machxo2: Fix packing for directly-connected DFFs. --- machxo2/cells.cc | 17 ++++++++++++----- machxo2/cells.h | 12 +++++++++++- machxo2/pack.cc | 8 +++++--- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 9b463147..7334234d 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -154,7 +154,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) replace_port(lut, ctx->id("Z"), lc, ctx->id("F0")); } -void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) +void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, LutType lut_type) { // FIXME: This will have to change once we support FFs with reset value of 1. lc->params[ctx->id("REG0_REGSET")] = std::string("RESET"); @@ -163,14 +163,21 @@ void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) replace_port(dff, ctx->id("LSR"), lc, ctx->id("LSR")); replace_port(dff, ctx->id("Q"), lc, ctx->id("Q0")); - // If a register's DI port is fed by a constant, options for placing are - // limited. Use the LUT to get around this. - if (pass_thru_lut) { + if (lut_type == LutType::PassThru) { + // If a register's DI port is fed by a constant, options for placing are + // limited. Use the LUT to get around this. + // LUT output will go to F0, which will feed back to DI0 input. lc->params[ctx->id("LUT0_INITVAL")] = Property(0xAAAA, 16); - ; replace_port(dff, ctx->id("DI"), lc, ctx->id("A0")); connect_ports(ctx, lc, ctx->id("F0"), lc, ctx->id("DI0")); + } else if (lut_type == LutType::None) { + // If there is no LUT, use the M0 input because DI0 requires + // going through the LUTs. + lc->params[ctx->id("REG0_SD")] = std::string("0"); + replace_port(dff, ctx->id("DI"), lc, ctx->id("M0")); } else { + // Otherwise, there's a LUT being used in the slice and mapping DI to + // DI0 input is fine. replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0")); } } diff --git a/machxo2/cells.h b/machxo2/cells.h index d26fdfa0..409b68b1 100644 --- a/machxo2/cells.h +++ b/machxo2/cells.h @@ -25,6 +25,16 @@ NEXTPNR_NAMESPACE_BEGIN +// When packing DFFs, we need context of how it's connected to a LUT to +// properly map DFF ports to FACADE_SLICEs; DI0 input muxes F0 and OFX0, +// and a DFF inside a slice can use either DI0 or M0 as an input. +enum class LutType +{ + None, + Normal, + PassThru, +}; + // Create a MachXO2 arch cell and return it // Name will be automatically assigned if not specified std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std::string name = ""); @@ -46,7 +56,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr // and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will // be configured as pass through and D connected to I0, otherwise D will be // ignored -void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false); +void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, LutType lut_type = LutType::Normal); // Convert a nextpnr IO buffer to a GENERIC_IOB void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool &todelete_cells); diff --git a/machxo2/pack.cc b/machxo2/pack.cc index a8a2a671..66d2d411 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -62,7 +62,7 @@ static void pack_lut_lutffs(Context *ctx) // Locations don't match, can't pack } else { lut_to_lc(ctx, ci, packed.get(), false); - dff_to_lc(ctx, dff, packed.get(), false); + dff_to_lc(ctx, dff, packed.get(), LutType::Normal); if (dff_bel != dff->attrs.end()) packed->attrs[ctx->id("BEL")] = dff_bel->second; packed_cells.insert(dff->name); @@ -105,7 +105,9 @@ static void pack_remaining_ffs(Context *ctx) packed->attrs[attr.first] = attr.second; auto dff_bel = ci->attrs.find(ctx->id("BEL")); - dff_to_lc(ctx, ci, packed.get(), false); + + dff_to_lc(ctx, ci, packed.get(), LutType::None); + if (dff_bel != ci->attrs.end()) packed->attrs[ctx->id("BEL")] = dff_bel->second; packed_cells.insert(ci->name); @@ -146,7 +148,7 @@ static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, boo for (auto &attr : uc->attrs) lc->attrs[attr.first] = attr.second; - dff_to_lc(ctx, uc, lc.get(), true); + dff_to_lc(ctx, uc, lc.get(), LutType::PassThru); packed_cells.insert(uc->name); lc->ports[id_A0].net = constnet; -- cgit v1.2.3