@@ -477,6 +477,7 @@ def set_banks(fse, db):
477
477
15 : 'PLL' ,
478
478
39 : 'BSRAM_INIT' ,
479
479
49 : 'HCLK' ,
480
+ 52 : 'DLLDLY' ,
480
481
59 : 'CFG' ,
481
482
62 : 'OSC' ,
482
483
63 : 'USB' ,
@@ -1438,6 +1439,64 @@ def fse_create_dhcen(dev, device, fse, dat: Datfile):
1438
1439
hclkin .update ({ 'ce' : wire })
1439
1440
dhcen .append (hclkin )
1440
1441
1442
+ # DLLDLY
1443
+ # from Gowin doc "DLLDLY is the clock delay module that adjusts the input clock according to the DLLSTEP"
1444
+ # In practice the following peculiarities were discovered: the input for the
1445
+ # clock cannot be arbitrary things, but only specialised pins of the chip and
1446
+ # the delay line is cut in between the pin and the clock MUX.
1447
+ # { bel_loc : ([('io_loc', 'io_output_wire', (row, col, flag_wirea))], [(fuse_row, fuse_col)])
1448
+
1449
+ _dlldly = {
1450
+ 'GW1N-1' : {
1451
+ (10 , 19 ) : {
1452
+ 'fuse_bels' : {(10 , 0 ), (10 , 19 )},
1453
+ 'ios' : [('X9Y10' , 'IOBA' , (10 , 0 , 'F1' )), ('X10Y10' , 'IOBA' , (10 , 0 , 'F0' ))],
1454
+ },
1455
+ },
1456
+ 'GW1NZ-1' : {
1457
+ ( 0 , 19 ) : {
1458
+ 'fuse_bels' : {(0 , 5 )},
1459
+ 'ios' : [('X9Y0' , 'IOBA' , (0 , 19 , 'F1' )), ('X10Y0' , 'IOBA' , (0 , 19 , 'F0' ))],
1460
+ },
1461
+ (10 , 19 ) : {
1462
+ 'fuse_bels' : {(5 , 19 )},
1463
+ 'ios' : [('X19Y4' , 'IOBA' , (5 , 19 , 'F0' )), ('X19Y6' , 'IOBA' , (5 , 19 , 'F2' ))],
1464
+ },
1465
+ }
1466
+ }
1467
+
1468
+ def fse_create_dlldly (dev , device ):
1469
+ if device in _dlldly :
1470
+ for bel , fuse_ios in _dlldly [device ].items ():
1471
+ row , col = bel
1472
+ fuse_bels = fuse_ios ['fuse_bels' ]
1473
+ ios = fuse_ios ['ios' ]
1474
+ extra = dev .extra_func .setdefault ((row , col ), {})
1475
+ dlldly = extra .setdefault (f'dlldly' , {})
1476
+ for idx in range (2 ):
1477
+ dlldly [idx ] = {'io_loc' : ios [idx ][0 ], 'io_bel' : ios [idx ][1 ]}
1478
+ # FLAG output
1479
+ nodename = f'X{ col } Y{ row } /DLLDLY_FLAG{ idx } '
1480
+ nodename = add_node (dev , nodename , "" , row , col , f'DLLDLY_FLAG{ idx } ' )
1481
+ add_node (dev , nodename , "" , ios [idx ][2 ][0 ], ios [idx ][2 ][1 ], ios [idx ][2 ][2 ])
1482
+ add_node (dev , f'{ ios [idx ][0 ]} /DLLDLY_IN' , "TILE_CLK" , row , col , f'DLLDLY_CLKIN{ idx } ' )
1483
+ add_node (dev , f'{ ios [idx ][0 ]} /DLLDLY_OUT' , "DLLDLY_O" , row , col , f'DLLDLY_CLKOUT{ idx } ' )
1484
+
1485
+ # STEP wires
1486
+ wires = dlldly [idx ].setdefault ('in_wires' , {})
1487
+ prefix = ["CB" , "DC" ][idx ]
1488
+ for wire_idx in range (8 ):
1489
+ wires [f'DLLSTEP{ wire_idx } ' ] = f"{ prefix [wire_idx // 4 ]} { (wire_idx + 4 ) % 8 } "
1490
+ wires ['DIR' ] = ["A1" , "B4" ][idx ]
1491
+ wires ['LOADN' ] = ["A0" , "B7" ][idx ]
1492
+ wires ['MOVE' ] = ["B6" , "B5" ][idx ]
1493
+ wires ['CLKIN' ] = f'DLLDLY_CLKIN{ idx } '
1494
+
1495
+ wires = dlldly [idx ].setdefault ('out_wires' , {})
1496
+ wires ['FLAG' ] = f'DLLDLY_FLAG{ idx } '
1497
+ wires ['CLKOUT' ] = f'DLLDLY_CLKOUT{ idx } '
1498
+ dlldly_bels = extra .setdefault (f'dlldly_fusebels' , set ())
1499
+ dlldly_bels .update (fuse_bels )
1441
1500
1442
1501
_pll_loc = {
1443
1502
'GW1N-1' :
@@ -1685,6 +1744,19 @@ def fse_create_clocks(dev, device, dat: Datfile, fse):
1685
1744
add_node (dev , f'{ clknames [clk_idx ]} -9C' , "GLOBAL_CLK" , row , dev .cols - 1 , 'LWT6' )
1686
1745
else :
1687
1746
add_node (dev , f'{ clknames [clk_idx ]} -9C' , "GLOBAL_CLK" , row , 0 , 'LWT6' )
1747
+ elif (device == 'GW1NZ-1' and (row == 0 or col == dev .cols - 1 )) or (device == 'GW1N-1' and row == dev .rows - 1 ):
1748
+ # Do not connect the IO output to the clock node because DLLDLY
1749
+ # may be located at these positions, which, if used, will be
1750
+ # the source for the clock. However, if DLLDLY is not used
1751
+ # (mostly), we need to have a way to connect them - for this we
1752
+ # add two PIPs - one to connect the IO output to the clock and
1753
+ # one to connect the IO output to the DLLDLY input.
1754
+ # Both are non-fuseable, but allow the router to work.
1755
+ add_node (dev , clknames [clk_idx ], "GLOBAL_CLK" , row , col , 'PCLK_DUMMY' )
1756
+ dev .grid [row ][col ].pips ['PCLK_DUMMY' ] = {wirenames [wire_idx ]: set (), 'DLLDLY_OUT' : set ()}
1757
+ add_node (dev , f'X{ col } Y{ row } /DLLDLY_OUT' , "DLLDLY_O" , row , col , 'DLLDLY_OUT' )
1758
+ add_node (dev , f'X{ col } Y{ row } /DLLDLY_IN' , "TILE_CLK" , row , col , 'DLLDLY_IN' )
1759
+ dev .grid [row ][col ].pips ['DLLDLY_IN' ] = {wirenames [wire_idx ]: set ()}
1688
1760
else :
1689
1761
add_node (dev , clknames [clk_idx ], "GLOBAL_CLK" , row , col , wirenames [wire_idx ])
1690
1762
add_buf_bel (dev , row , col , wirenames [wire_idx ])
@@ -1955,8 +2027,16 @@ def create_segments(dev, device):
1955
2027
if (b_row , s_col , seg ['bottom_gate_wire' ][1 ]) in dev_desc ['reserved_wires' ]:
1956
2028
seg ['bottom_gate_wire' ][1 ] = None
1957
2029
2030
+ # remove isolated segments (these are in the DSP area of -9, -9C, -18, -18C)
2031
+ if (not seg ['top_gate_wire' ][0 ] and not seg ['top_gate_wire' ][1 ]
2032
+ and not seg ['bottom_gate_wire' ][0 ] and not seg ['bottom_gate_wire' ][1 ]):
2033
+ del dev .segments [(top_gate_row , s_col , seg_idx )]
2034
+
1958
2035
# new segment i + 1
1959
2036
seg_idx += 4
2037
+ # XXX 6 and 7 need static DCS, disable for now
2038
+ if seg_idx in [6 , 7 ]:
2039
+ continue
1960
2040
seg_1 = dev .segments .setdefault ((top_gate_row , s_col , seg_idx ), {})
1961
2041
# controlled area
1962
2042
seg_1 ['min_x' ] = seg ['min_x' ]
@@ -1990,9 +2070,6 @@ def create_segments(dev, device):
1990
2070
seg_1 ['bottom_gate_wire' ][1 ] = None
1991
2071
1992
2072
# remove isolated segments (these are in the DSP area of -9, -9C, -18, -18C)
1993
- if (not seg ['top_gate_wire' ][0 ] and not seg ['top_gate_wire' ][1 ]
1994
- and not seg ['bottom_gate_wire' ][0 ] and not seg ['bottom_gate_wire' ][1 ]):
1995
- del dev .segments [(top_gate_row , s_col , seg_idx - 4 )]
1996
2073
if (not seg_1 ['top_gate_wire' ][0 ] and not seg_1 ['top_gate_wire' ][1 ]
1997
2074
and not seg_1 ['bottom_gate_wire' ][0 ] and not seg_1 ['bottom_gate_wire' ][1 ]):
1998
2075
del dev .segments [(top_gate_row , s_col , seg_idx )]
@@ -2721,6 +2798,7 @@ def from_fse(device, fse, dat: Datfile):
2721
2798
fse_create_emcu (dev , device , dat )
2722
2799
fse_create_logic2clk (dev , device , dat )
2723
2800
fse_create_dhcen (dev , device , fse , dat )
2801
+ fse_create_dlldly (dev , device )
2724
2802
create_segments (dev , device )
2725
2803
disable_plls (dev , device )
2726
2804
sync_extra_func (dev )
@@ -4131,6 +4209,8 @@ def fse_wire_delays(db):
4131
4209
db .wire_delay [clknames [i ]] = "CENT_SPINE_PCLK"
4132
4210
for i in range (1000 , 1010 ): # HCLK
4133
4211
db .wire_delay [clknames [i ]] = "X0" # XXX
4212
+ for wire in {'DLLDLY_OUT' , 'DLLDLY_CLKOUT' , 'DLLDLY_CLKOUT0' , 'DLLDLY_CLKOUT1' }:
4213
+ db .wire_delay [wire ] = "X0" # XXX
4134
4214
4135
4215
# assign pads with plls
4136
4216
# for now use static table and store the bel name although it is always PLL without a number
0 commit comments