Skip to content

Commit

Permalink
Add DHCEN primitive.
Browse files Browse the repository at this point in the history
Added parts necessary to generate chip databases with DHCEN support for
all supported boards. The packing was made with the necessary fuses set.

DHCEN is provided as a wire to disable the input MUXes of HCLK,
effectively turning off everything that is "beyond" those MUXes.

Most of the work happens in the nextpnr part.

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit committed Jul 20, 2024
1 parent fc1121f commit bea46f9
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 1 deletion.
64 changes: 64 additions & 0 deletions apycula/attrids.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,70 @@
'SYNC': 2,
}

# HCLK
hclk_attrids = {
'BK00DIV2_RST': 0,
'BK01DIV2_RST': 1,
'BK0MUX0_OUTSEL': 2,
'BK0MUX1_OUTSEL': 3,
'BK10DIV2_RST': 4,
'BK11DIV2_RST': 5,
'BK1MUX0_OUTSEL': 6,
'BK1MUX1_OUTSEL': 7,
'BRGMUX0_BRGOUT': 8,
'BRGMUX0_INSEL': 9,
'BRGMUX1_BRGOUT': 10,
'BRGMUX1_INSEL': 11,
'BRGMUX0_BRGSTOP': 12,
'BRGMUX1_BRGSTOP': 13,
'HCLKDIV0_DIV': 14,
'HCLKDIV0_RST': 15,
'HCLKDIV1_DIV': 16,
'HCLKDIV1_RST': 17,
'HSB0MUX0_HSTOP': 18,
'HSB0MUX1_HSTOP': 19,
'HSB1MUX0_HSTOP': 20,
'HSB1MUX1_HSTOP': 21,
'HCLKDCS0_SEL': 22,
'HCLKDCS1_SEL': 23,
'DCC0': 24,
'DCC1': 25,
'DLYMUX': 26,
'HCLKDIV_DIV': 27,
'HCLKDIV_RST': 28,
}

hclk_attrvals = {
'UNKNOWN': 0,
'DIVCIBRST2': 1,
'DIVCIBRST3': 2,
'DIV2': 3,
'DIVCIBRST0': 4,
'DIVCIBRST1': 5,
'DIVCIBRST4': 6,
'DIVCIBRST5': 7,
'ENABLE': 8,
'BRGCIBSEL0': 9,
'BRGCIBSEL1': 10,
'BRGCIBSTOP0': 11,
'BRGCIBSTOP1': 12,
'2': 13,
'3.5': 14,
'4': 15,
'5': 16,
'HCLKCIBSTOP0': 17,
'HCLKCIBSTOP1': 18,
'HCLKCIBSTOP2': 19,
'HCLKCIBSTOP3': 20,
'HCLKBK10': 21,
'HCLKBK11': 22,
'8': 23,
'DIVCIBRST': 24,
'NEG_80': 25,
'80': 26,
}


