| Version 9 (modified by , 18 years ago) (diff) |
|---|
TP10 VLSI : Vue physique de l'AMD2901
Objectifs
- Utiliser les outils de placement et routage.
- Vérifier la validité du routage.
Exercice(s)
Exercice 1-Placement
La première étape consiste à placer les plots puis le coeur.
Question 1
Exécutez le script suivant amd_chip.py en ayant pris soin de comprendre le contenu de ce fichier
#!/usr/bin/python
from stratus import *
class amd_chip ( Model ) :
def Interface ( self ) :
self.cke = CkIn ( "cke")
self.cin = SignalIn ( "cin", 1 )
self.cout = SignalOut ( "cout", 1 )
self.np = SignalOut ( "np", 1 )
self.ng = SignalOut ( "ng", 1 )
self.ovr = SignalOut ( "ovr", 1 )
self.zero = SignalOut ( "zero", 1 )
self.signe = SignalOut ( "signe", 1 )
self.r0 = TriState ( "r0", 1 )
self.r3 = TriState ( "r3", 1 )
self.q0 = TriState ( "q0", 1 )
self.q3 = TriState ( "q3", 1 )
self.a = SignalIn ( "a", 4 )
self.b = SignalIn ( "b", 4 )
self.d = SignalIn ( "d", 4 )
self.i = SignalIn ( "i", 9 )
self.noe = SignalIn ( "noe", 1 )
self.y = TriState ( "y", 4 )
self.vdd = VddIn ( "vdd" )
self.vss = VssIn ( "vss" )
self.vdde = VddIn ( "vdde" )
self.vsse = VssIn ( "vsse" )
def Netlist ( self ) :
cin_from_pads = Signal ( "cin_from_pads", 1 )
cout_to_pads = Signal ( "cout_to_pads", 1 )
np_to_pads = Signal ( "np_to_pads", 1 )
ng_to_pads = Signal ( "ng_to_pads", 1 )
ovr_to_pads = Signal ( "ovr_to_pads", 1 )
zero_to_pads = Signal ( "zero_to_pads", 1 )
shift_r = Signal ( "shift_r", 1 )
shift_l = Signal ( "shift_l", 1 )
signe_to_pads = Signal ( "signe_to_pads", 1 )
r0_to_pads = Signal ( "r0_to_pads", 1 )
r3_to_pads = Signal ( "r3_to_pads", 1 )
r0_from_pads = Signal ( "r0_from_pads", 1 )
r3_from_pads = Signal ( "r3_from_pads", 1 )
q0_to_pads = Signal ( "q0_to_pads", 1 )
q3_to_pads = Signal ( "q3_to_pads", 1 )
q0_from_pads = Signal ( "q0_from_pads", 1 )
q3_from_pads = Signal ( "q3_from_pads", 1 )
ck_ring = Signal ( "ck_ring", 1 )
a_from_pads = Signal ( "a_from_pads", 4 )
b_from_pads = Signal ( "b_from_pads", 4 )
d_from_pads = Signal ( "d_from_pads", 4 )
i_from_pads = Signal ( "i_from_pads", 9 )
y_to_pads = Signal ( "y_to_pads", 4 )
noe_from_pads = Signal ( "noe_from_pads", 1 )
y_oe = Signal ( "y_oe", 1 )
self.ckc = Signal ( "ckc", 1 )
self.coeur = Inst ( "coeur"
, "coeur"
, map = { 'cin_from_pads' : cin_from_pads
, 'cout_to_pads' : cout_to_pads
, 'np_to_pads' : np_to_pads
, 'ng_to_pads' : ng_to_pads
, 'ovr_to_pads' : ovr_to_pads
, 'signe_to_pads' : signe_to_pads
, 'zero_to_pads' : zero_to_pads
, 'shift_r' : shift_r
, 'shift_l' : shift_l
, 'r0_to_pads' : r0_to_pads
, 'r3_to_pads' : r3_to_pads
, 'r0_from_pads' : r0_from_pads
, 'r3_from_pads' : r3_from_pads
, 'q0_to_pads' : q0_to_pads
, 'q3_to_pads' : q3_to_pads
, 'q0_from_pads' : q0_from_pads
, 'q3_from_pads' : q3_from_pads
, 'ck' : self.ckc
, 'a_from_pads' : a_from_pads
, 'b_from_pads' : b_from_pads
, 'd_from_pads' : d_from_pads
, 'i_from_pads' : i_from_pads
, 'y_to_pads' : y_to_pads
, 'noe_from_pads' : noe_from_pads
, 'y_oe' : y_oe
, 'vdd' : self.vdd
, 'vss' : self.vss
}
)
self.p_ck = Inst ( "pck_px", "p_ck"
, map = { 'pad' : self.cke
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_cin = Inst ( "pi_px", "p_cin"
, map = { 'pad' : self.cin
, 't' : cin_from_pads
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_noe = Inst ( "pi_px", "p_noe"
, map = { 'pad' : self.noe
, 't' : noe_from_pads
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_a = {}
self.p_b = {}
self.p_d = {}
for i in range ( 4 ) :
self.p_a[i] = Inst ( "pi_px", "p_a%d" % i
, map = { 'pad' : self.a[i]
, 't' : a_from_pads[i]
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_b[i] = Inst ( "pi_px", "p_b%d" % i
, map = { 'pad' : self.b[i]
, 't' : b_from_pads[i]
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_d[i] = Inst ( "pi_px", "p_d%d" % i
, map = { 'pad' : self.d[i]
, 't' : d_from_pads[i]
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_i = {}
for i in range ( 9 ) :
self.p_i[i] = Inst ( "pi_px", "p_i%d" % i
, map = { 'pad' : self.i[i]
, 't' : i_from_pads[i]
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_cout = Inst ( "po_px", "p_cout"
, map = { 'i' : cout_to_pads
, 'pad' : self.cout
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_np = Inst ( "po_px", "p_np"
, map = { 'i' : np_to_pads
, 'pad' : self.np
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_ng = Inst ( "po_px", "p_ng"
, map = { 'i' : ng_to_pads
, 'pad' : self.ng
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_ovr = Inst ( "po_px", "p_ovr"
, map = { 'i' : ovr_to_pads
, 'pad' : self.ovr
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_zero = Inst ( "po_px", "p_zero"
, map = { 'i' : zero_to_pads
, 'pad' : self.zero
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_signe = Inst ( "po_px", "p_signe"
, map = { 'i' : signe_to_pads
, 'pad' : self.signe
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_y = {}
for i in range ( 4 ) :
self.p_y[i] = Inst ( "pot_px", "p_y%d" % i
, map = { 'i' : y_to_pads[i]
, 'b' : y_oe
, 'pad' : self.y[i]
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_q0 = Inst ( "piot_px", "p_q0"
, map = { 'i' : q0_to_pads
, 'b' : shift_r
, 't' : q0_from_pads
, 'pad' : self.q0
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_q3 = Inst ( "piot_px", "p_q3"
, map = { 'i' : q3_to_pads
, 'b' : shift_l
, 't' : q3_from_pads
, 'pad' : self.q3
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_r0 = Inst ( "piot_px", "p_r0"
, map = { 'i' : r0_to_pads
, 'b' : shift_r
, 't' : r0_from_pads
, 'pad' : self.r0
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_r3 = Inst ( "piot_px", "p_r3"
, map = { 'i' : r3_to_pads
, 'b' : shift_l
, 't' : r3_from_pads
, 'pad' : self.r3
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_vddick0 = Inst ( "pvddick_px", "p_vddick0"
, map = { 'cko' : self.ckc
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_vssick0 = Inst ( "pvssick_px", "p_vssick0"
, map = { 'cko' : self.ckc
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_vddeck0 = Inst ( "pvddeck_px", "p_vddeck0"
, map = { 'cko' : self.ckc
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_vddeck1 = Inst ( "pvddeck_px", "p_vddeck1"
, map = { 'cko' : self.ckc
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_vsseck0 = Inst ( "pvsseck_px", "p_vsseck0"
, map = { 'cko' : self.ckc
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
self.p_vsseck1 = Inst ( "pvsseck_px", "p_vsseck1"
, map = { 'cko' : self.ckc
, 'ck' : ck_ring
, 'vddi' : self.vdd
, 'vssi' : self.vss
, 'vdde' : self.vdde
, 'vsse' : self.vsse
}
)
def Layout ( self ) :
##### A COMLPETER #####
DefAb(XY(0,0),XY(3000,3000))
PlaceCentric(self.coeur)
PadNorth(self.p_i[3],self.p_i[4],self.p_i[5],self.p_b[0],self.p_b[1],self.p_b[2],self.p_b[3]
,self.p_q0,self.p_q3,self.p_i[6],self.p_i[7])
PadWest(self.p_ck,self.p_d[0],self.p_d[1],self.p_d[2],self.p_zero,self.p_vsseck0,self.p_ovr
,self.p_d[3],self.p_i[0],self.p_i[1],self.p_i[2])
PadSouth(self.p_cin,self.p_np,self.p_ng,self.p_vssick0,self.p_vddeck0,self.p_vsseck1,self.p_vddeck1
,self.p_cout,self.p_y[0],self.p_y[1],self.p_y[2])
PadEast(self.p_y[3],self.p_signe,self.p_noe,self.p_a[0],self.p_a[1],self.p_vddick0
,self.p_a[2],self.p_a[3],self.p_r0,self.p_r3,self.p_i[8])
PowerRing(3)
PlaceGlue(self.coeur)
FillCell(self.coeur)
RouteCk(self.ckc)
mon_chip = amd_chip ( "amd_2901_dpt" )
mon_chip.Interface ()
mon_chip.Netlist ()
#mon_chip.Layout ()
mon_chip.View ()
mon_chip.Save (LAYOUT)
Quels sont les fichiers obtenus? regardez en utilisant graal le résultat du placement.
Question 2
Faites varier la taille de la boite d'aboutement, qu'observez-vous ? Avez vous rencontré une limite ? peut-on en déduire la largeur des plots.
Exercice 2-Routage
Cette seconde étape consiste à relier les cellulesdu coeur entre elles. Vous allez pour cela utiliser l'outil nero . Consultez le man de nero
>nero -v -3 -p amd_chip_pl amd amd_route
Question 1
A quoi correspondent les options utilisées dans la commande ci-dessus? Faites varier le nombre de couches de métal utilisés pour le routage.
Exercice 3-Validation du routage
Cette étape consiste à vérifier que le routage a été effectué sans erreur. Il y a deux types de vérifications à réaliser
- Vérifier le respect des règles de dessin
- Vérifier les interconnexions réalisées
Question 1
Vérifiez le respect des règles de dessin en utilisant Druc . Vous aurez pris soin au préalable de vérifier que vous utilisez la technologie symbolique
Question 2
Utilisez l'outil cougar pour extraire la netlist de votre circuit au niveau "cellules de base ". Vous aurez au préalable pris soin de positionner la variable d'environnement MBK_OUT_LO au format al.
Question 3
Comparez la netlist extraite à celle d'origine (avnt routage) en utilisant l'outil lvx
