X-Git-Url: http://git.rot13.org/?p=x300-pci;a=blobdiff_plain;f=openocd-jtag-boundary-scan.pl;h=76c16ed8329257982d739921c8b504b117fd848b;hp=3169f1b7a1526cd9a6aa9860aa990837e4469593;hb=HEAD;hpb=5fc05729659e32121fdcb291c9b3e1bfd7daca04 diff --git a/openocd-jtag-boundary-scan.pl b/openocd-jtag-boundary-scan.pl index 3169f1b..76c16ed 100755 --- a/openocd-jtag-boundary-scan.pl +++ b/openocd-jtag-boundary-scan.pl @@ -8,38 +8,76 @@ use IO::Socket::INET; use Storable; my $openocd_remote = shift @ARGV || 'picam:4444'; +my $bsdl_file = $ENV{BSDL} || + 'x300-dongle/3064at44.bsd'; # XXX +#$bsdl_file = 'EP4CE6E22.bsd'; +#$bsdl_file = '_3128at100.bsd'; +my $project_file = 'Altera/epm3064_dac/3064at44.qsf'; +#$project_file = 'tb276/f32c.qsf'; + +my $BOUNDARY_LENGTH = -1; +my $entity; my $bit2pin; my $io2bit; my $pin2io; -my $in_pin_map = 0; -my $pin_map = ''; +my $parse; +my $parse_in = 0; +my $parse_regex = join('|', qw( + PIN_MAP_STRING + INSTRUCTION_OPCODE + INSTRUCTION_LENGTH + IDCODE_REGISTER +)); $|=1; # flush stdout -open(my $bsdl, '<', '_3128at100.bsd'); +my $have_gpio = `which gpio`; +warn "# ", ! $have_gpio ? "DOESN'T " : '', "have rpi gpio\n"; +require 'gpio.pl' if $have_gpio; + +open(my $bsdl, '<', $bsdl_file); while(<$bsdl>) { - if ( m/PIN_MAP_STRING/ ) { - $pin_map .= $_; - $in_pin_map = 1; - } elsif ( $in_pin_map ) { + if ( m/($parse_regex)/ ) { + $parse_in = $1; + $parse->{$1} .= $_; + } elsif ( $parse_in ) { next if m/^\s*--/; - $pin_map .= $_; - $in_pin_map = 0 if m/;/; + s/\s+--.+$//; # remove comments and EOL + $parse->{$parse_in} .= $_; + $parse_in = 0 if m/;/; } elsif ( m/"(\d+)\s+\(BC_\d+,\s+(\S+),\s+(\S+)/ ) { $bit2pin->{$1} = [ $2, $3 ]; push @{ $io2bit->{$2} }, $1; + } elsif ( m/attribute\s+BOUNDARY_LENGTH\s+of\s+\S+\s*:\s*entity\s+is\s+(\d+);/ ) { + $BOUNDARY_LENGTH = $1; + warn "# BSDL $bsdl_file BOUNDARY_LENGTH = $BOUNDARY_LENGTH\n"; + } elsif ( ! $entity && m/^entity\s(\S+)\s+is/ ) { + $entity = $1; + warn "# entity = $entity\n"; } + } close($bsdl); warn "# bit2pin = ",dump($bit2pin); warn "# io2bit = ",dump($io2bit); -$pin_map =~ s/"\s*\&\s*"/ /gs; -$pin_map =~ s/^.*?:=\s*"//; -$pin_map =~ s/"\s*;\s*$//s; +foreach my $chunk ( keys %$parse ) { + $parse->{$chunk} =~ s/"\s*\&\s*"/ /gs; # concat lines back to single line + $parse->{$chunk} =~ s/^.+?"//s; # strip upto first quote + $parse->{$chunk} =~ s/"\s*;.*?$//s; # strip everything after closing + $parse->{$chunk} =~ s/\s+/ /gs; + $parse->{$chunk} =~ s/^\s+//; + $parse->{$chunk} =~ s/\s+$//; + $parse->{$chunk} =~ s/attribute\s+$chunk\s+of\s+$entity\s+:\s+entity\s+is\s+(\d+)\s*;/$1/; + +} + +warn "# parse = ",dump($parse); + +my $pin_map = $parse->{PIN_MAP_STRING} || die "no PIN_MAP_STRING in ",dump($parse); sub str_comma { my $t = shift; @@ -57,33 +95,111 @@ foreach my $map ( split(/\s*,\s*/, $pin_map) ) { } warn "# pin2io = ",dump( $pin2io ); -store \$pin2io, '/dev/shm/pin2io.storable'; +#store \$pin2io, $bsdl_file . '.pin2io.storable'; +store \$pin2io, $entity . '.pin2io.storable'; + + +my $opcode; +my $o = $parse->{INSTRUCTION_OPCODE} || die "no INSTRUCTION_OPCODE in ",dump($parse); + +foreach ( split(/\)\s*,\s*/, $o) ) { + s/\s+\(/ /g; + s/\s*\)\s*$//g; + warn "### [$_]\n"; + my ( $inst_opcode, $bin ) = split(/\s+/, $_); + $opcode->{$inst_opcode} = sprintf "0x%02x", eval '0b' . $bin; +} +warn "# opcode = ",dump($opcode); + +foreach (qw(SAMPLE EXTEST)) { + die "missing INSTRUCTION_OPCODE $_ in ",dump($opcode) unless $opcode->{$_}; +} + +my $pin_desc; +foreach my $pin_file ( glob "pins/$entity*.tsv" ) { + open(my $fh, '<', $pin_file); + while(<$fh>) { + chomp; + my ($pin,$desc, $bcm) = split(/\t+/,$_,3); + $pin_desc->{$pin} = $desc; + gpio::add_bcm_desc( $bcm => $desc ) if $have_gpio; + } + close($fh); + warn "# $pin_file ",dump($pin_desc); +} + +{ + open(my $fh, '<', $project_file); + while(<$fh>) { + chomp; + s/[\r\n]+$//; + next if m/^\s*#/; + my ($set,$pin, $op, $desc) = split(/\s+/,$_,4); + if ( $set =~ m/set_location_assignment/i && $op =~ m/-to/i && $pin =~ s/^PIN_//ig ) { + $pin_desc->{$pin} = $desc; # overwrite pin description + } else { + #warn "## ignored $_\n"; + } + } + close($fh); + warn "# $project_file ",dump($pin_desc); +} +=for remove my @sort = sort { my $aa = $a; $aa =~ s/\D+//g; my $bb = $b; $bb =~ s/\D+//g; $aa <=> $bb } keys %$io2bit; warn "# sort = ",dump(@sort); +=cut + +sub bits { + my $bits = shift; + return $bits; # FIXME disable for now + $bits =~ s/0/ /; + $bits =~ s/^(.)0/$1 /; + $bits =~ s/^1/I/; + $bits =~ s/^(.)1/$1./; + return $bits; +} my $last_bits = ''; sub print_io { my $bits = shift; + return unless length($bits) == $BOUNDARY_LENGTH; my $o_bits = $bits; $bits = reverse $bits; # make substr work as expected + my $last_bits_r = reverse $last_bits; - print "pin off io___ ICO prv | " x 4, $openocd_remote,"\n"; + print "pin off io___ ICO | " x 4, $openocd_remote,"\n"; foreach my $i ( 0 .. ($#$pin2io/4)-1 ) { foreach my $j ( 0 .. 3 ) { #my $pin = ($i*4) + $j + 1; # rows my $pin = ($#$pin2io/4) * $j + $i + 1; # columns my $io = $pin2io->[$pin]; my $o = $io2bit->{$io}->[0]; + if ( defined $o ) { my $l = $b = substr($bits, $o, 3); - $l = substr($last_bits,$o,3) if $last_bits; - printf "%-3d %-3d %-5s %3s %3s | ", $pin, $o, $io, $b, $b ne $l ? $l : '' + $l = substr($last_bits_r,$o,3) if $last_bits; + + my $desc = $pin_desc->{$pin} || ''; + my $bits = bits($b); + if ( $b ne $l ) { + my @b = split(//, $bits); + my @l = split(//, bits($l)); + $bits = ''; + foreach ( 0 .. $#b ) { + $bits .= $b[$_] eq $l[$_] ? $b[$_] : "\e[33;7;1m$b[$_]\e[0m"; + } + } + + $desc = ' ' . $desc if length($desc) < 10; + $desc = substr($desc,0,10); + + printf "%-3d %-3d %-5s %3s%-10s| ", $pin, $o, $io, $bits, $desc; } else { - printf "%-3d ... %-5s %3s %3s | ", $pin, $io, '', ''; + printf "%-3d ... %-18s | ", $pin, $io; } } print "\n"; @@ -107,18 +223,19 @@ sub hex2bin { sub bin2hex { my $b = shift; + $b =~ s/\s+//g; my $blen = length($b); my $hlen = $blen / 4; return unpack("H$hlen", pack("B$blen", $b)); } -#my $cmd; + +my $tap; +print $sock "jtag names\n"; # will fill-in $tap variable from openocd my $BSR; -# first sample -print $sock "irscan x300.tap 0x55\n"; # SAMPLE/PRELOAD -print $sock "drscan x300.tap 288 0\n"; +my $scan_chain; while(1) { @@ -126,37 +243,68 @@ while (<$sock>) { warn "<< ",dump($_); chomp; s/[\r\x00]+//g; - if ( /^\s*([A-F0-9]+)/ ) { + if ( ! $tap && m/^(\w+\.tap)$/ ) { + $tap = $1; + warn "# using TAP $tap\n"; + + print $sock "scan_chain\n"; + $scan_chain = 0; + + } elsif ( ! $scan_chain && m/\d+\s+$tap\s+Y\s+0x([0-9a-f]+)\s+0x[0-9a-f]+\s+(\d+)/ ) { + + my ($IdCode,$IrLen) = ( $1, $2 ); + + my $bsdl_id_code = bin2hex( $parse->{IDCODE_REGISTER} ); + die "IdCode != IDCODE_REGISTER $IdCode != $bsdl_id_code" if lc($IdCode) ne lc($bsdl_id_code); + + die "IrLen != INSTRUCTION_LENGTH $IrLen != $parse->{INSTRUCTION_LENGTH}" if $IrLen != $parse->{INSTRUCTION_LENGTH}; + + warn "# OK IdCode $IdCode IrLen $IrLen\n"; + $scan_chain = 1; + + # first sample + print $sock "irscan $tap $opcode->{SAMPLE}\n"; # SAMPLE/PRELOAD + print $sock "drscan $tap $BOUNDARY_LENGTH 0\n"; + + } elsif ( /^\s*([A-F0-9]+)$/ ) { my $hex = $1; my $bin = hex2bin($hex); + $bin = substr($bin,0, $BOUNDARY_LENGTH) if length($bin) > $BOUNDARY_LENGTH; diff_bits($BSR, $bin); $BSR = $bin; print_io $bin if $bin ne $last_bits; + gpio::pins() if $have_gpio; last; + } elsif ( m/>\s+\S+/ ) { + # ignore command echo } else { - warn "# in ",dump($_); + warn "# ignored ",dump($_); } } sub diff_bits { my ($old, $new) = @_; + return unless $old && $new; + $old = reverse $old; # extra bits must be on the end + $new = reverse $new; $old =~ s/(...)/$1 /g; $new =~ s/(...)/$1 /g; my @o = split(/ /, $old); my @n = split(/ /, $new); - foreach my $i ( 0 .. $#o ) { + my $bsr_max_bit = $BOUNDARY_LENGTH / 3 - 1; + foreach my $i ( 0 .. $bsr_max_bit ) { if ( $o[$i] eq $n[$i] ) { $o[$i]='.'; } else { - my $pin = $bit2pin->{ 288 - ($i * 3) - 3 }->[0]; - $o[$i] = " $pin:" . $o[$i] . '>' . $n[$i]; + my $pin = $bit2pin->{ $i * 3 }->[0]; + $o[$i] = " $pin@" . ( $i * 3 ) . ":" . $o[$i] . '>' . $n[$i]; } } - my $diff = join('', @o); + my $diff = join('', @o[ 0 .. $bsr_max_bit ]); print "# diff_bits $diff\n"; } -print "[press enter]\n"; +print "> "; my $cmd = ; chomp $cmd; if ( $cmd =~ /(p|o)(\d+)=(\d+)/ ) { @@ -168,11 +316,11 @@ if ( $cmd =~ /(p|o)(\d+)=(\d+)/ ) { if ( $what eq 'p' && length($v) == 1 ) { my $pin = $p; - warn "# pin $pin = $v\n"; - my $io = $pin2io->[$pin]; my $bit = $io2bit->{$io}->[0]; + warn "# pin $pin = $v io=$io bit=$bit\n"; + $b = substr($old_bsr,0,$bit+1) # leave input as-is . ( $v eq 'Z' ? 1 : 0 ) # control @@ -181,7 +329,7 @@ if ( $cmd =~ /(p|o)(\d+)=(\d+)/ ) { ; - } elsif ( $what eq 'o' && $p < 288 ) { + } elsif ( $what eq 'o' && $p < $BOUNDARY_LENGTH ) { my $o = $p; #$b = substr($old_bsr,0,$o) . reverse $v . substr($old_bsr,$o+length($v)); $b = ( "0" x $o ) . reverse $v . ( "0" x ( length($old_bsr) - $o - length($v) ) ); @@ -193,20 +341,21 @@ warn "XXX",length($old_bsr), " == ",length($b); $b = reverse $b; - diff_bits( $BSR, $b ), $/; + diff_bits( $BSR, $b ); -# print $sock "irscan x300.tap 0x55\n"; # SAMPLE/PRELOAD - print $sock "drscan x300.tap 288 0x", bin2hex($b), "\n"; - print $sock "irscan x300.tap 0x00\n"; # EXTEST -# print $sock "drscan x300.tap 288 0x", bin2hex($b), "\n"; +# print $sock "irscan $tap $opcode->{SAMPLE}\n"; # SAMPLE/PRELOAD + print $sock "drscan $tap $BOUNDARY_LENGTH 0x", bin2hex($b), "\n"; + print $sock "irscan $tap $opcode->{EXTEST}\n"; # EXTEST +# print $sock "drscan $tap $BOUNDARY_LENGTH 0x", bin2hex($b), "\n"; } elsif ( $cmd =~ m/\?/ ) { $last_bits = ''; - print $sock "irscan x300.tap 0x55\n"; # SAMPLE/PRELOAD - print $sock "drscan x300.tap 288 0\n"; + print $sock "irscan $tap $opcode->{SAMPLE}\n"; # SAMPLE/PRELOAD + print $sock "drscan $tap $BOUNDARY_LENGTH 0\n"; } else { - print $sock "irscan x300.tap 0x55\n"; # SAMPLE/PRELOAD - print $sock "drscan x300.tap 288 0\n"; + gpio::cmd( $cmd ) if $have_gpio; + print $sock "irscan $tap $opcode->{SAMPLE}\n"; # SAMPLE/PRELOAD + print $sock "drscan $tap $BOUNDARY_LENGTH 0\n"; }