aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--machxo2/arch.h4
-rw-r--r--machxo2/bitstream.cc31
-rw-r--r--machxo2/cells.cc17
-rw-r--r--machxo2/cells.h12
-rw-r--r--machxo2/examples/README.md1
-rw-r--r--machxo2/examples/demo-vhdl.sh24
-rw-r--r--machxo2/examples/prims.vhd18
-rw-r--r--machxo2/examples/tinyfpga.vhd38
-rw-r--r--machxo2/pack.cc8
9 files changed, 140 insertions, 13 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<ArchRanges>
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<ArchRanges>
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
{
diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc
index f7e774cf..ed67975a 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)) {
@@ -100,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<bool> int_to_bitvector(int val, int size)
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<CellInfo> 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<IdString> &todelete_cells);
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;
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;