From 9355d4d2046000ae6b23814557aebe43f335d3d5 Mon Sep 17 00:00:00 2001 From: Tazmaniac Date: Mon, 7 Nov 2022 21:21:26 +0100 Subject: [PATCH] Add files via upload --- spt2hex.pl | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 spt2hex.pl diff --git a/spt2hex.pl b/spt2hex.pl new file mode 100644 index 0000000..65289c3 --- /dev/null +++ b/spt2hex.pl @@ -0,0 +1,259 @@ +#!/usr/bin/perl +# +# spt to hex converter +# This programm extract firmware from hex2spt gerenated Cypress EZ-USB +# spt script file. +# Copyright (C) 2013 Emmanuel Fusté +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# +# spt is a generic USB commands scripting format, but as we know how hex files +# are converted to spt by standard cypress tools or procedures to get back +# an hex file from a hex-converted-to-spt file. +# +# +# each USB transaction is described by a record +# record format: 32 byte header in little endian + data +# +# uint Signature == 0x54505343 or byte[4] == 'CSPT' //4 +# uint RecordSize == header size + data size == 32 + data size //8 +# ushort HeaderSize == 32 == 0x0020//10 +# byte Tag == 0 == 0x00//11 +# +# Device on wich the script will be played : selected at runtime, +# 0x0 in the script: +# byte ConfigNum == 0 == 0x00 //12 +# byte IntfcNum == 0 == 0x00 //13 +# byte AltIntfc == 0 == 0x00 //14 +# byte EndPtAddr == 0 = 0x00 //15 +# +# byte bReqType == 0x40 in our case (TGT_DEVICE|REQ_VENDOR|DIR_TO_DEVICE) //16 +# byte CtlReqCode //17 +# byte reserved0 is generaly 0x20//18 +# +# ushort wValue //20 +# ushort wIndex //22 +# byte reserved1 ~ 0x9F //23 +# byte reserved2 ~ 0x00 //24 + +# uint Timeout ~ 0x00000005 //28 +# uint DataLen; //32 +# +# hex to spt converter do the following: +# 1 CPU put in reset mode (A0 request to write 0x01 at 0xE600 for FX2LP) +# 2 upload of vendor_ax firmware with A0 request +# 3 CPU put in run mode (A0 request to write 0x00 to addresss 0xE600 for FX2LP) +# 4 upload of external RAM code with A3 vendor request implemented by vendor_ax +# 5 CPU put in reset mode +# 6 upload of RAM code with A0 vendor request (all code under 16k on FX2LP) +# 7 CPU put in run mode +# +# spt generated by cypress tools upload inconditionnaly vendor_ax firmware. +# If there is nothing to upload to external ram, step 4 is skipped. +# +# If manualy recorded, step 2,3,4,5 could be omitted if no code need to be +# uploaded to external ram. +# +# all contiguous hex record data are packed in one usb transaction and re-split +# in two if the packed result in payload > 4k +# Cypress tools generate hex file with 16 bytes of data max per record. +# Decoded spt data payload will be re-split in 16 bytes hex record. +# +use strict; +use warnings; +use Getopt::Long; +use Pod::Usage; + +my $version = "1.0"; +my $verbose = ''; +my $help = ''; + +GetOptions("help|h" => \$help, 'verbose|v' => \$verbose); + +my $sptfile = $ARGV[0]; + +if ((!$sptfile ) || $help) { pod2usage(2) }; + +open my $fh, '<', $sptfile or die "Couldn't open file $sptfile: $!\n"; + +binmode $fh; + +my %allrecords; +my @reset; +my @run; + +my $index=0; + +while ( read $fh, my $header, 32 ) { +# read $fh, my $header, 32 ; + + my ($magic, $rsize, $hsize, $tag, $confnum, $intfcnum, $altintfc, + $endptaddr, $breqtype, $ctlreqcode, $res0, $wvalue, $windex, + $res1, $res2, $timeout, $datalen) + = unpack("a4VvCCCCCCCCvvCCVV" , $header); + + if ($verbose) { + printf( "magic : %s\n", $magic); + printf( "record size : 0x%08x\n", $rsize); + printf( "header size : 0x%04x\n", $hsize); + printf( "tag : 0x%02x\n", $tag); + printf( "confnum : 0x%02x\n", $confnum); + printf( "intfcnum : 0x%02x\n", $intfcnum); + printf( "altintfc : 0x%02x\n", $altintfc); + printf( "endptaddr : 0x%02x\n", $endptaddr); + printf( "breqtype : 0x%02x\n", $breqtype); + printf( "ctlreqcode : 0x%02x\n", $ctlreqcode); + printf( "res0 : 0x%02x\n", $res0); + printf( "wvalue : 0x%04x\n", $wvalue); + printf( "windex : 0x%04x\n", $windex); + printf( "res1 : 0x%02x\n", $res1); + printf( "res2 : 0x%02x\n", $res2); + printf( "timeout : 0x%08x\n", $timeout); + printf( "datalen : 0x%08x\n", $datalen); + print "\n"; + } + + $index++; + + # sanity checks + if ( $magic ne "CSPT" ) { die "Bad header magic in record header No $index \n" }; + if ( $hsize != 32 ) { die "Bad header size in record header No $index \n" }; + if ( $rsize != (32 + $datalen) ) { die "bad record size in record header No $index \n" }; + if ( $breqtype != 0x40 ) { die "Record No $index not from a hex2spt file : bad breqtype\n" }; + if ( $windex != 0x0000 ) { die "Record No $index not from a hex2spt file : windex not null\n"}; + + # read the data payload + read $fh, my $rawdata, $datalen or die "Corrupted spt file\n"; + my $data = unpack("C", $rawdata); + + # is it reset or run command ? + if (($ctlreqcode == 0xa0) && ($wvalue == 0xe600)) { + if (($datalen == 0x00000001) && ($data == 0x01)) { + push @reset, $index; + next; + } + if (($datalen == 0x00000001) && ($data == 0x00)) { + push @run, $index; + next; + } + die "Invalid CPUCS value or length in record $index\n"; + } + if ($ctlreqcode == 0xa3) { + die "External ram recovery from spt not implemented\n"; + } + + $allrecords{$index}{ 'ctlreqcode' } = $ctlreqcode; + $allrecords{$index}{ 'wvalue' } = $wvalue; + $allrecords{$index}{ 'datalen' } = $datalen; + $allrecords{$index}{ 'data' } = $rawdata; + +} + +my $nbrun = @run; +my $nbreset = @reset; + +print "number of records : $index\n"; +print "number of reset : $nbreset at record No: @reset\n"; +print "number of run : $nbrun at record No: @run\n"; + +if (($nbreset != $nbrun) || ($nbreset > 2) || ($nbrun > 2) + || ($nbreset == 0) || ($nbrun == 0)) { + die "Not a hex2spt spt file\n"; +} + +sub writehex { + my ( $start, $end, $filename) = @_; + my $current; + open my $outfh, '>', $filename or die "Couldn't open file $filename: $!\n"; + + for ($current = $start; $current <= $end; $current++) { + my $worklen = $allrecords{$current}{'datalen'}; + my $offset = $allrecords{$current}{'wvalue'}; + my @data = unpack("C*", $allrecords{$current}{'data'}); + my $dataoffset = 0; + + while ($worklen > 0) { + my $writelen; + my $i; + + if ($worklen > 16) { + $writelen = 16; + } else { + $writelen = $worklen; + } + + printf($outfh ":%02X%04X00", $writelen, $offset); + my $checksum = $writelen; + $checksum += $offset & 0x000000FF; + $checksum += ($offset & 0x0000FF00) / 256; + for ($i = $dataoffset; $i < ($dataoffset + $writelen); $i++) { + printf($outfh "%02X", $data[$i]); + $checksum += $data[$i]; + } + $checksum &= 0x000000FF; + $checksum = 0x100 - $checksum; + $checksum &= 0x000000FF; + printf($outfh "%02X", $checksum); + printf($outfh "\n"); + $worklen -= 16; + $offset += 16; + $dataoffset += 16; + } + } + + printf($outfh ":00000001FF\n"); + close $outfh; +} + +my $beginfirstfw; +my $endfirstfw; +my @outfile; +$beginfirstfw = $reset[0] + 1; +$endfirstfw = $run[0] - 1; +@outfile = split(".spt", $sptfile); + +if (($nbreset == 2) && ($nbrun == 2)) { + my $beginsecondfw; + my $endsecondfw; + $beginsecondfw = $reset[1] + 1; + $endsecondfw = $run[1] - 1; + print "vend_ax firmware located in record $beginfirstfw to record $endfirstfw \n"; + writehex($beginfirstfw, $endfirstfw, "vend_ax.hex"); + print "original firmware located in record $beginsecondfw to record $endsecondfw \n"; + writehex($beginsecondfw, $endsecondfw, $outfile[0] . ".hex"); + +} else { + print "original firmware located in record $beginfirstfw to record $endfirstfw \n"; + writehex($beginfirstfw, $endfirstfw, $outfile[0] . ".hex"); +} + +close $fh; + +__END__ + +=head1 NAME + +spt2hex - Cypress EZ-USB spt script to hex file converter + +=head1 SYNOPSIS + +spt2hex [options] file + +Options: + + -verbose|-v show decoded spt records + -help|-h brief help message + +=cut