Skip to content

Commit a2da0e9

Browse files
committed
Merge branch 'master' of github.com:pepijndevos/apicula
2 parents 7badd43 + 13eedd3 commit a2da0e9

File tree

5 files changed

+365
-116
lines changed

5 files changed

+365
-116
lines changed

apycula/chipdb.py

+18
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class Bel:
4040
flags: Dict[Union[int, str], Set[Coord]] = field(default_factory=dict)
4141
# { iostd: { mode : IOBMode}}
4242
iob_flags: Dict[str, Dict[str, IOBMode]] = field(default_factory=dict)
43+
lvcmos121518_bits: Set[Coord] = field(default_factory = set)
44+
# this Bel is IOBUF and needs routing to become IBUF or OBUF
45+
simplified_iob: bool = field(default = False)
4346
# banks
4447
bank_mask: Set[Coord] = field(default_factory=set)
4548
bank_flags: Dict[str, Set[Coord]] = field(default_factory=dict)
@@ -404,6 +407,14 @@ def dff_clean(dev):
404407
for mode, bits in bel.modes.items():
405408
bits -= extra_bits
406409

410+
def get_route_bits(db, row, col):
411+
""" All routing bits for the cell """
412+
bits = set()
413+
for w in db.grid[row][col].pips.values():
414+
for v in w.values():
415+
bits.update(v)
416+
return bits
417+
407418
def diff2flag(dev):
408419
""" Minimize bits for flag values and calc flag bitmask"""
409420
seen_bels = []
@@ -414,11 +425,18 @@ def diff2flag(dev):
414425
if not bel.iob_flags or bel in seen_bels:
415426
continue
416427
seen_bels.append(bel)
428+
# get routing bits for cell
429+
rbits = get_route_bits(dev, idx, jdx)
417430
# If for a given mode all possible values of one flag
418431
# contain some bit, then this bit is "noise" --- this bit
419432
# belongs to the default value of another flag. Remove.
420433
for iostd, iostd_rec in bel.iob_flags.items():
421434
for mode, mode_rec in iostd_rec.items():
435+
# if encoding has routing
436+
r_encoding = mode_rec.encode_bits & rbits
437+
mode_rec.encode_bits -= rbits
438+
if r_encoding and mode != 'IOBUF':
439+
bel.simplified_iob = True
422440
mode_rec.decode_bits = mode_rec.encode_bits.copy()
423441
for flag, flag_rec in mode_rec.flags.items():
424442
noise_bits = None

apycula/gowin_bba.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ def write_pips(b, pips):
6868
def write_bels(b, bels):
6969
with b.block("bels") as blk:
7070
for typ, bel in bels.items():
71-
b.u16(id_string(typ))
71+
if bel.simplified_iob:
72+
b.u16(id_string(f'{typ}S'))
73+
else:
74+
b.u16(id_string(typ))
7275
with b.block("portmap") as port_blk:
7376
for dest, src in bel.portmap.items():
7477
b.u16(id_string(dest))

apycula/gowin_pack.py

