Subversion Repositories OpenARM Single-board Computer

Rev

Rev 231 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#!/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} = 300;
$y{right} = 300;
$y{labels} = -200;
$labelpin = 0;

# Read in the file, storing information about each pin.

my $pinnumwidth = 0;
my $blockname;

# vars used later too
#my (%x, %y);

my %pindata;

# vars used during parsing
my ($side, $busmode, $errors) = ('',0, 0);
# main loop which parses file
while (<>) {
        # skip empty lines
        next if /^#/;

        # cleanup leading/trailing spaces
        s/^\s+//;
        s/\s+$//;

        # convert spaces/tabs sequence to single space
        s/[\s\t]+/ /g;

        # remove all CR/LF newlines
        s/[\r\n]+$//;

        # 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 == 1) {
                        $y{$side} += 200;
                        $busmode = 0;
                }
                if ($space) {
                        if ($side =~ /left|right/) {
                                $y{$side} += 300;
                        }
                        if ($side =~ /top|bottom/) {
                                $x{$side} += 400;
                        }
                        $space = 0;
                }
                next;
        }


        # Hidden labels are stored separately, because we don't care how
        # big they are.
        if (/! (\S.*)/ && $side eq "labels") {
                # code probably could be more smart and store labels ex in certain order
                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") {
                # an blockswith
                if ($_ =~ /^block=/) {
                        $blockname = $_;
                        # printf STDERR "Blocname %s\n", $blockname;
                        next;
                }

                $labelpin --;
                $pinside{$labelpin} = $side;
                $piny{$labelpin} = $y{labels};
                $pinlabel{$labelpin} = $_;
                $y{labels} -= 200;
                $rlen{$labelpin} = &textlen($_);
                next;
        }

        # Regular pins are handled here.
        if (/^([0-9A-Za-z]+)\s*(.*)/) {
                $space = 1;
                ($pin, $rest) = ($1,$2);

                if ($saw_pin{$pin}) {
                        print STDERR "DUPLICATE PIN $pin (was $pinlabel{$pin}, now $rest)\n";
                        $errors ++;
                }

                $saw_pin{$pin} = 1;
                # our symbols use letters in names so next line wents wrong imo
                # we have two solutions, use numbers only (hard for BGA or sth like that)
                # or rework symdefs that we would get:
                # <#pin> <pin-number from datasheet> <pinname> <pintype> <other attributes>
                $maxpin = $pin if $maxpin < $pin;

                $pinside{$pin} = $side;

                next if $side eq "nc";

                if ($rest =~ /^([!>]+) (.*)/) {
                        $flags = $1;
                        $pinlabel{$pin} = $2;
                        $bubble{$pin} = 1 if $flags =~ /!/;
                        $edge{$pin} = 1 if $flags =~ />/;
                } else {
                        $pinlabel{$pin} = $rest;
                }

                # if pin has known suffix so it has pintype, maybe we have to rework current format too
                if ($pinlabel{$pin} =~ /type:([a-zA-Z]+)/) {
                        my $type = $1;
                        printf STDERR "Found pintype %s\n", $type;
                        $pinlabel{$pin} =~ s/type:$type//;
                        $pindata{$pin}{type} = $type;
                }
                $pinlabel{$pin} =~ s/^ +//;
                $pinlabel{$pin} =~ s/ +$//;
               
                $rlen{$pin} = &textlen($pinlabel{$pin});

                if ($pinnumwidth < &textlen($pin)) {
                        $pinnumwidth = &textlen($pin);
                }

                if ($side =~ /left|right/) {
                        $y = $piny{$pin} = $y{$side};
                        $y{$side} += ($busmode ? 200 : 300);
                }
               
                if ($side =~ /top|bottom/) {
                        $tw = &alignpin((200 + $rlen{$pin}) / 2);
                        $pinx{$pin} = $w{$side} + $tw;
                        $w{$side} += $tw + $tw;
                }

        }

}

# parser finished here

# round to nearest multiple of 100 larger or equal to actual number
$pinnumwidth += 100 - ($pinnumwidth % 100);

$minpin = $labelpin;
$boxwidth = 0;
%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-100; $y<=$yb+100; $y+=100) {
                # again we got not numbers inside, so lt/gt operator dont work well.. need to track why and how fix
                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};
        }
}
$maxy += 300;

# Now, use the slice widths to compute the minimum width of the box.
for ($i=0; $i<$maxy; $i+=100) {
        my $w = 0;

        $w += $bw{$i}{left} if (defined $bw{$i}{left});
        $w += $bw{$i}{labels} if (defined $bw{$i}{labels});
        $w += $bw{$i}{right} if (defined $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;
    }
    # need to review that if()'s
    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;
    }
}


