Skip to content

Commit

Permalink
Add support for MUX2_LUT5 (#52)
Browse files Browse the repository at this point in the history
* Add support for MUX2_LUT5

Both packing and unpacking are supported. Unpacking creates MUX2 primitive.

Signed-off-by: YRabbit <[email protected]>

* Leave LUTs as LUTS

Signed-off-by: YRabbit <[email protected]>

* Swap I0 I1

Signed-off-by: YRabbit <[email protected]>

* Fix the mux wiring diagram

Signed-off-by: YRabbit <[email protected]>

* LUT8

Signed-off-by: YRabbit <[email protected]>

* Fix gowin unpack

Signed-off-by: YRabbit <[email protected]>

* Fix unpack

Signed-off-by: YRabbit <[email protected]>

* do not execute match twice

* ignore dummy pips

Co-authored-by: Pepijn de Vos <[email protected]>
  • Loading branch information
yrabbit and pepijndevos authored Oct 12, 2021
1 parent 10fb338 commit 4140d04
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 10 deletions.
10 changes: 6 additions & 4 deletions apycula/gowin_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ def sanitize_name(name):
return f"\{retname} "

def get_bels(data):
belre = re.compile(r"R(\d+)C(\d+)_(?:SLICE|IOB)(\w)")
belre = re.compile(r"R(\d+)C(\d+)_(?:SLICE|IOB|MUX2_LUT5|MUX2_LUT6|MUX2_LUT7|MUX2_LUT8)(\w)")
for cellname, cell in data['modules']['top']['cells'].items():
bel = cell['attributes']['NEXTPNR_BEL']
row, col, num = belre.match(bel).groups()
bels = belre.match(bel)
if not bels:
raise Exception(f"Unknown bel:{bel}")
row, col, num = bels.groups()
yield (cell['type'], int(row), int(col), num,
cell['parameters'], cell['attributes'], sanitize_name(cellname))

Expand All @@ -42,7 +45,7 @@ def get_pips(data):
if res:
row, col, src, dest = res.groups()
yield int(row), int(col), src, dest
elif pip:
elif pip and "DUMMY" not in pip:
print("Invalid pip:", pip)

def infovaluemap(infovalue, start=2):
Expand Down Expand Up @@ -81,7 +84,6 @@ def place(db, tilemap, bels, cst):
# XXX skip power
if not cellname.startswith('\$PACKER'):
cst.cells[cellname] = f"R{row}C{col}[{int(num) // 2}][{_sides[int(num) % 2]}]"

elif typ == "IOB":
edge = 'T'
idx = col;
Expand Down
63 changes: 57 additions & 6 deletions apycula/gowin_unpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,54 @@ def portname(n):
return "OEN"
return n

def make_muxes(row, col, idx, db, mod):
name = f"R{row}C{col}_MUX2_LUT50"
if name in mod.primitives.keys():
return

# one MUX8
if col < db.cols :
name = f"R{row}C{col}_MUX2_LUT80"
mux2 = codegen.Primitive("MUX2", name)
mux2.portmap['I0'] = f"R{row}C{col + 1}_OF3"
mux2.portmap['I1'] = f"R{row}C{col}_OF3"
mux2.portmap['O'] = f"R{row}C{col}_OF7"
mux2.portmap['S0'] = f"R{row}C{col}_SEL7"
mod.wires.update(mux2.portmap.values())
mod.primitives[name] = mux2

# one MUX7
name = f"R{row}C{col}_MUX2_LUT70"
mux2 = codegen.Primitive("MUX2", name)
mux2.portmap['I0'] = f"R{row}C{col}_OF5"
mux2.portmap['I1'] = f"R{row}C{col}_OF1"
mux2.portmap['O'] = f"R{row}C{col}_OF3"
mux2.portmap['S0'] = f"R{row}C{col}_SEL3"
mod.wires.update(mux2.portmap.values())
mod.primitives[name] = mux2

# two MUX6
for i in range(2):
name = f"R{row}C{col}_MUX2_LUT6{i}"
mux2 = codegen.Primitive("MUX2", name)
mux2.portmap['I0'] = f"R{row}C{col}_OF{i * 4 + 2}"
mux2.portmap['I1'] = f"R{row}C{col}_OF{i * 4}"
mux2.portmap['O'] = f"R{row}C{col}_OF{i * 4 + 1}"
mux2.portmap['S0'] = f"R{row}C{col}_SEL{i * 4 + 1}"
mod.wires.update(mux2.portmap.values())
mod.primitives[name] = mux2

# four MUX5
for i in range(4):
name = f"R{row}C{col}_MUX2_LUT5{i}"
mux2 = codegen.Primitive("MUX2", name)
mux2.portmap['I0'] = f"R{row}C{col}_F{i * 2}"
mux2.portmap['I1'] = f"R{row}C{col}_F{i * 2 + 1}"
mux2.portmap['O'] = f"R{row}C{col}_OF{i * 2}"
mux2.portmap['S0'] = f"R{row}C{col}_SEL{i * 2}"
mod.wires.update(mux2.portmap.values())
mod.primitives[name] = mux2

_sides = "AB"
def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cfg, cst, db):
# db is 0-based, floorplanner is 1-based
Expand Down Expand Up @@ -159,6 +207,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cfg, cst, db):
mod.wires.update(lut.portmap.values())
mod.primitives[name] = lut
cst.cells[name] = f"R{row}C{col}[{int(idx) // 2}][{_sides[int(idx) % 2]}]"
make_muxes(row, col, idx, db, mod)
elif typ == "DFF":
kind, = flags # DFF only have one flag
idx = int(idx)
Expand Down Expand Up @@ -251,8 +300,8 @@ def main():
parser.add_argument('bitstream')
parser.add_argument('-d', '--device', required=True)
parser.add_argument('-o', '--output', default='unpack.v')
parser.add_argument('-c', '--config', default='unpack.cfg')
parser.add_argument('-s', '--cst', default='unpack.cst')
parser.add_argument('-c', '--config', default=None)
parser.add_argument('-s', '--cst', default=None)

args = parser.parse_args()

Expand Down Expand Up @@ -301,11 +350,13 @@ def main():
with open(args.output, 'w') as f:
mod.write(f)

with open(args.config, 'w') as f:
cfg.write(f)
if args.config:
with open(args.config, 'w') as f:
cfg.write(f)

with open(args.cst, 'w') as f:
cst.write(f)
if args.cst:
with open(args.cst, 'w') as f:
cst.write(f)

if __name__ == "__main__":
main()

0 comments on commit 4140d04

Please sign in to comment.