Skip to content

Commit

Permalink
Merge branch 'master' of github.com:pepijndevos/apicula
Browse files Browse the repository at this point in the history
  • Loading branch information
pepijndevos committed Dec 24, 2021
2 parents 7badd43 + 13eedd3 commit a2da0e9
Show file tree
Hide file tree
Showing 5 changed files with 365 additions and 116 deletions.
18 changes: 18 additions & 0 deletions apycula/chipdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class Bel:
flags: Dict[Union[int, str], Set[Coord]] = field(default_factory=dict)
# { iostd: { mode : IOBMode}}
iob_flags: Dict[str, Dict[str, IOBMode]] = field(default_factory=dict)
lvcmos121518_bits: Set[Coord] = field(default_factory = set)
# this Bel is IOBUF and needs routing to become IBUF or OBUF
simplified_iob: bool = field(default = False)
# banks
bank_mask: Set[Coord] = field(default_factory=set)
bank_flags: Dict[str, Set[Coord]] = field(default_factory=dict)
Expand Down Expand Up @@ -404,6 +407,14 @@ def dff_clean(dev):
for mode, bits in bel.modes.items():
bits -= extra_bits

def get_route_bits(db, row, col):
""" All routing bits for the cell """
bits = set()
for w in db.grid[row][col].pips.values():
for v in w.values():
bits.update(v)
return bits

def diff2flag(dev):
""" Minimize bits for flag values and calc flag bitmask"""
seen_bels = []
Expand All @@ -414,11 +425,18 @@ def diff2flag(dev):
if not bel.iob_flags or bel in seen_bels:
continue
seen_bels.append(bel)
# get routing bits for cell
rbits = get_route_bits(dev, idx, jdx)
# If for a given mode all possible values of one flag
# contain some bit, then this bit is "noise" --- this bit
# belongs to the default value of another flag. Remove.
for iostd, iostd_rec in bel.iob_flags.items():
for mode, mode_rec in iostd_rec.items():
# if encoding has routing
r_encoding = mode_rec.encode_bits & rbits
mode_rec.encode_bits -= rbits
if r_encoding and mode != 'IOBUF':
bel.simplified_iob = True
mode_rec.decode_bits = mode_rec.encode_bits.copy()
for flag, flag_rec in mode_rec.flags.items():
noise_bits = None
Expand Down
5 changes: 4 additions & 1 deletion apycula/gowin_bba.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ def write_pips(b, pips):
def write_bels(b, bels):
with b.block("bels") as blk:
for typ, bel in bels.items():
b.u16(id_string(typ))
if bel.simplified_iob:
b.u16(id_string(f'{typ}S'))
else:
b.u16(id_string(typ))
with b.block("portmap") as port_blk:
for dest, src in bel.portmap.items():
b.u16(id_string(dest))
Expand Down
35 changes: 31 additions & 4 deletions apycula/gowin_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import re
import pickle
import itertools
import numpy as np
import json
import argparse
Expand Down Expand Up @@ -60,6 +61,13 @@ def infovaluemap(infovalue, start=2):
"SSTL33_II" : "SSTL33_I",
"LVTTL33" : "LVCMOS33",
}
# For each bank, remember the Bels used, mark whether Outs were among them and the standard.
class BankDesc:
def __init__(self, iostd, inputs_only, bels_tiles):
self.iostd = iostd
self.inputs_only = inputs_only
self.bels_tiles = bels_tiles

