Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DHCEN primitive. #261

Merged
merged 9 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add DHCEN primitive.
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 <rabbit@yrabbit.cyou>
  • Loading branch information
yrabbit committed Jul 20, 2024
commit bea46f9bdbec1ddeb864d5f8a91e062fcc99af01
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
Loading