Browse Source
Remove ddr3_length_match.py
Remove ddr3_length_match.py
The script is designed to be used with a particular board that does not exist in the repository.6.0.7
committed by
jean-pierre charras
3 changed files with 9 additions and 316 deletions
-
4pcbnew/python/examples/createFPC40.py
-
308scripts/ddr3_length_match.py
-
13scripts/test_kicad_plugin.py
@ -1,308 +0,0 @@ |
|||
#!/usr/bin/env python2 |
|||
|
|||
|
|||
# Author: Dick Hollenbeck |
|||
# Report any length problems pertaining to a SDRAM DDR3 T topology using |
|||
# 4 memory chips: a T into 2 Ts routing strategy from the CPU. |
|||
|
|||
# Designed to be run from the command line in a process separate from pcbnew. |
|||
# It can monitor writes to disk which will trigger updates to its output, or |
|||
# it can be run with --once option. |
|||
|
|||
|
|||
from __future__ import print_function |
|||
|
|||
import pcbnew |
|||
import os.path |
|||
import sys |
|||
import time |
|||
|
|||
|
|||
CPU_REF = 'U7' # CPU reference designator |
|||
|
|||
# four SDRAM memory chips: |
|||
DDR_LF = 'U15' # left front DRAM |
|||
DDR_RF = 'U17' # right front DRAM |
|||
DDR_LB = 'U16' # left back DRAM |
|||
DDR_RB = 'U18' # right back DRAM |
|||
|
|||
|
|||
# Length of SDRAM clock, it sets the maximum or equal needed for other traces |
|||
CLOCK_LEN = pcbnew.FromMils( 2.25 * 1000 ) |
|||
|
|||
def addr_line_netname(line_no): |
|||
"""From an address line number, return the netname""" |
|||
netname = '/DDR3/DRAM_A' + str(line_no) |
|||
return netname |
|||
|
|||
# Establish GOALS which are LENs, TOLERANCEs and NETs for each group of nets. |
|||
|
|||
# Net Group: ADDR_AND_CMD |
|||
ADDR_AND_CMD_LEN = pcbnew.FromMils( 2.22 * 1000 ) |
|||
ADDR_AND_CMD_TOLERANCE = pcbnew.FromMils( 25 ) / 2 |
|||
ADDR_AND_CMD_NETS = [addr_line_netname(a) for a in range(0,16)] |
|||
ADDR_AND_CMD_NETS += [ |
|||
'/DDR3/DRAM_SDBA0', |
|||
'/DDR3/DRAM_SDBA1', |
|||
'/DDR3/DRAM_SDBA2', |
|||
'/DDR3/DRAM_RAS_B', |
|||
'/DDR3/DRAM_CAS_B', |
|||
'/DDR3/DRAM_WE_B' |
|||
] |
|||
|
|||
|
|||
# Net Group: CONTROL |
|||
CONTROL_LEN = pcbnew.FromMils( 2.10 * 1000 ) |
|||
CONTROL_TOLERANCE = pcbnew.FromMils( 50 ) / 2 |
|||
CONTROL_NETS = [ |
|||
'/DDR3/DRAM_SDODT0', |
|||
#'/DDR3/DRAM_SDODT1', |
|||
'/DDR3/DRAM_CS0_B', |
|||
#'/DDR3/DRAM_CS1_B', |
|||
'/DDR3/DRAM_SDCKE0', |
|||
#'/DDR3/DRAM_SDCKE1', |
|||
] |
|||
|
|||
|
|||
|
|||
BRIGHTGREEN = '\033[92;1m' |
|||
GREEN = '\033[92m' |
|||
BRIGHTRED = '\033[91;1m' |
|||
RED = '\033[91m' |
|||
ENDC = '\033[0m' |
|||
|
|||
|
|||
pcb = None |
|||
nets = None |
|||
|
|||
dbg_conn = False # when true prints out reason for track discontinuity |
|||
|
|||
def print_color(color, s): |
|||
print(color + s + ENDC) |
|||
|
|||
|
|||
def addr_line_netname(line_no): |
|||
netname = '/DDR3/DRAM_A' + str(line_no) |
|||
return netname |
|||
|
|||
|
|||
def pad_name(pad): |
|||
return str( pad.GetParent().Reference().GetShownText() ) + '/' + pad.GetPadName() |
|||
|
|||
|
|||
def pad_pos(pad): |
|||
return str(pad.GetPosition()) |
|||
|
|||
|
|||
def pads_in_net(netname): |
|||
byname = {} |
|||
pads = nets[netname].Pads() |
|||
for pad in pads: |
|||
byname[pad_name(pad)] = pad |
|||
return byname |
|||
|
|||
|
|||
def track_ends(track): |
|||
"""return a string showing both ends of a track""" |
|||
return str(track.GetStart()) + ' ' + str(track.GetEnd()) |
|||
|
|||
|
|||
def print_tracks(net_name,tracks): |
|||
print('net:', net_name) |
|||
for track in tracks: |
|||
print(' track:', track_ends(track)) |
|||
|
|||
|
|||
def sum_track_lengths(point1,point2,netcode): |
|||
tracks = pcb.TracksInNetBetweenPoints(point1, point2, netcode) |
|||
sum = 0 |
|||
for t in tracks: |
|||
sum += t.GetLength() |
|||
return sum |
|||
|
|||
|
|||
def tracks_in_net(netname): |
|||
nc = pcb.GetNetcodeFromNetname(netname) |
|||
tracks_and_vias = pcb.TracksInNet(nc) |
|||
# remove vias while making new non-owning list |
|||
tracks = [t for t in tracks_and_vias if not t.Type() == pcbnew.PCB_VIA_T] |
|||
return tracks |
|||
|
|||
|
|||
def print_pad(pad): |
|||
print( " pad name:'%s' pos:%s" % ( pad_name(pad), pad_pos(pad) ) ) |
|||
|
|||
|
|||
def print_pads(prompt,pads): |
|||
print(prompt) |
|||
for pad in pads: |
|||
print_pad(pad) |
|||
|
|||
|
|||
def is_connected(start_pad, end_pad): |
|||
""" |
|||
Return True if the two pads are copper connected only with vias and tracks |
|||
directly and with no intervening pads, else False. |
|||
""" |
|||
netcode = start_pad.GetNet().GetNet() |
|||
try: |
|||
tracks = pcb.TracksInNetBetweenPoints(start_pad.GetPosition(), end_pad.GetPosition(), netcode) |
|||
except IOError as ioe: |
|||
if dbg_conn: # can be True when wanting details on discontinuity |
|||
print(ioe) |
|||
return False |
|||
return True |
|||
|
|||
|
|||
def find_connected_pad(start_pad, pads): |
|||
for p in pads: |
|||
if p == start_pad: |
|||
continue |
|||
if is_connected(start_pad,p): |
|||
return p |
|||
raise IOError( 'no connection to pad %s' % pad_name(start_pad) ) |
|||
|
|||
|
|||
def find_cpu_pad(pads): |
|||
for p in pads: |
|||
if CPU_REF in pad_name(p): |
|||
return p |
|||
raise IOError( 'no cpu pad' ) |
|||
|
|||
|
|||
def report_teed_lengths(groupname, netname, target_length, tolerance): |
|||
global dbg_conn |
|||
|
|||
print(groupname, netname) |
|||
nc = pcb.GetNetcodeFromNetname(netname) |
|||
#print("nc", nc) |
|||
|
|||
pads = nets[netname].Pads() |
|||
|
|||
# convert from std::vector<> to python list |
|||
pads = list(pads) |
|||
#print_pads(netname, pads ) |
|||
|
|||
cpu_pad = find_cpu_pad(pads) |
|||
pads.remove(cpu_pad) |
|||
|
|||
# a trap for a troublesome net that appears to be disconnected or has stray segments. |
|||
if netname == None: |
|||
#if netname == '/DDR3/DRAM_SDCKE0': |
|||
dbg_conn = True |
|||
|
|||
# find the first T |
|||
#print_pads(netname + ' without cpu pad', pads ) |
|||
t1 = find_connected_pad(cpu_pad, pads) |
|||
pads.remove(t1) |
|||
|
|||
# find 2 second tier T pads |
|||
t2_1 = find_connected_pad(t1, pads) |
|||
pads.remove(t2_1) |
|||
|
|||
t2_2 = find_connected_pad(t1, pads) |
|||
pads.remove(t2_2) |
|||
|
|||
cpad = [0] * 4 |
|||
|
|||
# find 4 memory pads off of each 2nd tier T |
|||
cpad[0] = find_connected_pad(t2_1, pads) |
|||
pads.remove(cpad[0]) |
|||
|
|||
cpad[1] = find_connected_pad(t2_1, pads) |
|||
pads.remove(cpad[1]) |
|||
|
|||
cpad[2] = find_connected_pad(t2_2, pads) |
|||
pads.remove(cpad[2]) |
|||
|
|||
cpad[3] = find_connected_pad(t2_2, pads) |
|||
pads.remove(cpad[3]) |
|||
|
|||
len_t1 = sum_track_lengths(cpu_pad.GetPosition(),t1.GetPosition(),nc) |
|||
#print("len_t1 %.0f" % len_t1) |
|||
|
|||
len_t2_1 = sum_track_lengths(t1.GetPosition(),t2_1.GetPosition(),nc) |
|||
len_t2_2 = sum_track_lengths(t1.GetPosition(),t2_2.GetPosition(),nc) |
|||
#print("len_t2_1 %.0f" % len_t2_1) |
|||
#print("len_t2_2 %.0f" % len_t2_2) |
|||
|
|||
lens = [0] * 4 |
|||
|
|||
lens[0] = sum_track_lengths(t2_1.GetPosition(),cpad[0].GetPosition(),nc) |
|||
lens[1] = sum_track_lengths(t2_1.GetPosition(),cpad[1].GetPosition(),nc) |
|||
lens[2] = sum_track_lengths(t2_2.GetPosition(),cpad[2].GetPosition(),nc) |
|||
lens[3] = sum_track_lengths(t2_2.GetPosition(),cpad[3].GetPosition(),nc) |
|||
|
|||
""" |
|||
for index, total_len in enumerate(lens): |
|||
print( "%s: %.0f" % (pad_name(cpad[index]), lens[index])) |
|||
""" |
|||
|
|||
# Each net goes from CPU to four memory chips, these are the 4 lengths from |
|||
# CPU to each of the for memory chip balls/pads, some of these journeys are |
|||
# common with one another but branch off at each T. |
|||
lens[0] += len_t1 + len_t2_1 |
|||
lens[1] += len_t1 + len_t2_1 |
|||
lens[2] += len_t1 + len_t2_2 |
|||
lens[3] += len_t1 + len_t2_2 |
|||
|
|||
for index, total_len in enumerate(lens): |
|||
delta = total_len - target_length |
|||
if delta > tolerance: |
|||
print_color( BRIGHTRED, "%s %s len:%.0f long by %.0f mils" % |
|||
(netname, pad_name(cpad[index]), pcbnew.ToMils(total_len), pcbnew.ToMils(delta - tolerance) )) |
|||
elif delta < -tolerance: |
|||
print_color( BRIGHTRED, "%s %s len:%.0f short by %.0f mils" % |
|||
(netname, pad_name(cpad[index]), pcbnew.ToMils(total_len), pcbnew.ToMils(tolerance - delta) )) |
|||
|
|||
|
|||
|
|||
def load_board_and_report_lengths(filename): |
|||
|
|||
global pcb |
|||
pcb = pcbnew.LoadBoard(filename) |
|||
pcb.BuildListOfNets() # required so 'pcb' contains valid netclass data |
|||
|
|||
global nets |
|||
nets = pcb.GetNetsByName() |
|||
|
|||
for netname in ADDR_AND_CMD_NETS: |
|||
report_teed_lengths("addr_and_cmd", netname, ADDR_AND_CMD_LEN, ADDR_AND_CMD_TOLERANCE) |
|||
|
|||
for netname in CONTROL_NETS: |
|||
report_teed_lengths("control", netname, CONTROL_LEN, CONTROL_TOLERANCE) |
|||
|
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
try: |
|||
boardfile = sys.argv[1] |
|||
except IndexError: |
|||
print("Usage: %s <boardname.kicad_pcb> [--once]" % sys.argv[0]) |
|||
sys.exit(1) |
|||
|
|||
first = True |
|||
|
|||
while True: |
|||
|
|||
# wait for the file contents to change |
|||
lastmtime = os.path.getmtime(boardfile) |
|||
mtime = lastmtime |
|||
while mtime == lastmtime and not first: |
|||
try: |
|||
mtime = os.path.getmtime(boardfile) |
|||
except OSError: |
|||
pass # kicad save process seems to momentarily delete file, so there's a race here with "No such file.." |
|||
time.sleep(0.5) |
|||
|
|||
# The "Debug" build of pcbnew writes to disk slowly, new file takes time to get to disk. |
|||
time.sleep(1) |
|||
|
|||
first = False |
|||
|
|||
print( '\033[2J' ) # clear screen, maybe |
|||
|
|||
load_board_and_report_lengths(boardfile) |
|||
|
|||
if "--once" in sys.argv: |
|||
sys.exit(0) |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue