1#!/usr/bin/perl
2# -*- perl -*-
3#
4# Toshiba MeP Media Engine Relocation Generator
5# Copyright (C) 2001, 2007 Free Software Foundation, Inc.
6# This file is part of BFD.
7# Originally written by DJ Delorie <dj@redhat.com>
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
22
23
24# Usage: Run this anywhere inside your source tree.  It will read
25# include/elf/mep.h and scan the comments therein.  It will renumber
26# the relocs to be sequential (this is needed so that bfd/elf32-mep.h
27# works) if needed.  It will then update the reloc list in bfd/reloc.c
28# and the howto, mapping, and apply routines in bfd/elf32-mep.c.  You
29# can then regenerate bfd-in2.h and check everything in.
30
31# FIXME: After the relocation list is finalized, change this to
32# *verify* the reloc list, rather than resequence it.
33
34while (! -f "include/elf/mep.h" && ! -f "bfd/reloc.c") {
35    chdir "..";
36    $pwd = `pwd`;
37    if ($pwd !~ m@/.*/@) {
38	print STDERR "Cannot find include/elf/mep.h or bfd/reloc.h\n";
39	exit 1;
40    }
41}
42$pwd = `pwd`;
43print "srctop is $pwd";
44
45printf "Reading include/elf/mep.h ...\n";
46open(MEPH, "include/elf/mep.h");
47open(MEPHO, "> include/elf/mep.h.new") || die("mep.h.new create: $!");
48$val = 0;
49while (<MEPH>) {
50    if (($pre,$rel,$rest) = /(.*RELOC_NUMBER \()([^,]+), *\d+(.*)/) {
51	$rest =~ s/[\r\n]+$//;
52	print (MEPHO "$pre$rel, $val$rest\n") || die("mep.h.new write: $!");
53	$val ++;
54	$rel =~ s/R_MEP_//;
55	push(@relocs, $rel);
56
57	$rest =~ s@.*/\* @@;
58	($pattern, $sign, $attrs) = $rest =~ m@(.*) ([US]) (.*)\*/@;
59	$pattern =~ s/ //g;
60	push(@pattern, $pattern);
61	push(@sign, $sign);
62	push(@attrs, $attrs);
63
64	printf "%4d $rel p=`$pattern' s=`$sign' a=`$attrs'\n", $#pattern;
65
66    } else {
67	print(MEPHO) || die("mep.h.new write: $!");
68    }
69}
70close(MEPH);
71close(MEPHO) || die("mep.h.new close: $!");
72
73&swapfile("include/elf/mep.h");
74
75redo_file ("bfd/reloc.c",
76	   "",
77	   "ENUMDOC\n  Toshiba Media Processor Relocations.\n\nCOMMENT\n",
78	   "ENUM\n  BFD_RELOC_MEP_%s\n",
79	   "");
80
81$autogen = "    /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h.  */\n";
82
83redo_file ("bfd/elf32-mep.c",
84	   "MEPRELOC:HOWTO",
85	   $autogen,
86	   "MEPRELOC:END",
87	   "",
88	   "&emit_howto();",
89	   "MEPRELOC:MAP",
90	   $autogen,
91	   "MEPRELOC:END",
92	   "",
93	   "    MAP(%s);\n",
94	   "MEPRELOC:APPLY",
95	   $autogen,
96	   "MEPRELOC:END",
97	   "",
98	   "&emit_apply();",
99	   );
100
101sub mask2shifts {
102    my ($mask) = @_;
103    my ($bits, $left, $right, $ci, $c, $cv);
104    $bits = 0;
105    $left = 0;
106    $right = 32;
107    for ($ci=0; $ci<length($mask); $ci++) {
108	$c = substr($mask, $ci, 1);
109	$left++;
110	next if $c eq '-';
111	$left = 0;
112	$cv = ord($c) - ord('0');
113	$cv -= ord('a') - ord('9') - 1 if $cv > 9;
114	$right = $cv unless $right < $cv;
115	$bits = $cv+1 unless $bits > $cv+1;
116    }
117    $mask =~ tr/-/1/c;
118    $mask =~ tr/-/0/;
119    ($rmask = $mask) =~ tr/01/10/;
120    $mask = unpack("H*", pack("B*", $mask));
121    $rmask = unpack("H*", pack("B*", $rmask));
122    return ($bits, $left, $right, $mask, $rmask);
123}
124
125sub emit_howto {
126    for ($i=2; $i<=$#relocs; $i++) {
127	$mask = $pattern[$i];
128
129	if (length($mask) == 8)     { $bytesize = 0; }
130	elsif (length($mask) == 16) { $bytesize = 1; }
131	elsif (length($mask) == 32) { $bytesize = 2; }
132
133	($bits, $left, $right, $mask) = mask2shifts ($mask);
134	$bits[$i] = $bits;
135	$pcrel = 0;
136	$pcrel = 1 if $attrs[$i] =~ /pc-rel/i;
137	$overflow = $sign[$i];
138	$overflow = 'N' if $attrs[$i] =~ /no-overflow/;
139
140	$c = "$relocs[$i],";
141	printf(NEW "  MEPREL (R_MEP_%-10s%d,%3d,%2d,%2d,%2d,%2s, 0x%s),\n",
142	       $c, $bytesize, $bits, $left, $right, $pcrel, $overflow, $mask);
143    }
144}
145
146sub emit_apply {
147    for ($i=2; $i<=$#relocs; $i++) {
148	$v = "u";
149	$v = "s" if $sign[$i] =~ /S/;
150	if (length($pattern[$i]) == 8) {
151	    $e = ''; # no endian swap for bytes
152	} elsif ($pattern[$i] =~ /-/ || length($pattern[$i]) == 16) {
153	    $e = '^e2'; # endian swap - 2byte words only
154	} else {
155	    $e = '^e4' # endian swap for data
156	}
157	print NEW "    case R_MEP_$relocs[$i]: /* $pattern[$i] */\n";
158	if ($attrs[$i] =~ /tp-rel/i) {
159	    print NEW "      $v -= mep_tpoff_base(rel->r_offset);\n";
160	}
161	if ($attrs[$i] =~ /gp-rel/i) {
162	    print NEW "      $v -= mep_sdaoff_base(rel->r_offset);\n";
163	}
164	if ($attrs[$i] !~ /no-overflow/ && $bits[$i] < 32) {
165	    if ($v eq "u") {
166		$max = (1 << $bits[$i]) - 1;
167		print NEW "      if (u > $max) r = bfd_reloc_overflow;\n";
168	    } else {
169		$min = -(1 << ($bits[$i]-1));
170		$max = (1 << ($bits[$i]-1)) - 1;
171		print NEW "      if ($min > s || s > $max) r = bfd_reloc_overflow;\n";
172	    }
173	}
174	for ($b=0; $b<length($pattern[$i]); $b += 8) {
175	    $mask = substr($pattern[$i], $b, 8);
176	    ($bits, $left, $right, $mask, $rmask) = mask2shifts ($mask);
177	    if ($left > $right) { $left -= $right; $right = 0; }
178	    else { $right -= $left; $left = 0; }
179
180	    if ($mask ne "00") {
181		$bb = $b / 8;
182		print NEW "      byte[$bb$e] = ";
183		print NEW "(byte[$bb$e] & 0x$rmask) | " if $rmask ne "00";
184		if ($left) {
185		    print NEW "(($v << $left) & 0x$mask)";
186		} elsif ($right) {
187		    print NEW "(($v >> $right) & 0x$mask)";
188		} else {
189		    print NEW "($v & 0x$mask)";
190		}
191		print NEW ";\n";
192	    }
193	}
194	print NEW "      break;\n";
195    }
196}
197
198
199#-----------------------------------------------------------------------------
200
201sub redo_file {
202    my ($file, @control) = @_;
203    open(OLD, $file);
204    open(NEW, "> $file.new") || die("$file.new create: $!");
205
206    print "Scanning file $file ...\n";
207
208    while (1) {
209	$start = shift @control;
210	$prefix = shift @control;
211	$end = shift @control;
212	$suffix = shift @control;
213	$pattern = shift @control;
214
215	if (!$start) {
216	    print NEW while <OLD>;
217	    last;
218	}
219
220	print "  looking for $start\n";
221	while (<OLD>) {
222	    print NEW;
223	    last if /\Q$start\E/;
224	}
225	print "can't find $start\n" unless $_;
226	last unless $_;
227
228	print NEW $prefix;
229	if ($pattern =~ /^\&/) {
230	    eval $pattern;
231	    die("$pattern: $@") if $@;
232	} else {
233	    for $i (2..$#relocs) {
234		printf (NEW "$pattern", $relocs[$i]) || die("$file.new write: $!");
235		$pattern =~ s/^ENUM\n/ENUMX\n/;
236	    }
237	}
238	print NEW $suffix;
239	while (<OLD>) {
240	    last if /\Q$end\E/;
241	}
242	print NEW;
243    }
244
245    close(OLD);
246    close(NEW) || die("$file.new close: $!");
247    &swapfile($file);
248}
249
250#-----------------------------------------------------------------------------
251
252sub swapfile {
253    my ($f) = @_;
254    if ( ! -f "$f.save") {
255	system "cp $f $f.save";
256    }
257    open(ORIG, $f);
258    open(NEW, "$f.new");
259    while (<ORIG>) {
260	$n = <NEW>;
261	if ($n ne $_) {
262	    close(ORIG);
263	    close(NEW);
264	    print "  Updating $f\n";
265	    rename "$f", "$f.old";
266	    rename "$f.new", "$f";
267	    return;
268	}
269    }
270    close(ORIG);
271    close(NEW);
272    print "  No change to $f\n";
273    unlink "$f.new";
274}
275