summaryrefslogtreecommitdiff
path: root/tools/st7_dtc_as
diff options
context:
space:
mode:
Diffstat (limited to 'tools/st7_dtc_as')
-rwxr-xr-xtools/st7_dtc_as/st7_dtc_as2
-rw-r--r--tools/st7_dtc_as/st7_dtc_as.pl709
2 files changed, 711 insertions, 0 deletions
diff --git a/tools/st7_dtc_as/st7_dtc_as b/tools/st7_dtc_as/st7_dtc_as
new file mode 100755
index 00000000..62f7a480
--- /dev/null
+++ b/tools/st7_dtc_as/st7_dtc_as
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec perl "$0.pl" $*
diff --git a/tools/st7_dtc_as/st7_dtc_as.pl b/tools/st7_dtc_as/st7_dtc_as.pl
new file mode 100644
index 00000000..7a293c3f
--- /dev/null
+++ b/tools/st7_dtc_as/st7_dtc_as.pl
@@ -0,0 +1,709 @@
+#!/bin/perl
+#***************************************************************************
+#* Copyright (C) 2008 Lou Deluxe *
+#* lou.openocd012@fixit.nospammail.net *
+#* *
+#* 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 2 of the License, or *
+#* (at your option) 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, write to the *
+#* Free Software Foundation, Inc., *
+#* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+#***************************************************************************
+
+# A rudimentary assembler for DTC code.
+# It is not robust, by any means, but it gets the job done.
+
+{package DTC_as;
+
+my($i); # for later loop to generate reverse lookup
+
+sub new {
+ my($self) = bless{};
+
+ $self->{'pagewidth'} = 60;
+ $self;
+}
+
+
+
+%status_bit_arg = (
+ 'STOP' => 0x01,
+ 'ERROR' => 0x02,
+);
+
+%cp_arg = (
+ 'A=>X' => 0x00,
+ 'A<X' => 0x01,
+ 'CARRY' => 0x02,
+ 'ALWAYS' => 0x03,
+ 'ADR_BUFFER0=>CMP0' => 0x04,
+ 'ADR_BUFFER0<CMP0' => 0x05,
+ 'ADR_BUFFER1=>CMP1' => 0x06,
+ 'ADR_BUFFER1<CMP1' => 0x07,
+);
+
+%shift_unit_arg = (
+ 'CARD' => 0x00,
+ 'MPEG' => 0x08,
+);
+
+%shift_pin_arg = (
+ 'PIN0=>IN' => 0x00,
+ 'PIN1=>IN' => 0x04,
+ 'OUT=>PIN0' => 0x01,
+ 'OUT=>PIN1' => 0x03,
+);
+
+@ld_arg = (
+ '<Y>',
+ 'X',
+ 'Y',
+ 'MASK',
+ 'ADR_BUFFER00',
+ 'ADR_BUFFER01',
+ 'ADR_BUFFER10',
+ 'ADR_BUFFER11',
+ 'CMP00',
+ 'CMP01',
+ 'CMP10',
+ 'CMP11',
+ 'DATA_FLASH',
+ 'CTRL_FCI',
+ 'CTRL_CARD',
+ 'CTRL_MPEG',
+ 'DR_PARALLEL',
+ 'DDR_PARALLEL',
+ 'OR_PARALLEL',
+ 'DR_CARD',
+ 'DDR_CARD',
+ 'OR_CARD',
+ 'SHIFT_CARD',
+ 'DR_MPEG',
+ 'DDR_MPEG',
+ 'OR_MPEG',
+ 'SHIFT_MPEG',
+ 'DATA_BUFFER0',
+ 'DATA_BUFFER1',
+ 'ECC_CRC',
+ 'TMP_ECC',
+ 'BUFFER_MNGT'
+);
+
+for($i = 0; $i < @ld_arg; $i++) {
+ $ld_arg{$ld_arg[$i]} = $i;
+}
+
+
+# ADDER8 / SUB8
+sub alu8 {
+ my($self) = shift;
+ my($operand, $i) = shift;
+
+ if(defined($ld_arg{$operand})) {
+ $i = $ld_arg{$operand};
+
+ if($i > 0x00 && $i < 0x04) {
+ return(($i - 0x01) << 3);
+ }
+ }
+
+ return undef;
+}
+
+# ADDER16 / SUB16
+sub alu16 {
+ my($self) = shift;
+ my($operand, $i) = shift;
+
+ $operand .= '0';
+
+ if(defined($ld_arg{$operand})) {
+ $i = $ld_arg{$operand};
+
+ if($i > 0x03 && $i < 0x0c) {
+ return(($i - 0x04) << 2);
+ }
+ }
+
+ return undef;
+}
+
+
+# BSET / BCLR
+sub bsetorclr {
+ my($self) = shift;
+ my($ret);
+
+ if(@_ < 1) {
+ return undef;
+ }
+ $ret = $_[0];
+
+ if(($ret < 0) || ($ret > 3)) {
+ return undef;
+ }
+
+ return $ret;
+}
+
+
+# Opcode lookup table
+%op = (
+ 'NOP' => [
+ 0x0,
+ ],
+ 'SEC' => [
+ 0x1,
+ ],
+ 'CLC' => [
+ 0x2,
+ ],
+ 'RET' => [
+ 0x3,
+ ],
+ 'STATUS' => [
+ 0x4,
+ sub {
+ my($self) = shift;
+ my($ret, $i);
+
+ for $i (@_) {
+ if(!defined($status_bit_arg{"\U$i"})) {
+ return undef;
+ }
+
+ $ret |= $status_bit_arg{"\U$i"};
+ }
+ if($ret < 1) {
+ return undef;
+ }
+
+ return $ret;
+ }
+ ],
+ 'CP' => [
+ 0x8,
+ sub {
+ my($self) = shift;
+ if((@_ != 1) || (!defined($cp_arg{"\U$_[0]"}))) {
+ return undef;
+ }
+ return($cp_arg{"\U$_[0]"});
+ }
+ ],
+ 'SHIFT' => [
+ 0x10,
+ sub {
+ my($self) = shift;
+ my($ret, $i);
+
+ if((@_ < 2) || (!defined($shift_unit_arg{"\U$_[0]"}))) {
+ return undef;
+ }
+ $ret = $shift_unit_arg{"\U$_[0]"};
+ shift;
+
+ for $i (@_) {
+ if(!defined($shift_pin_arg{"\U$i"})) {
+ return undef;
+ }
+
+ $ret |= $shift_pin_arg{"\U$i"};
+ }
+
+ return $ret;
+ }
+ ],
+ 'SUB8' => [
+ 0x24,
+ \&alu8
+ ],
+ 'ADDER8' => [
+ 0x25,
+ \&alu8
+ ],
+ 'SUB16' => [
+ 0x26,
+ \&alu16
+ ],
+ 'ADDER16' => [
+ 0x27,
+ \&alu16
+ ],
+ 'BCLR' => [
+ 0x28,
+ \&bsetorclr
+ ],
+ 'BSET' => [
+ 0x38,
+ \&bsetorclr
+ ],
+ 'REVERSE' => [
+ 0x30,
+ ],
+ 'XOR' => [
+ 0x31,
+ ],
+ 'AND' => [
+ 0x32,
+ ],
+ 'EXCHANGE' => [
+ 0x33,
+ ],
+ 'DECY' => [
+ 0x3c,
+ ],
+ 'INCY' => [
+ 0x3d,
+ ],
+ 'JP' => [
+ 0x40,
+ sub {
+ my($self) = shift;
+ my($i);
+
+ if(@_ != 1) {
+ return undef;
+ }
+ $i = $_[0];
+ if(!defined($self->{'label'}{$i})) {
+ $i =~ s/^://o;
+ if(!defined($self->{'label'}{$i})) {
+ # not a defined label
+ undef $i;
+ }
+ }
+
+ if(defined($i)) {
+ $i = $self->{'label'}{$i} - $self->{'pc'};
+ } else {
+ $i = $_[0];
+ }
+
+ if($i =~ m/^([+-]?\d+)$/) {
+ $i = 0 + $1;
+ if(($i > 31) || ($i < -31)) {
+ warn "relative jump ($i) out of range";
+ return undef;
+ }
+ if($i < 0) {
+ return(0x20 - $1);
+ } else {
+ return(0x00 + $1);
+ }
+ }
+
+ return undef;
+ }
+ ],
+ 'BRANCH' => [
+ 0x60,
+ ],
+ 'LD' => [
+ 0x80,
+ sub {
+ my($self) = shift;
+ my($i);
+
+# print STDERR join(", ", LD, @_), "\n";
+
+ if(@_ == 1) {
+ $_[1] = 'A';
+ }
+ if(@_ != 2) {
+ return undef;
+ }
+
+
+ if($_[0] =~ m/^([ML])S[BN]$/o) {
+ # MSB/LSB aka MSN/LSN
+ if($1 eq 'L') {
+ $_[0] = 'A.L';
+ } else {
+ $_[0] = 'A.H';
+ }
+ }
+ if($_[0] =~ m/^A\.([LH])$/o) {
+ # A.L/A.H
+ my($islsb) = ($1 eq 'L') ? 1 : 0;
+ $i = $_[1];
+ if($i =~ s/^0x([0-9a-fA-F])$/hex($1)/e) {
+# print "$i looks hex\n";
+ } elsif($i =~ m/^\d+$/) {
+# print "$i looks decimal\n";
+ } elsif(defined($self->{'label'}{$i})) {
+# print "label match for $i ($self->{'label'}{$i})\n";
+ $i = $self->{'label'}{$i};
+# print "\$i=$i\n";
+# print "\$islsb=$islsb\n";
+ if($islsb) {
+ $i = ($i & 0xf);
+ } else {
+ $i = ($i >> 4) & 0xf;
+ }
+# print "\$i=$i\n";
+ } else {
+ print "no label match for $i\n";
+ return undef;
+ }
+ if(($i < 0) || ($i > 0xf)) {
+ return undef;
+ }
+ if($islsb) {
+ $i |= 0x10;
+ };
+ return(0x20 | $i);
+ } elsif($_[0] eq 'A') {
+ if(!defined($ld_arg{$_[1]})) {
+ return undef;
+ }
+ return(0x40 | $ld_arg{$_[1]});
+ } elsif($_[1] eq 'A') {
+ if(!defined($ld_arg{$_[0]})) {
+ return undef;
+ }
+ return(0x00 | $ld_arg{$_[0]});
+ }
+
+ return undef;
+ }
+ ],
+);
+
+$op{'JR'} = $op{'JP'};
+
+
+sub pass {
+ my($self, $ifh, $ofh, $passnum) = @_;
+
+ # passnum=0 for plain parsing pass to populate label values
+ # passnum=1 for actual pass to assemble
+
+ my($line, $oline, $opcd);
+
+ if($passnum == 0) {
+ delete($self->{'label'});
+ delete($self->{'binary'});
+ delete($self->{'ENTRY'});
+ delete($self->{'LUT'});
+ }
+
+ seek($ifh, 0, 0); # rewind
+ $self->{'pc'} = 0;
+ $self->{'line_number'} = 0;
+ while(defined($line = <$ifh>)) {
+ $self->{'line_number'}++;
+ $line =~ s/\s+$//so;
+ $oline = $line;
+ $line =~ s/;.*//o;
+ $line =~ s/^\s+//o;
+ @_ = split(/[\s,]+/, $line);
+
+ undef($opcd);
+
+ if(@_ > 0) {
+
+ if(
+ ($_[0] =~ s/^://o)
+ ||
+ ($_[0] =~ s/:$//o)
+ ) {
+ if($passnum == 0) {
+ if(defined($self->{'label'}{$_[0]})) {
+ die "label redefinition for \"$_[0]\" in line $self->{'line_number'}";
+ }
+ $self->{'label'}{$_[0]} = $self->{'pc'};
+ }
+ shift(@_);
+ }
+
+ if(@_ > 0) {
+ if($passnum == 1) {
+ if((@_ == 3) && ($_[1] eq '=')) {
+ # convert this = that to LD
+ $_[1] = $_[0];
+ $_[0] = 'LD';
+ }
+ elsif((@_ == 3) && ($_[1] eq '+=')) {
+ # convert this += that to ADDER8 or ADDER16
+ if($_[0] eq 'A') {
+ @_ = ('ADDER8', $_[2]);
+ }
+ elsif($_[2] eq 'X') {
+ @_ = ('ADDER16', $_[0]);
+ }
+ }
+ elsif((@_ == 3) && ($_[1] eq '-=')) {
+ # convert this -= that to ADDER8 or ADDER16
+ if($_[0] eq 'A') {
+ @_ = ('SUB8', $_[2]);
+ }
+ elsif($_[2] eq 'X') {
+ @_ = ('SUB16', $_[0]);
+ }
+ }
+ elsif((@_ == 1) && ($_[0] =~ m/^(B((SET)|(CLR)))([1-4])$/oi)) {
+ # convert BSETn or BCLRn to BSET n-1 or BCLR n-1
+ $_[0] = $1;
+ $_[1] = $5 - 1;
+ }
+
+ $op = "\U$_[0]";
+ if(!defined($op{$op})) {
+ die "unknown instruction: $op in line $self->{'line_number'}";
+ }
+ shift(@_);
+
+ $op = $op{$op};
+ $sub = $op->[1];
+ if(defined($sub)) {
+ $opcd = &$sub($self, @_);
+ } else {
+ $opcd = 0;
+ }
+
+ if(!defined($opcd)) {
+ die "bad argument(s) in line $self->{'line_number'}";
+ }
+
+ $opcd |= $op->[0];
+ }
+
+ $self->{'pc'}++;
+ }
+
+ } else {
+ if($passnum == 0) {
+ if($oline =~ m/^;LUT; (.*)/o) {
+ my($entry, $label) = split(/\s+/, $1);
+ $entry =~ s/^0x//o;
+ $self->{'LUT'}[hex($entry)] = $label;
+ }
+ if($oline =~ m/^;ENTRY; (.*)/o) {
+ my($id, $label) = split(/\s+/, $1);
+ $self->{'ENTRY'}{$id} = $label;
+ }
+ }
+ }
+
+ if($passnum == 1) {
+ if(defined($opcd)) {
+ $self->{'binary'} .= chr($opcd);
+
+ printf $ofh ("/* 0x%02x */ 0x%02x%s /* %-*s */\n",
+ $self->{'pc'} - 1,
+ $opcd,
+ (
+ (
+ ($self->{'last pc'} < 0xff)
+ ||
+ ($self->{'last pc'} != $self->{'pc'} - 1)
+ ) ?
+ ','
+ :
+ ''
+ ),
+ $self->{'pagewidth'} - 23,
+ $oline
+ );
+ } else {
+ if($oline ne '') {
+ print $ofh " /* $oline */\n";
+ } else {
+ print $ofh "\n";
+ }
+ }
+ }
+ }
+
+ if($passnum == 0) {
+ $self->{'last pc'} = $self->{'pc'} - 1;
+ }
+
+ if($passnum == 1) {
+ while($self->{'pc'} < 0xff) {
+ printf $ofh ("/* 0x%02x */ 0,\n",
+ $self->{'pc'}
+ );
+ $self->{'pc'}++;
+ }
+ if($self->{'pc'} < 0x100) {
+ printf $ofh ("/* 0x%02x */ 0\n",
+ $self->{'pc'}
+ );
+ $self->{'pc'}++;
+ }
+ }
+}
+
+} # package DTC_as
+
+
+use Getopt::Std;
+
+%opt = (
+ 't' => 'unsigned char',
+);
+
+# -t type of arrays (defaults to unsigned char)
+# -l lookup table array name (no table generated if not provided)
+# -d DTC code array name (naked elements if not provided)
+# -i input filename (trailing argument if not provided)
+# -o output filename (stdout if not provided)
+getopts('l:d:i:o:t:b', \%opt);
+
+if(defined($opt{'i'})) {
+ $infile = $opt{'i'};
+} else {
+ $infile = shift;
+}
+
+if(!open(IN, '<', $infile)) {
+ die "$infile: $!";
+}
+
+
+if($opt{'b'}) {
+ if(!defined($opt{'o'})) {
+ die "binary format requires -o";
+ }
+ if(!open(OUT, '>&', *STDOUT)) {
+ die "dup stdout: $!";
+ }
+ open(STDOUT, '>&', *STDERR);
+} else {
+ if(defined($opt{'o'})) {
+ if(!open(OUT, '>', $opt{'o'})) {
+ die "$opt{'o'}: $!";
+ }
+ } else {
+ if(!open(OUT, '>&', *STDOUT)) {
+ die "dup stdout: $!";
+ }
+ open(STDOUT, '>&', *STDERR);
+ }
+}
+
+
+$as = new DTC_as;
+
+$as->pass(*IN, *OUT, 0);
+
+if(defined($opt{'d'})) {
+ print OUT "$opt{'t'} $opt{'d'}", "[0x100] = {\n";
+}
+$as->pass(*IN, *OUT, 1);
+if(defined($opt{'d'})) {
+ print OUT "};\n\n";
+}
+
+close(IN);
+
+if(defined($opt{'l'})) {
+ print OUT "$opt{'t'} $opt{'l'}", "[0x40] = {\n";
+# $end = @{$as->{'LUT'}};
+# if($end > 0x100) {
+# $end = 0x100;
+# }
+ for($i = 0xc0; $i < 0x100; $i++) {
+ $label = $as->{'LUT'}[$i];
+ if(defined($label)) {
+ if(defined($as->{'label'}{$label})) {
+ printf OUT ("/* 0x%02x */ 0x%02x%s /* %s */\n",
+ $i,
+ $as->{'label'}{$label},
+ (($i < 0xff) ? ',' : ''),
+ $label
+ );
+ } else {
+ die "label $label has not been defined";
+ }
+ } else {
+ printf OUT ("/* 0x%02x */ 0%s\n",
+ $i,
+ (($i < 0xff) ? ',' : ''),
+ );
+ }
+ }
+ print OUT "};\n\n";
+}
+
+
+close(OUT);
+
+sub DTCLOAD_COMMENT { 0; }
+sub DTCLOAD_ENTRY { 1; }
+sub DTCLOAD_LOAD { 2; }
+sub DTCLOAD_RUN { 3; }
+sub DTCLOAD_LUT_START { 4; }
+sub DTCLOAD_LUT { 5; }
+
+
+if($opt{'b'}) {
+ open(OUT, ">", $opt{'o'}) || die "$opt{'o'}: $!";
+ syswrite(OUT, pack('CC', DTCLOAD_LUT_COMMENT, 3 - 1) . 'DTC');
+
+ $ref = $as->{'LUT'};
+ if(@$ref > 0) {
+ for($start = 0; $start < @$ref && !defined($ref->[$start]); $start++) {}
+ for($end = 0xff; $end >= $start && !defined($ref->[$end]); $end--) {}
+ undef($lut);
+ for($i = $start; $i <= $end; $i++) {
+ if(!defined($ref->[$i])) {
+ $lut .= "\0";
+ next;
+ }
+ $label = $ref->[$i];
+ if(defined($as->{'label'}{$label})) {
+ $label = $as->{'label'}{$label};
+# printf("adding LUT entry 0x%02x\n", $label);
+ $lut .= chr($label);
+ } else {
+ die "label $label has not been defined";
+ }
+ }
+ if(length($lut) > 0) {
+ syswrite(OUT, pack('CCC', DTCLOAD_LUT_START, 1 - 1, $start));
+ syswrite(OUT, pack('CC', DTCLOAD_LUT, length($lut) - 1) . $lut);
+ }
+ }
+
+ while(($key, $label) = each(%{$as->{'ENTRY'}})) {
+# print "$key = $label\n";
+ if(defined($as->{'label'}{$label})) {
+ $label = $as->{'label'}{$label};
+# print "key=$key\n";
+# print "label=$label\n";
+ syswrite(OUT, pack('CCC', DTCLOAD_ENTRY, length($key), $label) . $key);
+ } else {
+ die "label $label has not been defined";
+ }
+ }
+
+ if(length($as->{'binary'})) {
+# printf("DTC code size: 0x%x\n", length($as->{'binary'}));
+ syswrite(OUT, pack('CC',
+ DTCLOAD_LOAD ,
+ length($as->{'binary'}) - 1
+ ) . $as->{'binary'});
+
+ if(%{$as->{'ENTRY'}} < 1) {
+ syswrite(OUT, pack('CCC', DTCLOAD_RUN, 1 - 1, 0x00));
+ }
+ }
+
+ close(OUT);
+}
+
+
+0;
+