1
1
from dataclasses import dataclass , field
2
2
from typing import Dict , List , Set , Tuple , Union , ByteString
3
+ from itertools import chain
3
4
import re
4
5
from functools import reduce
5
6
from collections import namedtuple
@@ -64,6 +65,10 @@ class Tile:
64
65
for this specific tile type"""
65
66
width : int
66
67
height : int
68
+ # At the time of packing/unpacking the information about the types of cells
69
+ # is already lost, it is critical to work through the 'logicinfo' table so
70
+ # store it.
71
+ ttyp : int
67
72
# a mapping from dest, source wire to bit coordinates
68
73
pips : Dict [str , Dict [str , Set [Coord ]]] = field (default_factory = dict )
69
74
clock_pips : Dict [str , Dict [str , Set [Coord ]]] = field (default_factory = dict )
@@ -83,6 +88,15 @@ class Device:
83
88
cmd_hdr : List [ByteString ] = field (default_factory = list )
84
89
cmd_ftr : List [ByteString ] = field (default_factory = list )
85
90
template : np .ndarray = None
91
+ # allowable values of bel attributes
92
+ # {table_name: [(attr_id, attr_value)]}
93
+ logicinfo : Dict [str , List [Tuple [int , int ]]] = field (default_factory = dict )
94
+ # fuses for a pair of the "features" (or pairs of parameter values)
95
+ # {ttype: {table_name: {(feature_A, feature_B): {bits}}}
96
+ shortval : Dict [int , Dict [str , Dict [Tuple [int , int ], Set [Coord ]]]] = field (default_factory = dict )
97
+ # fuses for 16 of the "features"
98
+ # {ttype: {table_name: {(feature_0, feature_1, ..., feature_15): {bits}}}
99
+ longval : Dict [int , Dict [str , Dict [Tuple [int , int , int , int , int , int , int , int , int , int , int , int , int , int , int , int ], Set [Coord ]]]] = field (default_factory = dict )
86
100
# always-connected dest, src aliases
87
101
aliases : Dict [Tuple [int , int , str ], Tuple [int , int , str ]] = field (default_factory = dict )
88
102
@@ -145,6 +159,17 @@ def fse_pips(fse, ttyp, table=2, wn=wirenames):
145
159
146
160
return pips
147
161
162
+ # make PLL bels
163
+ def fse_pll (device , fse , ttyp ):
164
+ bels = {}
165
+ # XXX use second grid in order to find PLL ttypes
166
+ if device in ['GW1N-1' , 'GW1NZ-1' ]:
167
+ if ttyp == 89 :
168
+ bel = bels .setdefault ('RPLLB' , Bel ())
169
+ else :
170
+ bel = bels .setdefault ('RPLLA' , Bel ())
171
+ return bels
172
+
148
173
# add the ALU mode
149
174
# new_mode_bits: string like "0110000010011010"
150
175
def add_alu_mode (base_mode , modes , lut , new_alu_mode , new_mode_bits ):
@@ -319,25 +344,145 @@ def set_banks(fse, db):
319
344
for rd in fse [ttyp ]['longval' ][37 ]:
320
345
db .grid [row ][col ].bels .setdefault (f"BANK{ rd [0 ]} " , Bel ())
321
346
347
+ _known_logic_tables = {
348
+ 8 : 'DCS' ,
349
+ 9 : 'GSR' ,
350
+ 10 : 'IOLOGIC' ,
351
+ 11 : 'IOB' ,
352
+ 12 : 'SLICE' ,
353
+ 13 : 'BSRAM' ,
354
+ 14 : 'DSP' ,
355
+ 15 : 'PLL' ,
356
+ 62 : 'USB' ,
357
+ }
358
+
359
+ _known_tables = {
360
+ 4 : 'CONST' ,
361
+ 5 : 'LUT' ,
362
+ 21 : 'IOLOGICA' ,
363
+ 22 : 'IOLOGICB' ,
364
+ 23 : 'IOBA' ,
365
+ 24 : 'IOBB' ,
366
+ 25 : 'CLS0' ,
367
+ 26 : 'CLS1' ,
368
+ 27 : 'CLS2' ,
369
+ 28 : 'CLS3' ,
370
+ 35 : 'PLL' ,
371
+ 37 : 'BANK' ,
372
+ 40 : 'IOBC' ,
373
+ 41 : 'IOBD' ,
374
+ 42 : 'IOBE' ,
375
+ 43 : 'IOBF' ,
376
+ 44 : 'IOBG' ,
377
+ 45 : 'IOBH' ,
378
+ 46 : 'IOBI' ,
379
+ 47 : 'IOBJ' ,
380
+ 53 : 'DLLDEL0' ,
381
+ 54 : 'DLLDEL1' ,
382
+ 56 : 'DLL0' ,
383
+ 64 : 'USB' ,
384
+ 66 : 'EFLASH' ,
385
+ 68 : 'ADC' ,
386
+ 80 : 'DLL1' ,
387
+ }
388
+
389
+ def fse_fill_logic_tables (dev , fse ):
390
+ # logicinfo
391
+ for ltable in fse ['header' ]['logicinfo' ].keys ():
392
+ if ltable in _known_logic_tables .keys ():
393
+ table = dev .logicinfo .setdefault (_known_logic_tables [ltable ], [])
394
+ else :
395
+ table = dev .logicinfo .setdefault (f"unknown_{ ltable } " , [])
396
+ for attr , val , _ in fse ['header' ]['logicinfo' ][ltable ]:
397
+ table .append ((attr , val ))
398
+ # shortval
399
+ ttypes = {t for row in fse ['header' ]['grid' ][61 ] for t in row }
400
+ for ttyp in ttypes :
401
+ if 'shortval' in fse [ttyp ].keys ():
402
+ ttyp_rec = dev .shortval .setdefault (ttyp , {})
403
+ for stable in fse [ttyp ]['shortval' ].keys ():
404
+ if stable in _known_tables :
405
+ table = ttyp_rec .setdefault (_known_tables [stable ], {})
406
+ else :
407
+ table = ttyp_rec .setdefault (f"unknown_{ stable } " , {})
408
+ for f_a , f_b , * fuses in fse [ttyp ]['shortval' ][stable ]:
409
+ table [(f_a , f_b )] = {fuse .fuse_lookup (fse , ttyp , f ) for f in unpad (fuses )}
410
+ if 'longval' in fse [ttyp ].keys ():
411
+ ttyp_rec = dev .longval .setdefault (ttyp , {})
412
+ for ltable in fse [ttyp ]['longval' ].keys ():
413
+ if ltable in _known_tables :
414
+ table = ttyp_rec .setdefault (_known_tables [ltable ], {})
415
+ else :
416
+ table = ttyp_rec .setdefault (f"unknown_{ ltable } " , {})
417
+ for f0 , f1 , f2 , f3 , f4 , f5 , f6 , f7 , f8 , f9 , f10 , f11 , f12 , f13 , f14 , f15 , * fuses in fse [ttyp ]['longval' ][ltable ]:
418
+ table [(f0 , f1 , f2 , f3 , f4 , f5 , f6 , f7 , f8 , f9 , f10 , f11 , f12 , f13 , f14 , f15 )] = {fuse .fuse_lookup (fse , ttyp , f ) for f in unpad (fuses )}
419
+
322
420
def from_fse (device , fse ):
323
421
dev = Device ()
324
422
ttypes = {t for row in fse ['header' ]['grid' ][61 ] for t in row }
325
423
tiles = {}
326
424
for ttyp in ttypes :
327
425
w = fse [ttyp ]['width' ]
328
426
h = fse [ttyp ]['height' ]
329
- tile = Tile (w , h )
427
+ tile = Tile (w , h , ttyp )
330
428
tile .pips = fse_pips (fse , ttyp , 2 , wirenames )
331
429
tile .clock_pips = fse_pips (fse , ttyp , 38 , clknames )
332
430
if 5 in fse [ttyp ]['shortval' ]:
333
431
tile .bels = fse_luts (fse , ttyp )
334
432
if 51 in fse [ttyp ]['shortval' ]:
335
433
tile .bels = fse_osc (device , fse , ttyp )
434
+ if ttyp in [88 , 89 ]:
435
+ tile .bels = fse_pll (device , fse , ttyp )
336
436
tiles [ttyp ] = tile
337
437
438
+ fse_fill_logic_tables (dev , fse )
338
439
dev .grid = [[tiles [ttyp ] for ttyp in row ] for row in fse ['header' ]['grid' ][61 ]]
339
440
return dev
340
441
442
+ # get fuses for attr/val set using short/longval table
443
+ # returns a bit set
444
+ def get_table_fuses (attrs , table ):
445
+ bits = set ()
446
+ for key , fuses in table .items ():
447
+ # all 16 "features" must be present to be able to use a set of bits from the record
448
+ have_full_key = True
449
+ for attrval in key :
450
+ if attrval == 0 : # no "feature"
451
+ continue
452
+ if attrval > 0 :
453
+ # this "feature" must present
454
+ if attrval not in attrs :
455
+ have_full_key = False
456
+ break
457
+ continue
458
+ if attrval < 0 :
459
+ # this "feature" is set by default and can only be unset
460
+ if abs (attrval ) in attrs :
461
+ have_full_key = False
462
+ break
463
+ if not have_full_key :
464
+ continue
465
+ bits .update (fuses )
466
+ return bits
467
+
468
+ # get fuses for attr/val set using shortval table for ttyp
469
+ # returns a bit set
470
+ def get_shortval_fuses (dev , ttyp , attrs , table_name ):
471
+ return get_table_fuses (attrs , dev .shortval [ttyp ][table_name ])
472
+
473
+ # get fuses for attr/val set using longval table for ttyp
474
+ # returns a bit set
475
+ def get_longval_fuses (dev , ttyp , attrs , table_name ):
476
+ return get_table_fuses (attrs , dev .longval [ttyp ][table_name ])
477
+
478
+ # add the attribute/value pair into an set, which is then passed to
479
+ # get_longval_fuses() and get_shortval_fuses()
480
+ def add_attr_val (dev , logic_table , attrs , attr , val ):
481
+ for idx , attr_val in enumerate (dev .logicinfo [logic_table ]):
482
+ if attr_val [0 ] == attr and attr_val [1 ] == val :
483
+ attrs .add (idx )
484
+ break
485
+
341
486
def get_pins (device ):
342
487
if device not in {"GW1N-1" , "GW1NZ-1" , "GW1N-4" , "GW1N-9" , "GW1NR-9" , "GW1N-9C" , "GW1NR-9C" , "GW1NS-2" , "GW1NS-2C" , "GW1NS-4" , "GW1NSR-4C" }:
343
488
raise Exception (f"unsupported device { device } " )
@@ -425,6 +570,16 @@ def json_pinout(device):
425
570
raise Exception ("unsupported device" )
426
571
427
572
573
+
574
+ _pll_inputs = [(5 , 'CLKFB' ), (6 , 'FBDSEL0' ), (7 , 'FBDSEL1' ), (8 , 'FBDSEL2' ), (9 , 'FBDSEL3' ),
575
+ (10 , 'FBDSEL4' ), (11 , 'FBDSEL5' ),
576
+ (12 , 'IDSEL0' ), (13 , 'IDSEL1' ), (14 , 'IDSEL2' ), (15 , 'IDSEL3' ), (16 , 'IDSEL4' ),
577
+ (17 , 'IDSEL5' ),
578
+ (18 , 'ODSEL0' ), (19 , 'ODSEL1' ), (20 , 'ODSEL2' ), (21 , 'ODSEL3' ), (22 , 'ODSEL4' ),
579
+ (24 , 'PSDA0' ), (25 , 'PSDA1' ), (26 , 'PSDA2' ), (27 , 'PSDA3' ),
580
+ (28 , 'DUTYDA0' ), (29 , 'DUTYDA1' ), (30 , 'DUTYDA2' ), (31 , 'DUTYDA3' ),
581
+ (32 , 'FDLY0' ), (33 , 'FDLY1' ), (34 , 'FDLY2' ), (35 , 'FDLY3' )]
582
+ _pll_outputs = [(0 , 'CLKOUT' ), (1 , 'LOCK' ), (2 , 'CLKOUTP' ), (3 , 'CLKOUTD' ), (4 , 'CLKOUTD3' )]
428
583
def dat_portmap (dat , dev ):
429
584
for row in dev .grid :
430
585
for tile in row :
@@ -447,6 +602,28 @@ def dat_portmap(dat, dev):
447
602
bel .portmap ['I' ] = out
448
603
oe = wirenames [dat [f'Iobuf{ pin } OE' ]]
449
604
bel .portmap ['OE' ] = oe
605
+ elif name .startswith ("ODDR" ):
606
+ d0 = wirenames [dat [f'Iologic{ pin } In' ][1 ]]
607
+ bel .portmap ['D0' ] = d0
608
+ d1 = wirenames [dat [f'Iologic{ pin } In' ][2 ]]
609
+ bel .portmap ['D1' ] = d1
610
+ tx = wirenames [dat [f'Iologic{ pin } In' ][27 ]]
611
+ bel .portmap ['TX' ] = tx
612
+ elif name == 'RPLLA' :
613
+ for idx , nam in _pll_inputs :
614
+ wire = wirenames [dat ['PllIn' ][idx ]]
615
+ bel .portmap [nam ] = wire
616
+ for idx , nam in _pll_outputs :
617
+ wire = wirenames [dat ['PllOut' ][idx ]]
618
+ bel .portmap [nam ] = wire
619
+ bel .portmap ['CLKIN' ] = wirenames [124 ];
620
+ elif name == 'RPLLB' :
621
+ reset = wirenames [dat ['PllIn' ][0 ]]
622
+ bel .portmap ['RESET' ] = reset
623
+ reset_p = wirenames [dat ['PllIn' ][1 ]]
624
+ bel .portmap ['RESET_P' ] = reset_p
625
+ odsel5 = wirenames [dat ['PllIn' ][23 ]]
626
+ bel .portmap ['ODSEL5' ] = odsel5
450
627
451
628
def dat_aliases (dat , dev ):
452
629
for row in dev .grid :
@@ -655,3 +832,4 @@ def loc2bank(db, row, col):
655
832
bank = db .pin_bank [name + 'B' ]
656
833
return bank
657
834
835
+
0 commit comments