#!/usr/bin/perl # -*- perl -*- # Copyright (C) 2006 DJ Delorie dj@delorie.com # Released under the terms of the GNU General Public License, version 2 # Usage: djboxsym sample.symdef > sample.sym $y{left} = 400; $y{right} = 400; $y{labels} = 600; $labelpin = 0; $busspace = 200; $groupspace = 400; $skipspace = 800; $yinvert = 300; $minwidth = 0; # If set, top and bottom labels are vertical. $vmode = 0; # Read in the file, storing information about each pin. while (<>) { next if /^#/; s/^\s+//; s/\s+$//; s/[\s\t]+/ /g; s/[\r\n]+$//; # options if (/^--(\S*)\s*(.*)/) { $opt = $1; @args = split(' ', $2); ($opt, $value) = split(' ', $opt, 2); if ($opt eq "vmode") { $vmode = 1; # $y{left} = $y{right} = 0; } if ($opt eq "square") { $square = 1; } if ($opt eq "minwidth") { $minwidth = $args[0]; } if ($opt eq "compact") { $groupspace = 200; $skipspace = 400; $yinvert = 400; $compactmode = 1; } next; } # Note change of section. if (/^\[(.*)\]/) { $side = $1; $space = 0; next; } # Start a bus if (/^\.bus/) { $busmode = 1; next; } # blank lines - cancel bus, add gap. if (! /\S/) { if ($busmode) { $y{$side} += $busspace; } $busmode = 0; if ($space) { if ($side =~ /left|right/) { $y{$side} += $groupspace; } if ($side =~ /top|bottom/) { $x{$side} += 400; } $space = 0; } next; } if (/^\.skip (\d+)/) { $skip = $1; $space = 0; if ($side =~ /left|right/) { $y{$side} += $skip; } next; } # Hidden labels are stored separately, because we don't care how # big they are. if (/! (\S.*)/ && $side eq "labels") { push(@attrs, $1); next; } # Visible labels are stored as pins because their size affects the # size of the symbols' box. if (/\S/ && $side eq "labels") { $labelpin --; $pinside{$labelpin} = $side; $piny{$labelpin} = $y{labels}; $pinlabel{$labelpin} = $_; $y{labels} += $groupspace; $rlen{$labelpin} = &textlen($_); next; } # Regular pins are handled here. if (/^(\S+)\s*(.*)/) { $space = 1; ($pin, $rest) = ($1,$2); if ($pin =~ /^\d+$/) { $pinseq_used[$pin] = 1; } if ($saw_pin{$pin}) { print STDERR "DUPLICATE PIN $pin (was $pinlabel{$pin}, now $rest)\n"; $errors ++; } $saw_pin{$pin} = 1; $maxpin = $pin if $maxpin < $pin; $pinside{$pin} = $side; $pintype{$pin} = "pas"; next if $side eq "nc"; if ($rest =~ /^([!>iop]+) (.*)/) { $flags = $1; $pinlabel{$pin} = $2; $bubble{$pin} = 1 if $flags =~ /!/; $edge{$pin} = 1 if $flags =~ />/; $pintype{$pin} = "in" if $flags =~ /i/; $pintype{$pin} = "out" if $flags =~ /o/; $pintype{$pin} = "pwr" if $flags =~ /p/; $pintype{$pin} = "inout" if $flags =~ /io/; } else { $pinlabel{$pin} = $rest; } $rlen{$pin} = &textlen($pinlabel{$pin}); if ($side =~ /left|right/) { $y = $piny{$pin} = $y{$side}; $y{$side} += ($busmode ? $busspace : $groupspace); } if ($side =~ /top|bottom/) { $tw = &alignpin((200 + $rlen{$pin}) / 2); if ($vmode) { $pinx{$pin} = $w{$side}; $w{$side} += (($busmode || $compactmode) ? 200 : 400); } else { $pinx{$pin} = $w{$side} + $tw; $w{$side} += $tw + $tw; } } } } $pinseq = 1; $minpin = $labelpin; $boxwidth = $minwidth; %bw = (); # for each horizontal slice of the symbol, keep track of how much # width is used up by the left, middle, and right labels. for $lp (keys %pinside) { next unless $pinside{$lp} =~ /left|right|label/; $yb = &alignpin($piny{$lp}); for ($y=$yb-300; $y<=$yb+300; $y+=100) { if ($bw{$y}{$pinside{$lp}} < $rlen{$lp}) { $bw{$y}{$pinside{$lp}} = $rlen{$lp}; } } } # Compute the height of the box. for $p (keys %pinside) { next unless $pinside{$p} =~ /left|right/; if ($maxy < $piny{$p}) { $maxy = $piny{$p}; } } if (! $vmode) { $maxy += $groupspace; } # Now, use the slice widths to compute the minimum width of the box. for ($i=0; $i<$maxy; $i+=100) { $w = $bw{$i}{left} + $bw{$i}{labels} + $bw{$i}{right}; if ($bw{$i}{labels}) { $wl = ($bw{$i}{left} + $bw{$i}{labels}/2) * 2; $w = $wl if $w < $wl; $wl = ($bw{$i}{right} + $bw{$i}{labels}/2) * 2; $w = $wl if $w < $wl; } if ($bw{$i}{left} && $bw{$i}{labels}) { $w += 100; } elsif ($bw{$i}{left} && $bw{$i}{right}) { $w += 200; } if ($bw{$i}{right} && $bw{$i}{labels}) { $w += 100; } if ($boxwidth < $w) { $boxwidth = $w; } } $boxwidth = $w{top} if $boxwidth < $w{top}; $boxwidth = $w{bottom} if $boxwidth < $w{bottom}; # Flip Y coordinates (we count from the top, but symbols coordinates # are from the bottom). for $p (keys %pinside) { next unless $pinside{$p} =~ /left|right|labels/; $piny{$p} = $maxy - $piny{$p} + $yinvert; } $boxwidth = &alignpin($boxwidth); $boxwidth += 200; # Adjust the position of the top/bottom pins so that, as a group, # they're centered. %maxh = (); for $p (keys %pinside) { next unless $pinside{$p} =~ /top|bottom/; $pinx{$p} += &alignpin(($boxwidth - $w{$pinside{$p}})/2) + 300; if ($vmode) { $pinx{$p} += 200; $h = &textlen($pinlabel{$p}); $maxh{$pinside{$p}} = $h if $maxh{$pinside{$p}} < $h; } } if ($vmode) { $dy = &alignpin($maxh{bottom}); for $lp ($minpin..-1) { $piny{$lp} += $dy; } for $p (keys %pinside) { if ($pinside{$p} =~ /left|right|bottom/) { $piny{$p} += $dy; } } $maxy += $dy + &alignpin ($maxh{top}); } if ($square) { if ($boxwidth < $maxy) { $delta = $maxy - $boxwidth; $delta = &alignpin($delta / 2); $boxwidth = $maxy; for $p (keys %pinside) { if ($pinside{$p} =~ /top|bottom/) { $pinx{$p} += $delta; } } } if ($maxy < $boxwidth) { $maxy = $boxwidth; } } # Labels are centered in the box. for $lp ($minpin..-1) { $pinx{$lp} = &alignpin($boxwidth/2) + 300; } # Version. print "v 20060123 1\n"; # Symbol box. printf("B %d %d %d %d 3 0 0 0 -1 -1 0 -1 -1 -1 -1 -1\n", 300, 300, $boxwidth, $maxy); # These are the hidden labels. $ax = 300 + $boxwidth; $ay = 400 + $maxy; for $a (reverse @attrs) { printf("T %d %d 9 10 0 0 0 0 1\n%s\n", $ax, $ay, $a); $ay += 200; } sub pinsort { my ($a, $b) = @_; $a =~ tr/a-z/A-Z/; $b =~ tr/a-z/A-Z/; $a =~ s/(\d+)/sprintf("%06d", $1);/ge; $b =~ s/(\d+)/sprintf("%06d", $1);/ge; return $a cmp $b; } # Now print all the pins. for $p (sort {&pinsort($a,$b)} keys %pinside) { next unless $pinside{$p}; if ($pinside{$p} eq "left") { $pinx{$p} = 300; } if ($pinside{$p} eq "right") { $pinx{$p} = 300 + $boxwidth; } if ($p > 0 && !$saw_pin{$p}) { print STDERR "MISSING PIN $p\n"; $errors++; } else { printf STDERR ("%3s %-6s %4d %4d %s\n", $p, $pinside{$p}, $pinx{$p}, $piny{$p}, $pinlabel{$p}); } eval "&drawpin_$pinside{\"$p\"} (\"$p\")"; } # what remains are helper functions; for drawing each type of pin, # each type of label, etc. sub drawpin_nc { } sub drawpin_top { my($pin) = @_; $y = $maxy + 300; printf("P %d %d %d %d 1 0 0\n", $pinx{$pin}, $y+300, $pinx{$pin}, $y); print "{\n"; if ($vmode) { &pvltext($pinx{$pin}, $y-50, 7, $pinlabel{$pin}); } else { &pltext($pinx{$pin}, $y-50, 5, $pinlabel{$pin}); } &ntext($pinx{$pin}+50, $y+50, 0, $pin); &pttext($pinx{$pin} -100, $piny{$pin} + 50, 6, $pintype{$pin}); print "}\n"; } sub drawpin_bottom { my($pin) = @_; printf("P %d %d %d %d 1 0 0\n", $pinx{$pin}, 0, $pinx{$pin}, 300); print "{\n"; if ($vmode) { &pvltext($pinx{$pin}, 350, 1, $pinlabel{$pin}); } else { &pltext($pinx{$pin}, 350, 3, $pinlabel{$pin}); } &ntext($pinx{$pin}+50, 250, 2, $pin); &pttext($pinx{$pin} -100, $piny{$pin} + 50, 6, $pintype{$pin}); print "}\n"; } sub drawpin_labels { my($pin) = @_; <ext($pinx{$pin}, $piny{$pin}, 3, $pinlabel{$pin}); } sub circle { my ($x, $y) = @_; print "V $x $y 50 3 0 0 0 -1 -1 0 -1 -1 -1 -1 -1\n"; } sub drawpin_left { my($pin) = @_; $x = $pinx{$pin}; $px = 50; if ($bubble{$pin}) { $x -= 100; &circle($x+50, $piny{$pin}); } if ($edge{$pin}) { $px += 100; printf("L %d %d %d %d 3 0 0 0 0 0\n", $pinx{$pin}, $piny{$pin}-50, $pinx{$pin}+100, $piny{$pin}); printf("L %d %d %d %d 3 0 0 0 0 0\n", $pinx{$pin}+100, $piny{$pin}, $pinx{$pin}, $piny{$pin}+50); } printf("P %d %d %d %d 1 0 0\n", $pinx{$pin} - 300, $piny{$pin}, $x, $piny{$pin}); print "{\n"; &pltext($pinx{$pin} + $px, $piny{$pin}, 1, $pinlabel{$pin}); &ntext($pinx{$pin} -100, $piny{$pin} + 50, 6, $pin); &pttext($pinx{$pin} -100, $piny{$pin} + 50, 6, $pintype{$pin}); print "}\n"; } sub drawpin_right { my($pin) = @_; $x = $pinx{$pin}; $px = 50; if ($bubble{$pin}) { $x += 100; &circle($x-50, $piny{$pin}); } if ($edge{$pin}) { $px += 100; printf("L %d %d %d %d 3 0 0 0 0 0\n", $pinx{$pin}, $piny{$pin}-50, $pinx{$pin}-100, $piny{$pin}); printf("L %d %d %d %d 3 0 0 0 0 0\n", $pinx{$pin}-100, $piny{$pin}, $pinx{$pin}, $piny{$pin}+50); } printf("P %d %d %d %d 1 0 0\n", $pinx{$pin} + 300, $piny{$pin}, $x, $piny{$pin}); print "{\n"; &pltext($pinx{$pin} - $px, $piny{$pin}, 7, $pinlabel{$pin}); &ntext($pinx{$pin} +100, $piny{$pin} + 50, 0, $pin); &pttext($pinx{$pin} -100, $piny{$pin} + 50, 6, $pintype{$pin}); print "}\n"; } sub ntext { my ($x, $y, $a, $s) = @_; printf("T %d %d 5 8 1 1 0 %s 1\npinnumber=%s\n", $x, $y, $a, $s); if ($s =~ /^\d+$/) { $my_pinseq = $s; } else { while ($pinseq_used[$pinseq]) { $pinseq ++; } $pinseq_used[$pinseq] = 1; $my_pinseq = $pinseq; } printf("T %d %d 5 8 0 1 0 %s 1\npinseq=%d\n", $x, $y, $a, $my_pinseq); } sub pttext { my ($x, $y, $a, $s) = @_; printf("T %d %d 9 10 0 1 0 %s 1\npintype=%s\n", $x, $y, $a, $s); } sub pltext { my ($x, $y, $a, $s) = @_; $s = "pinlabel=$s" unless $s =~ /=/; printf("T %d %d 9 10 1 1 0 %s 1\n%s\n", $x, $y, $a, $s); } sub pvltext { my ($x, $y, $a, $s) = @_; $s = "pinlabel=$s" unless $s =~ /=/; printf("T %d %d 9 10 1 1 90 %s 1\n%s\n", $x, $y, $a, $s); } sub ltext { my ($x, $y, $a, $s) = @_; printf("T %d %d 9 10 1 1 0 %s 1\n%s\n", $x, $y, $a, $s); } sub textlen { my($t) = @_; $t =~ s/^[^=]*=//; $t =~ s@\\_@@g; return length($t) * 110; } sub alignpin { my($v) = @_; return int(($v + 99) / 100) * 100; } exit $errors;