* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[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     if ( (lastHexAddr > addr) && (rflag) ) {
147         overrun = hexPageOverrun + 1;
148         ihxExtendedLinearAddress(lastExtendedAddress + overrun);
149         hexPageOverrun = overrun;
150         hexRecord(addr, rtvalIndex);
151         return;
152     }
153
154     lastHexAddr = addr;
155     fprintf(ofp, ":%02X%04X00", chksum, addr);
156     chksum += (addr >> 8) + (addr & 0xff);
157     for (i = rtvalIndex, bytes = 0; i < rtcnt; i++) {
158         if (rtflg[i]) {
159             fprintf(ofp, "%02X", rtval[i]);
160             chksum += rtval[i];
161             if (addr + ++bytes > 0xffff) {
162                 if (rflag) {
163                     fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
164                     overrun = hexPageOverrun + 1;
165                     ihxExtendedLinearAddress(lastExtendedAddress + overrun);
166                     hexPageOverrun = overrun;
167                     hexRecord(0, i + 1);
168                     return;
169                 } else {
170                     fprintf(stderr,
171                         "warning: extended linear address encountered; "
172                         "you probably want the -r flag.\n");
173                 }
174             }
175         }
176     }
177     fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
178 }
179
180 /*)Function ihx(i)
181  *
182  *      int     i           0 - process data
183  *                          1 - end of data
184  *
185  *  The function ihx() calls the hexRecord() function for processing data
186  *  or writes the End of Data record to the file defined by ofp.
187  *
188  *  local variables:
189  *      Addr_T  n           auxiliary variable
190  *
191  *  global variables:
192  *      int     hilo        byte order
193  *      FILE *  ofp         output file handle
194  *      Addr_T  rtval[]     relocated data
195  *
196  *  functions called:
197  *      VOID hexRecord()    lkihx.c
198  *      int fprintf()       c_library
199  *
200  *  side effects:
201  *      The sequence of rtval[0], rtval[1] is eventually changed.
202  */
203
204 VOID
205 ihx(i)
206 {
207     Addr_T n;
208     if (i) {
209         if (hilo == 0) {
210             n = rtval[0];
211             rtval[0] = rtval[1];
212             rtval[1] = n;
213         }
214         hexRecord((rtval[0]<<8) + rtval[1], 2);
215     } else {
216         if (rflag) /* linear start address, hardcoded as reset vector (0x0000) */
217             fprintf(ofp, ":0400000500000000F7\n");
218         fprintf(ofp, ":00000001FF\n");
219     }
220 }
221
222 /*)Function ihxNewArea(i)
223  * The function ihxNewArea() is called when processing of new area is started.
224  * It resets the value of lastHexAddr.
225  */
226
227 VOID
228 ihxNewArea()
229 {
230     lastHexAddr = 0;
231 }
232
233 /*)Function ihxExtendedLinearAddress(i)
234  *
235  *      Addr_T  i           16 bit extended linear address.
236  *
237  *  The function ihxExtendedLinearAddress() writes an extended
238  *  linear address record (type 04) to the output file.
239  *
240  *  local variables:
241  *      Addr_T  chksum      byte checksum
242  *
243  *  global variables:
244  *      FILE *  ofp         output file handle
245  *
246  *  functions called:
247  *      int     fprintf()   c_library
248  *
249  *  side effects:
250  *      The data is output to the file defined by ofp.
251  *      hexPageOverrun and lastHexAddr is cleared
252  */
253 VOID
254 ihxExtendedLinearAddress(Addr_T a)
255 {
256     Addr_T  chksum;
257
258     /* The checksum is the complement of the bytes in the
259      * record: the 2 is record length, 4 is the extended linear
260      * address record type, plus the two address bytes.
261      */
262     chksum = 2 + 4 + (a & 0xff) + ((a >> 8) & 0xff);
263
264     fprintf(ofp, ":02000004%04X%02X\n", a & 0xffff, (0-chksum) & 0xff);
265     hexPageOverrun = 0;
266     lastHexAddr = 0;
267 }