Merge pull request #747 from cr1901/machxo2

MachXO2 Checkpoint 1
This commit is contained in:
gatecat 2021-07-01 20:17:02 +01:00 committed by GitHub
commit fe38e70dc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 140 additions and 13 deletions

View File

@ -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
{

View File

@ -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)

View File

@ -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"));
}
}

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;