+31-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import re
44
import pickle
5+
import itertools
56
import numpy as np
67
import json
78
import argparse
@@ -60,6 +61,13 @@ def infovaluemap(infovalue, start=2):
6061
"SSTL33_II" : "SSTL33_I",
6162
"LVTTL33" : "LVCMOS33",
6263
}
64+
# For each bank, remember the Bels used, mark whether Outs were among them and the standard.
65+
class BankDesc:
66+
def __init__(self, iostd, inputs_only, bels_tiles):
67+
self.iostd = iostd
68+
self.inputs_only = inputs_only
69+
self.bels_tiles = bels_tiles
70+
6371
_banks = {}
6472
_sides = "AB"
6573
def place(db, tilemap, bels, cst, args):
@@ -98,7 +106,7 @@ def place(db, tilemap, bels, cst, args):
98106
# XXX skip power
99107
if not cellname.startswith('\$PACKER'):
100108
cst.cells[cellname] = (row, col, int(num) // 2, _sides[int(num) % 2])
101-
elif typ == "IOB":
109+
elif typ[:3] == "IOB":
102110
edge = 'T'
103111
idx = col;
104112
if row == db.rows:
@@ -124,7 +132,7 @@ def place(db, tilemap, bels, cst, args):
124132
pinless_io = False
125133
try:
126134
bank = chipdb.loc2bank(db, row - 1, col - 1)
127-
iostd = _banks.setdefault(bank, None)
135+
iostd = _banks.setdefault(bank, BankDesc(None, True, [])).iostd
128136
except KeyError:
129137
if not args.allow_pinless_io:
130138
raise Exception(f"IO{edge}{idx}{num} is not allowed for a given package")
@@ -148,11 +156,19 @@ def place(db, tilemap, bels, cst, args):
148156
if not iostd:
149157
iostd = "LVCMOS18"
150158
if not pinless_io:
151-
_banks[bank] = iostd
159+
_banks[bank].iostd = iostd
160+
if mode == 'IBUF':
161+
_banks[bank].bels_tiles.append((iob, tile))
162+
else:
163+
_banks[bank].inputs_only = False
152164

153165
cst.attrs.setdefault(cellname, {}).update({"IO_TYPE": iostd})
154166
# collect flag bits
155167
bits = iob.iob_flags[iostd][mode].encode_bits.copy()
168+
# XXX OPEN_DRAIN must be after DRIVE
169+
attrs_keys = attrs.keys()
170+
if 'OPEN_DRAIN=ON' in attrs_keys:
171+
attrs_keys = itertools.chain(attrs_keys, ['OPEN_DRAIN=ON'])
156172
for flag in attrs.keys():
157173
flag_name_val = flag.split("=")
158174
if len(flag_name_val) < 2:
@@ -161,6 +177,10 @@ def place(db, tilemap, bels, cst, args):
161177
continue
162178
if flag_name_val[0] == chipdb.mode_attr_sep + "IO_TYPE":
163179
continue
180+
# skip OPEN_DRAIN=OFF can't clear by mask and OFF is the default
181+
if flag_name_val[0] == chipdb.mode_attr_sep + "OPEN_DRAIN" \
182+
and flag_name_val[1] == 'OFF':
183+
continue
164184
# set flag
165185
mode_desc = iob.iob_flags[iostd][mode]
166186
try:
@@ -191,7 +211,14 @@ def place(db, tilemap, bels, cst, args):
191211
bits |= bank_bel.bank_flags[iostd]
192212
for row, col in bits:
193213
tile[row][col] = 1
194-
214+
# If the entire bank has only inputs, the LVCMOS12/15/18 bit is set
215+
# in each IBUF regardless of the actual I/O standard.
216+
for _, bank_desc in _banks.items():
217+
if bank_desc.inputs_only:
218+
if bank_desc.iostd in {'LVCMOS33', 'LVCMOS25'}:
219+
for bel, tile in bank_desc.bels_tiles:
220+
for row, col in bel.lvcmos121518_bits:
221+
tile[row][col] = 1
195222

196223
def route(db, tilemap, pips):
197224
for row, col, src, dest in pips:

apycula/gowin_unpack.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ def zero_bits(mode, all_modes):
3030
m_mask.update(flag.mask)
3131
return res.difference(all_modes[mode].decode_bits).difference(m_mask)
3232

33+
# If the length of the bit pattern is equal, start the comparison with IOBUF
34+
def _io_mode_sort_func(mode):
35+
l = len(mode[1].decode_bits) * 10
36+
if mode[0] == 'IOBUF':
37+
l += 2
38+
elif mode[1] == 'OBUF':
39+
l += 1
40+
return l
3341
# noiostd --- this is the case when the function is called
3442
# with iostd by default, e.g. from the clock fuzzer
3543
# With normal gowun_unpack io standard is determined first and it is known.
@@ -39,6 +47,7 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True)
3947
bels = {}
4048
for name, bel in tiledata.bels.items():
4149
if name[0:3] == "IOB":
50+
#print(name)
4251
if noiostd:
4352
iostd = ''
4453
else:
@@ -49,7 +58,7 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True)
4958
# Here we don't use a mask common to all modes (it didn't work),
5059
# instead we try the longest bit sequence first.
5160
for mode, mode_rec in sorted(bel.iob_flags[iostd].items(),
52-
key = lambda m: len(m[1].decode_bits), reverse = True):
61+
key = _io_mode_sort_func, reverse = True):
5362
# print(mode, mode_rec.decode_bits)
5463
mode_bits = {(row, col)
5564
for row, col in mode_rec.decode_bits
@@ -249,7 +258,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cfg, cst, db):
249258
cst.cells[name] = (row, col, int(idx) // 2, _sides[int(idx) % 2])
250259
make_muxes(row, col, idx, db, mod)
251260
elif typ == "ALU":
252-
print(flags)
261+
#print(flags)
253262
kind, = flags # ALU only have one flag
254263
idx = int(idx)
255264
name = f"R{row}C{col}_ALU_{idx}"
@@ -277,7 +286,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cfg, cst, db):
277286
mod.primitives[name] = alu
278287

279288
elif typ == "DFF":
280-
print(flags)
289+
#print(flags)
281290
kind, = flags # DFF only have one flag
282291
idx = int(idx)
283292
port = dffmap[kind]

0 commit comments

Comments
 (0)