* as/link/mcs51/lkihx.c (hexRecord): bugfix do not insert extended address
[fw/sdcc] / as / link / mcs51 / lkihx.c
1 /* lkihx.c
2
3    Copyright (C) 1989-1995 Alan R. Baldwin
4    721 Berkeley St., Kent, Ohio 44240
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include "aslink.h"
22
23 /*)Module   lkihx.c
24  *
25  *  The module lkihx.c contains the function to
26  *  output the relocated object code in the
27  *  Intel Hex format.
28  *
29  *  lkihx.c contains the following functions:
30  *      VOID    hexRecord(addr, rtvalIndex)
31  *      VOID    ihx(i)
32  *      VOID    ihxExtendedLinearAddress(a)
33  *
34  *  local variables: hexPageOverrun, lastHexAddr
35  */
36
37 /*Intel Hex Format
38  *      Record Mark Field    -  This  field  signifies  the  start  of a
39  *                              record, and consists of an  ascii  colon
40  *                              (:).
41  *
42  *      Record Length Field  -  This   field   consists   of  two  ascii
43  *                              characters which indicate the number  of
44  *                              data   bytes   in   this   record.   The
45  *                              characters are the result of  converting
46  *                              the  number  of  bytes  in binary to two
47  *                              ascii characters, high digit first.   An
48  *                              End  of  File  record contains two ascii
49  *                              zeros in this field.
50  *
51  *      Load Address Field   -  This  field  consists  of the four ascii
52  *                              characters which result from  converting
53  *                              the  the  binary value of the address in
54  *                              which to begin loading this record.  The
55  *                              order is as follows:
56  *
57  *                                  High digit of high byte of address.
58  *                                  Low digit of high byte of address.
59  *                                  High digit of low byte of address.
60  *                                  Low digit of low byte of address.
61  *
62  *                              In an End of File record this field con-
63  *                              sists of either four ascii zeros or  the
64  *                              program  entry  address.   Currently the
65  *                              entry address option is not supported.
66  *
67  *      Record Type Field    -  This  field  identifies the record type,
68  *                              which is either 0 for data records or  1
69  *                              for  an End of File record.  It consists
70  *                              of two ascii characters, with  the  high
71  *                              digit of the record type first, followed
72  *                              by the low digit of the record type.
73  *
74  *      Data Field           -  This  field consists of the actual data,
75  *                              converted to two ascii characters,  high
76  *                              digit first.  There are no data bytes in
77  *                              the End of File record.
78  *
79  *      Checksum Field       -  The  checksum  field is the 8 bit binary
80  *                              sum of the record length field, the load
81  *                              address  field,  the  record type field,
82  *                              and the data field.  This  sum  is  then
83  *                              negated  (2's  complement) and converted
84  *                              to  two  ascii  characters,  high  digit
85  *                              first.
86  */
87
88 /* Static variable which holds the count of hex page overruns
89  * (crossings of the 64kB boundary). Cleared at explicit extended
90  * address output.
91  */
92 static int hexPageOverrun = 0;
93
94 /* Global which holds the last (16 bit) address of hex record.
95  * Cleared at begin of new area or when the extended address is output.
96  */
97 unsigned int lastHexAddr = 0;
98
99
100 /*)Function hexRecord(addr, rtvalIndex)
101  *
102  *      unsigned addr       starting address of hex record
103  *      int rtvalIndex      starting index into the rtval[] array
104  *
105  *  The function hexRecord() outputs the relocated data
106  *  in the standard Intel Hex format (with inserting
107  *  the extended address record if necessary).
108  *
109  *  local variables:
110  *      Addr_T  chksum      byte checksum
111  *      int     i           index for loops
112  *      int     overrun     temporary storage for hexPageOverrun
113  *      int     bytes       counter for bytes written
114  *
115  *  global variables:
116  *      FILE *  ofp         output file handle
117  *      int     rtcnt       count of data words
118  *      int     rtflg[]     output the data flag
119  *      Addr_T  rtval[]     relocated data
120  *
121  *  functions called:
122  *      int     fprintf()           c_library
123  *      ihxExtendedLinearAddress()  lkihx.c
124  *      hexRecord()                 lkihx.c     (recursion)
125  *
126  *  side effects:
127  *      hexPageOverrun is eventually incremented,
128  *      lastHexAddr is updated
129  */
130
131 VOID
132 hexRecord(unsigned addr, int rtvalIndex)
133 {
134     Addr_T chksum;
135     int i, overrun, bytes;
136
137     for (i = rtvalIndex, chksum = 0; i < rtcnt; i++) {
138         if (rtflg[i]) {
139             if (addr + ++chksum > 0xffff)
140                 break;
141         }
142     }
143     if (chksum == 0)
144         return;         // nothing to output
145
146     /* Is this record in the same bank as previous? */
147     if ( ((lastHexAddr>>16) != (addr>>16)) && (rflag) ) {
148         overrun = hexPageOverrun + 1;
149         ihxExtendedLinearAddress(lastExtendedAddress + overrun);
150         hexPageOverrun = overrun;
151         hexRecord(addr, rtvalIndex);
152         return;
153     }
154
155     lastHexAddr = addr;
156     fprintf(ofp, ":%02X%04X00", chksum, addr);
157     chksum += (addr >> 8) + (addr & 0xff);
158     for (i = rtvalIndex, bytes = 0; i < rtcnt; i++) {
159         if (rtflg[i]) {
160             fprintf(ofp, "%02X", rtval[i]);
161             chksum += rtval[i];
162             if (addr + ++bytes > 0xffff) {
163                 if (rflag) {
164                     fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
165                     overrun = hexPageOverrun + 1;
166                     ihxExtendedLinearAddress(lastExtendedAddress + overrun);
167                     hexPageOverrun = overrun;
168                     hexRecord(0, i + 1);
169                     return;
170                 } else {
171                     fprintf(stderr,
172                         "warning: extended linear address encountered; "
173                         "you probably want the -r flag.\n");
174                 }
175             }
176         }
177     }
178     fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
179 }
180
181 /*)Function ihx(i)
182  *
183  *      int     i           0 - process data
184  *                          1 - end of data
185  *
186  *  The function ihx() calls the hexRecord() function for processing data
187  *  or writes the End of Data record to the file defined by ofp.
188  *
189  *  local variables:
190  *      Addr_T  n           auxiliary variable
191  *
192  *  global variables:
193  *      int     hilo        byte order
194  *      FILE *  ofp         output file handle
195  *      Addr_T  rtval[]     relocated data
196  *
197  *  functions called:
198  *      VOID hexRecord()    lkihx.c
199  *      int fprintf()       c_library
200  *
201  *  side effects:
202  *      The sequence of rtval[0], rtval[1] is eventually changed.
203  */
204
205 VOID
206 ihx(i)
207 {
208     Addr_T n;
209     if (i) {
210         if (hilo == 0) {
211             n = rtval[0];
212             rtval[0] = rtval[1];
213             rtval[1] = n;
214         }
215         hexRecord((rtval[0]<<8) + rtval[1], 2);
216     } else {
217         if (rflag) /* linear start address, hardcoded as reset vector (0x0000) */
218             fprintf(ofp, ":0400000500000000F7\n");
219         fprintf(ofp, ":00000001FF\n");
220     }
221 }
222
223 /*)Function ihxNewArea(i)
224  * The function ihxNewArea() is called when processing of new area is started.
225  * It resets the value of lastHexAddr.
226  */
227
228 VOID
229 ihxNewArea()
230 {
231     lastHexAddr = 0;
232 }
233
234 /*)Function ihxExtendedLinearAddress(i)
235  *
236  *      Addr_T  i           16 bit extended linear address.
237  *
238  *  The function ihxExtendedLinearAddress() writes an extended
239  *  linear address record (type 04) to the output file.
240  *
241  *  local variables:
242  *      Addr_T  chksum      byte checksum
243  *
244  *  global variables:
245  *      FILE *  ofp         output file handle
246  *
247  *  functions called:
248  *      int     fprintf()   c_library
249  *
250  *  side effects:
251  *      The data is output to the file defined by ofp.
252  *      hexPageOverrun and lastHexAddr is cleared
253  */
254 VOID
255 ihxExtendedLinearAddress(Addr_T a)
256 {
257     Addr_T  chksum;
258
259     /* The checksum is the complement of the bytes in the
260      * record: the 2 is record length, 4 is the extended linear
261      * address record type, plus the two address bytes.
262      */
263     chksum = 2 + 4 + (a & 0xff) + ((a >> 8) & 0xff);
264
265     fprintf(ofp, ":02000004%04X%02X\n", a & 0xffff, (0-chksum) & 0xff);
266     hexPageOverrun = 0;
267     lastHexAddr = 0;
268 }