# iologic
iologic_attrids = {
'INMODE': 0,
Expand Down
71 changes: 71 additions & 0 deletions apycula/chipdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ def set_banks(fse, db):
14: 'DSP',
15: 'PLL',
39: 'BSRAM_INIT',
49: 'HCLK',
59: 'CFG',
62: 'OSC',
63: 'USB',
Expand Down Expand Up @@ -487,6 +488,7 @@ def set_banks(fse, db):
45: 'IOBH',
46: 'IOBI',
47: 'IOBJ',
50: 'HCLK',
51: 'OSC',
53: 'DLLDEL0',
54: 'DLLDEL1',
Expand Down Expand Up @@ -1064,6 +1066,74 @@ def fse_create_hclk_nodes(dev, device, fse, dat: Datfile):
if src.startswith('HCLK'):
hclks[src].add((row, col, src))

# DHCEN (as I imagine) is an additional control input of the HCLK input
# multiplexer. We have four input multiplexers - HCLK_IN0, HCLK_IN1, HCLK_IN2,
# HCLK_IN3 (GW1N-9C with its additional four multiplexers stands separately,
# but we will deal with it separately).
# Creating images using IDE where we use the maximum allowable number of DHCEN,
# the CE port of which is connected to the IO ports, then we trace the route
# from IO to the final wire, which will be the CE port of the DHCEN primitive.
# We are not interested in the CLKIN and CLKOUT ports because we are supposed
# to simply disable/enable one of the input multiplexers.
# Let's summarize the experimental data in a table.
# There are 4 multiplexers on each side of the chip (sides: Right Bottom Left Top).
_dhcen_ce = {
'GW1N-1':
{'B' : [( 0, 19, 'D5'), ( 0, 19, 'D3'), ( 0, 19, 'D4'), ( 0, 19, 'D2')]},
'GW1NZ-1':
{'R' : [( 0, 19, 'A2'), ( 0, 19, 'A4'), ( 0, 19, 'A3'), ( 0, 19, 'A5')],
'T' : [(10, 19, 'A2'), (10, 19, 'A4'), (10, 19, 'A3'), (10, 19, 'A5')]},
'GW1NS-2':
{'R' : [(10, 19, 'A4'), (10, 19, 'A6'), (10, 19, 'A5'), (10, 19, 'A7')],
'B' : [(11, 19, 'A4'), (11, 19, 'A6'), (11, 19, 'A5'), (11, 19, 'A7')],
'L' : [( 9, 0, 'A0'), ( 9, 0, 'A2'), ( 9, 0, 'A1'), ( 9, 0, 'A3')],
'T' : [( 0, 19, 'D5'), ( 0, 19, 'D3'), ( 0, 19, 'D4'), ( 0, 19, 'D2')]},
'GW1N-4':
{'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6')],
'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5')],
'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')]},
'GW1NS-4':
{'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6')],
'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5')],
'T' : [( 1, 0, 'B6'), ( 1, 0, 'A0'), ( 1, 0, 'B7'), ( 1, 0, 'A1')]},
'GW1N-9C':
{'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6')],
'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5')],
'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')],
'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6')]},
'GW1N-9C':
{'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6')],
'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5')],
'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')],
'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6')]},
'GW2A-18':
{'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3')],
'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3')],
'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3')],
'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3')]},
'GW2A-18C':
{'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3')],
'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3')],
'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3')],
'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3')]},
}
def fse_create_dhcen(dev, device, fse, dat: Datfile):
if device not in _dhcen_ce:
print(f'No DHCEN for {device} for now.')
return
for side, ces in _dhcen_ce[device].items():
for idx, ce_wire in enumerate(ces):
row, col, wire = ce_wire
extra = dev.extra_func.setdefault((row, col), {})
dhcen = extra.setdefault('dhcen', [])
# use db.hclk_pips in order to find HCLK_IN cells
for hclk_loc in _hclk_to_fclk[device][side]['hclk']:
if f'HCLK_IN{idx}' in dev.hclk_pips[hclk_loc]:
hclkin = {'hclkin' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', f'HCLK_IN{idx}', side]}
hclkin.update({ 'ce' : wire})
dhcen.append(hclkin)


_pll_loc = {
'GW1N-1':
{'TRPLL0CLK0': (0, 17, 'F4'), 'TRPLL0CLK1': (0, 17, 'F5'),
Expand Down Expand Up @@ -1722,6 +1792,7 @@ def from_fse(device, fse, dat: Datfile):
fse_create_gsr(dev, device)
fse_create_bandgap(dev, device)
fse_create_logic2clk(dev, device, dat)
fse_create_dhcen(dev, device, fse, dat)
disable_plls(dev, device)
sync_extra_func(dev)
set_chip_flags(dev, device);
Expand Down
45 changes: 44 additions & 1 deletion apycula/gowin_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def get_bits(init_data):
def get_bels(data):
later = []
if is_himbaechel:
belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP)(\w*)")
belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP|DHCEN)(\w*)")
else:
belre = re.compile(r"R(\d+)C(\d+)_(?:GSR|SLICE|IOB|MUX2_LUT5|MUX2_LUT6|MUX2_LUT7|MUX2_LUT8|ODDR|OSC[ZFHWO]?|BUFS|RAMW|rPLL|PLLVR|IOLOGIC)(\w*)")

Expand Down Expand Up @@ -1968,6 +1968,41 @@ def set_osc_attrs(db, typ, params):
add_attr_val(db, 'OSC', fin_attrs, attrids.osc_attrids[attr], val)
return fin_attrs

_wire2attr_val = {
'HCLK_IN0': ('HSB0MUX0_HSTOP', 'HCLKCIBSTOP0'),
'HCLK_IN1': ('HSB1MUX0_HSTOP', 'HCLKCIBSTOP2'),
'HCLK_IN2': ('HSB0MUX1_HSTOP', 'HCLKCIBSTOP1'),
'HCLK_IN3': ('HSB1MUX1_HSTOP', 'HCLKCIBSTOP3'),
}
def find_and_set_dhcen_hclk_fuses(db, tilemap, wire, side):
fin_attrs = set()
attr, attr_val = _wire2attr_val[wire]
val = attrids.hclk_attrvals[attr_val]
add_attr_val(db, 'HCLK', fin_attrs, attrids.hclk_attrids[attr], val)

def set_fuse():
ttyp = db.grid[row][col].ttyp
if 'HCLK' in db.shortval[ttyp]:
bits = get_shortval_fuses(db, ttyp, fin_attrs, "HCLK")
tile = tilemap[row, col]
for r, c in bits:
tile[r][c] = 1

if side in "TB":
if side == 'T':
row = 0
else:
row = db.rows - 1
for col in range(db.cols):
set_fuse()
else:
if side == 'R':
col = 0
else:
col = db.col - 1
for row in range(db.rows):
set_fuse()

_iologic_default_attrs = {
'DUMMY': {},
'IOLOGIC': {},
Expand Down Expand Up @@ -2431,6 +2466,14 @@ def place(db, tilemap, bels, cst, args):
cfg_tile = tilemap[(0, 37)]
for r, c in bits:
cfg_tile[r][c] = 1
elif typ == "DHCEN":
if 'DHCEN_SIDE' not in attrs:
continue
# DHCEN as such is just a control wire and does not have a fuse
# itself, but HCLK has fuses that allow this control. Here we look
# for the corresponding HCLK and set its fuses.
_, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['hclk']
hclk_attrs = find_and_set_dhcen_hclk_fuses(db, wire, side)
else:
print("unknown type", typ)

Expand Down

0 comments on commit bea46f9

Please sign in to comment.