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