_banks = {}
_sides = "AB"
def place(db, tilemap, bels, cst, args):
Expand Down Expand Up @@ -98,7 +106,7 @@ def place(db, tilemap, bels, cst, args):
# XXX skip power
if not cellname.startswith('\$PACKER'):
cst.cells[cellname] = (row, col, int(num) // 2, _sides[int(num) % 2])
elif typ == "IOB":
elif typ[:3] == "IOB":
edge = 'T'
idx = col;
if row == db.rows:
Expand All @@ -124,7 +132,7 @@ def place(db, tilemap, bels, cst, args):
pinless_io = False
try:
bank = chipdb.loc2bank(db, row - 1, col - 1)
iostd = _banks.setdefault(bank, None)
iostd = _banks.setdefault(bank, BankDesc(None, True, [])).iostd
except KeyError:
if not args.allow_pinless_io:
raise Exception(f"IO{edge}{idx}{num} is not allowed for a given package")
Expand All @@ -148,11 +156,19 @@ def place(db, tilemap, bels, cst, args):
if not iostd:
iostd = "LVCMOS18"
if not pinless_io:
_banks[bank] = iostd
_banks[bank].iostd = iostd
if mode == 'IBUF':
_banks[bank].bels_tiles.append((iob, tile))
else:
_banks[bank].inputs_only = False

cst.attrs.setdefault(cellname, {}).update({"IO_TYPE": iostd})
# collect flag bits
bits = iob.iob_flags[iostd][mode].encode_bits.copy()
# XXX OPEN_DRAIN must be after DRIVE
attrs_keys = attrs.keys()
if 'OPEN_DRAIN=ON' in attrs_keys:
attrs_keys = itertools.chain(attrs_keys, ['OPEN_DRAIN=ON'])
for flag in attrs.keys():
flag_name_val = flag.split("=")
if len(flag_name_val) < 2:
Expand All @@ -161,6 +177,10 @@ def place(db, tilemap, bels, cst, args):
continue
if flag_name_val[0] == chipdb.mode_attr_sep + "IO_TYPE":
continue
# skip OPEN_DRAIN=OFF can't clear by mask and OFF is the default
if flag_name_val[0] == chipdb.mode_attr_sep + "OPEN_DRAIN" \
and flag_name_val[1] == 'OFF':
continue
# set flag
mode_desc = iob.iob_flags[iostd][mode]
try:
Expand Down Expand Up @@ -191,7 +211,14 @@ def place(db, tilemap, bels, cst, args):
bits |= bank_bel.bank_flags[iostd]
for row, col in bits:
tile[row][col] = 1

# If the entire bank has only inputs, the LVCMOS12/15/18 bit is set
# in each IBUF regardless of the actual I/O standard.
for _, bank_desc in _banks.items():
if bank_desc.inputs_only:
if bank_desc.iostd in {'LVCMOS33', 'LVCMOS25'}:
for bel, tile in bank_desc.bels_tiles:
for row, col in bel.lvcmos121518_bits:
tile[row][col] = 1

def route(db, tilemap, pips):
for row, col, src, dest in pips:
Expand Down
15 changes: 12 additions & 3 deletions apycula/gowin_unpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ def zero_bits(mode, all_modes):
m_mask.update(flag.mask)
return res.difference(all_modes[mode].decode_bits).difference(m_mask)

# If the length of the bit pattern is equal, start the comparison with IOBUF
def _io_mode_sort_func(mode):
l = len(mode[1].decode_bits) * 10
if mode[0] == 'IOBUF':
l += 2
elif mode[1] == 'OBUF':
l += 1
return l
# noiostd --- this is the case when the function is called
# with iostd by default, e.g. from the clock fuzzer
# With normal gowun_unpack io standard is determined first and it is known.
Expand All @@ -39,6 +47,7 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True)
bels = {}
for name, bel in tiledata.bels.items():
if name[0:3] == "IOB":
#print(name)
if noiostd:
iostd = ''
else:
Expand All @@ -49,7 +58,7 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True)
# Here we don't use a mask common to all modes (it didn't work),
# instead we try the longest bit sequence first.
for mode, mode_rec in sorted(bel.iob_flags[iostd].items(),
key = lambda m: len(m[1].decode_bits), reverse = True):
key = _io_mode_sort_func, reverse = True):
# print(mode, mode_rec.decode_bits)
mode_bits = {(row, col)
for row, col in mode_rec.decode_bits
Expand Down Expand Up @@ -249,7 +258,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cfg, cst, db):
cst.cells[name] = (row, col, int(idx) // 2, _sides[int(idx) % 2])
make_muxes(row, col, idx, db, mod)
elif typ == "ALU":
print(flags)
#print(flags)
kind, = flags # ALU only have one flag
idx = int(idx)
name = f"R{row}C{col}_ALU_{idx}"
Expand Down Expand Up @@ -277,7 +286,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cfg, cst, db):
mod.primitives[name] = alu

elif typ == "DFF":
print(flags)
#print(flags)
kind, = flags # DFF only have one flag
idx = int(idx)
port = dffmap[kind]
Expand Down
Loading

0 comments on commit a2da0e9

Please sign in to comment.