for ($i = $y{labels}; $i <= 0; $i+=100) {
        my $w = $bw{$i}{labels};
        $w += 100 - ($w%100);
        if (defined $blockname && defined $bw{$i}{labels}) { # device name is longest, so rest arent affected
                my ($p,$q) = split ('=', $blockname,2);
                #printf STDERR "LINE %s %d w=%d\n", $bw{$i}{labels}, $i, $w;
                $w += &textlen($q) + 100; # same space enforcement as it was for inside labels
                #printf STDERR "LINE %s %d w=%d\n", $bw{$i}{labels}, $i, $w;
                # so we have to block name width to $w here..
                # but only in last line (device name)
        }
        #$w = (int($w/100) * 100) + (($w/100) > int($w/100))?100:0;
        if ($boxwidth < $w) {
                $boxwidth = $w;
        }
}

#printf STDERR "test: %d\n", $y{labels};

$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/;
    $piny{$p} = $maxy - $piny{$p} + 300;
}

for $p (keys %pinside) {
    next unless $pinside{$p} =~ /label/;
    $piny{$p} = $maxy + $piny{$p} - $minpin * 200 + 400;
}

$boxwidth = &alignpin($boxwidth);
$boxwidth += 200;

# Adjust the position of the top/bottom pins so that, as a group,
# they're centered.
for $p (keys %pinside) {
    next unless $pinside{$p} =~ /top|bottom/;
    $pinx{$p} += &alignpin(($boxwidth - $w{$pinside{$p}})/2) + $pinnumwidth;
}

# Labels are centered in the box.
# labels have to be top, lef
for $lp ($minpin..-1) {
    #$pinx{$lp} = &alignpin($boxwidth/2) + 300;
    $pinx{$lp} = $pinnumwidth;
}

# 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",
       $pinnumwidth, 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;
}

# blockname if present
if(defined $blockname) {
    printf("T %d %d 5 10 1 1 0 6 1\n%s\n", $boxwidth + $pinnumwidth, $maxy + 400, $blockname);
}

# Now print all the pins.
# and here non digit numbers bug us too, so we need to rework..
for $p (sort {$a<=>$b} keys %pinside) {
    next unless $pinside{$p};
    if ($pinside{$p} eq "left") {
        $pinx{$p} = $pinnumwidth;
    }
    if ($pinside{$p} eq "right") {
        $pinx{$p} = $pinnumwidth + $boxwidth;
    }
        # here we get warning about undefined value in addition, probably one of things isnt defined..
    if ($p > 0 && !$saw_pin{$p}) {
        print STDERR "MISSING PIN $p\n";
        $errors++;
    } else {
        printf STDERR ("%3d  %-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";
    &pltext($pinx{$pin}, $y-50, 5, $pinlabel{$pin});
    &ntext($pinx{$pin}+50, $y+50, 0, $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";
    &pltext($pinx{$pin}, 350, 3, $pinlabel{$pin});
    &ntext($pinx{$pin}+50, 250, 2, $pin);
    print "}\n";
}

sub drawpin_labels {
    my($pin) = @_;
    &ltext($pinx{$pin}, $piny{$pin}, 0, $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} - $pinnumwidth, $piny{$pin}, $x, $piny{$pin});
    print "{\n";
    &pltext($pinx{$pin} + $px, $piny{$pin}, 1, $pinlabel{$pin});

    # pintype
    if (defined $pindata{$pin} && defined $pindata{$pin}{type}) {
            printf("T %d %d 5 8 1 1 0 8 1\n%s\n", $pinx{$pin} - 50,
                    $piny{$pin} - 25, $pindata{$pin}{type});
    }
    &ntext($pinx{$pin} -100, $piny{$pin} + 50, 6, $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} + $pinnumwidth, $piny{$pin}, $x, $piny{$pin});
    print "{\n";
    &pltext($pinx{$pin} - $px, $piny{$pin}, 7, $pinlabel{$pin});

    # pintype
    if (defined $pindata{$pin} && defined $pindata{$pin}{type}) {
            printf("T %d %d 5 8 1 1 0 2 1\n%s\n", $pinx{$pin} + 50,
                    $piny{$pin} - 25, $pindata{$pin}{type});
    }

    &ntext($pinx{$pin} +100, $piny{$pin} + 50, 0, $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);
    printf("T %d %d 5 8 0 1 0 %s 1\npinseq=%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 ltext {
    my ($x, $y, $a, $s) = @_;
    printf("T %d %d 5 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) * 120;
}

sub alignpin {
    my($v) = @_;
    return int(($v + 99) / 100) * 100;
}

exit $errors;