Setting up repository
[linux-libre-firmware.git] / as31 / as31 / emitter.c
1 /* ----------------------------------------------------------------------
2  * FILE: emitter.c
3  * PACKAGE: as31 - 8031/8051 Assembler.
4  *
5  * DESCRIPTION:
6  *      This file contains the code to generate various
7  *      object code formats. Provisions exist to
8  *      support many types of output formats within the
9  *      same executable.
10  *
11  * REVISION HISTORY:
12  *      Jan. 19, 1990 - Created. (Ken Stauffer)
13  *      Jan. 29, 1990 - Added S-records (Theo Deraadt)
14  *
15  *
16  * AUTHOR:
17  *      All code in this file written by Ken Stauffer (University of Calgary).
18  *      January, 1990.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include "as31.h"
25
26 /* ----------------------------------------------------------------------
27  * DECLARE your own open(), close(), addr(), and byte() routines here.
28  *
29  */
30
31 static int open_tdr(const char *file, const char *ftype, const char *arg);
32 static void close_tdr(void);
33 static void addr_tdr(unsigned long a);
34 static void byte_tdr(unsigned char b);
35
36 static int open_byte(const char *file, const char *ftype, const char *arg);
37 static void close_byte(void);
38 static void addr_byte(unsigned long a);
39 static void byte_byte(unsigned char b);
40
41 static int open_od(const char *file, const char *ftype, const char *arg);
42 static void close_od(void);
43 static void addr_od(unsigned long a);
44 static void byte_od(unsigned char b);
45
46 static int open_srec(const char *file, const char *ftype, const char *arg);
47 static void close_srec(void);
48 static void addr_srec(unsigned long a);
49 static void byte_srec(unsigned char b);
50
51 static int open_hex(const char *file, const char *ftype, const char *arg);
52 static void close_hex(void);
53 static void addr_hex(unsigned long a);
54 static void byte_hex(unsigned char b);
55
56 static int open_bin(const char *file, const char *ftype, const char *arg);
57 static void close_bin(void);
58 static void addr_bin(unsigned long a);
59 static void byte_bin(unsigned char b);
60
61 /* ----------------------------------------------------------------------
62  * ADD an entry to this table to register your
63  * output format routines. Give your object format
64  * a name to be specified with the -F option.
65  *
66  */
67
68 static int format;
69
70 static struct {
71         char *name;
72         char *extension;
73         char *description;
74         int (*e_open)(const char *file, const char *ftype, const char *arg);
75         void (*e_close)(void);
76         void (*e_addr)(unsigned long a);
77         void (*e_byte)(unsigned char b);
78 } formtab[] = {
79         { "hex",   "hex",  "Intel-Hex (.hex)",  open_hex,  close_hex,  addr_hex,  byte_hex },
80         { "bin",   "bin",  "Binary (.bin)",  open_bin,  close_bin,  addr_bin,  byte_bin },
81         { "tdr",   "tdr",  "TDR Format (.tdr)", open_tdr,  close_tdr,  addr_tdr,  byte_tdr },
82         { "byte",  "byte", "BYTE list (.byte)",  open_byte, close_byte, addr_byte, byte_byte },
83         { "od",    "od",   "Octal Dump (.od)", open_od,   close_od,   addr_od,   byte_od },
84         { "srec2", "srec", "S Record, 16 bit Address (.srec)", open_srec, close_srec, addr_srec, byte_srec },
85         { "srec3", "srec", "S Record, 24 bit Address (.srec)", open_srec, close_srec, addr_srec, byte_srec },
86         { "srec4", "srec", "S Record, 32 bit Address (.srec)", open_srec, close_srec, addr_srec, byte_srec }
87 };
88
89 #define FORMTABSIZE     (sizeof(formtab)/sizeof(formtab[0]))
90
91 void emitusage(void)
92 {
93         int i;
94
95         fprintf(stderr, "[");
96         for(i=0; i<FORMTABSIZE; ) {
97                 fprintf(stderr, "%s", formtab[i].name);
98                 if( ++i < FORMTABSIZE)
99                         fprintf(stderr, "|");
100         }
101         fprintf(stderr, "]");
102 }
103
104 const char *emit_extension(const char *ftype)
105 {
106         int i;
107
108         if (ftype) {
109                 for(i=0; i<FORMTABSIZE; i++ ) {
110                         if (!strcmp(formtab[i].name, ftype))
111                                 return formtab[i].extension;
112                 }
113         }
114         return formtab[0].extension;
115 }
116
117
118 const char *emit_desc_lookup(int num)
119 {
120         if (num >= 0 && num < FORMTABSIZE)
121                 return formtab[num].description;
122         return NULL;
123 }
124
125 const char *emit_desc_to_name_lookup(const char *desc)
126 {
127         int i;
128
129         if (desc) {
130                 for(i=0; i<FORMTABSIZE; i++ ) {
131                         if (!strcmp(formtab[i].description, desc))
132                                 return formtab[i].name;
133                 }
134         }
135         return NULL;
136 }
137
138
139 int emitopen(const char *file, const char *ftype, const char *arg)
140 {
141         int i;
142         if( ftype ) {
143                 for(i=0; i<FORMTABSIZE; i++ ) {
144                         if( !strcmp(formtab[i].name,ftype) ) {
145                                 format = i;
146                                 return (*formtab[format].e_open)
147                                         (file,ftype,arg);
148                         }
149                 }
150                 mesg_f("no format \"%s\", using \"%s\"\n",
151                         ftype, formtab[0].name);
152         }
153         /*
154          * 0th entry is the default format type
155          */
156         format = 0;
157         return (*formtab[format].e_open)(file, ftype, arg);
158 }
159
160 void emitclose(void)
161 {
162         (*formtab[format].e_close)();
163 }
164
165 void emitaddr(unsigned long a)
166 {
167         (*formtab[format].e_addr)(a);
168 }
169
170 void emitbyte(int b)
171 {
172         (*formtab[format].e_byte)(b);
173 }
174
175 /* ----------------------------------------------------------------------
176  * Individual file format routines appear here:
177  *      Each file format must define the following routines:
178  *              open()  - Called ONCE before any of the others.
179  *                      It is passed with a filename and a format
180  *                      specific argument.
181  *
182  *              close() - Called ONCE when no more emit_byte()
183  *                      function calls will be made.
184  *
185  *              addr() - Called when ever a new address has been set
186  *                      in the assembler (ie. .org, .skip).
187  *                      This routine is also called once when the
188  *                      location counter is set to 0 at the very start of
189  *                      assembling.
190  * 
191  *              byte() - Called with each byte to be outputed.
192  *
193  */
194
195
196 static unsigned long addr;
197 static FILE *fout=NULL;
198 static long int offset;
199 static int newaddr;
200 static int pos=-666;
201 static unsigned char bytes[16];
202
203
204 /*-----------------------------------------------------------------------
205  * "hex" format.  Intel HEX format expected by many EPROM programmers
206  */
207
208
209 void hexdump(void)     /* dumps one line into file */
210 {
211         int i, sum;
212
213         if (fout == NULL) return;
214         fprintf(fout,":%02X%04lX00", pos, addr & 0xFFFF);
215         sum = pos + ((addr>>8)&0xff) + (addr&0xff) ;
216         for (i=0; i < pos; i++) {
217                 fprintf(fout,"%02X", bytes[i] & 0xFF );
218                 sum += bytes[i]&0xff;
219         }
220         fprintf(fout, "%02X\n", (-sum)&0xff);
221         addr += pos;
222         pos = 0;
223 }
224
225 static int open_hex(const char *file, const char *ftype, const char *arg)
226 {
227         if (file == NULL) fout = stdout;
228         else fout = fopen(file, "w");
229
230         if( fout == NULL ) {
231                 mesg_f("Cannot open %s for writing.\n", file);
232                 return -1;
233         }
234         pos = 0;
235         return 0;
236 }
237
238 static void close_hex(void)
239 {
240         if (fout == NULL) return;
241         if ( pos > 0 ) hexdump();
242         fprintf(fout, ":00000001FF\n");  /* end of file marker */
243         fclose(fout);
244 }
245
246 static void addr_hex(unsigned long a)
247 {
248         if ( pos > 0 ) hexdump();
249         addr = a;
250 }
251
252 static void byte_hex(unsigned char b)
253 {
254         bytes[pos] = b;
255         pos += 1;
256         if ( pos == 16) hexdump();
257 }
258
259
260 /*-----------------------------------------------------------------------
261  * "bin" format.  Raw binary data
262  */
263
264 static int open_bin(const char *file, const char *ftype, const char *arg)
265 {
266         if (file == NULL) fout = stdout;
267         else fout = fopen(file, "w");
268
269         if( fout == NULL ) {
270                 mesg_f("Cannot open %s for writing.\n", file);
271                 return -1;
272         }
273         addr = 0;
274         return 0;
275 }
276
277 static void close_bin(void)
278 {
279         if (fout == NULL) return;
280         fclose(fout);
281 }
282
283 static void addr_bin(unsigned long a)
284 {
285         long i;
286
287         if (fout == NULL) return;
288         if (a > addr) {
289                 for (i=0; i < a - addr; i++) {
290                         fprintf(fout, "%c", 0);
291                 }
292                 addr = a;
293                 return;
294         }
295         if (a < addr) {
296                 error("address changed to %lX, from %lX", a, addr);
297                 error("binary output format can't write backwards");
298                 addr = a;
299                 return;
300         }
301 }
302
303 static void byte_bin(unsigned char b)
304 {
305         if (fout == NULL) return;
306         fprintf(fout, "%c", b & 0xFF);
307         addr++;
308 }
309
310
311 /* ----------------------------------------------------------------------
312  * "tdr" format. For tdr's 68008 system. Generates a
313  * script file readable by a debugger.
314  *      [addr] : [byte] [byte] ..
315  *
316  * arg: This is a number in decimal which specifies
317  *      the offset, -Ftdr -A0000
318  *
319  *      These options specifies the tdr format, with an argument
320  *      of 0. This becomes the offset used in generating the
321  *      script file. The default if no A is present is 0x10000.
322  * 
323  */
324
325 static int open_tdr(const char *file, const char *ftype, const char *arg)
326 {
327         if (file == NULL) fout = stdout;
328         else fout = fopen(file,"w");
329
330         if( fout == NULL ) {
331                 mesg_f("Cannot open %s for writing.\n",file);
332                 return -1;
333         }
334         if (arg) {
335                 offset = atoi(arg);
336         } else {
337                 offset = 0x10000;
338         }
339         return 0;
340 }
341
342 static void close_tdr(void)
343 {
344         if (fout == NULL) return;
345         if( pos != 15 ) fprintf(fout,"\n");
346         fclose(fout);
347 }
348
349 static void addr_tdr(unsigned long a)
350 {
351         addr = a;
352         newaddr = 1;
353 }
354
355 static void byte_tdr(unsigned char b)
356 {
357         if (fout == NULL) return;
358         if( newaddr ) {
359                 if( pos != -666 ) fprintf(fout,"\n");
360                 newaddr = 0;
361                 pos = 15;
362                 fprintf(fout,"%06lx: ", (addr + offset) & 0xFFFFFF);
363         } else if( pos == 15 ) {
364                 fprintf(fout,"%06lx: ", (addr + offset) & 0xFFFFFF);
365         }
366
367         fprintf(fout,"%02x ", b & 0xFF );
368
369         if( pos-- == 0 ) {
370                 fprintf(fout, "\n");
371                 pos = 15;
372         }
373         addr += 1;
374 }
375
376
377 /* ----------------------------------------------------------------------
378  * "byte" format.
379  *      Like "tdr" but each byte is on a line by itself.
380  *      This is nice for debugging. No -A is used.
381  */
382
383 static int open_byte(const char *file, const char *ftype, const char *arg)
384 {
385         if (file == NULL) fout = stdout;
386         else fout = fopen(file,"w");
387
388         if( fout == NULL ) {
389                 mesg_f("Cannot open %s for writing.\n", file);
390                 return -1;
391         }
392         return 0;
393 }
394
395 static void close_byte(void)
396 {
397         if (fout == NULL) return;
398         fclose(fout);
399 }
400
401 static void addr_byte(unsigned long a)
402 {
403         addr = a;
404 }
405
406 static void byte_byte(unsigned char b)
407 {
408         if (fout == NULL) return;
409         fprintf(fout,"%04lX: %02X\n", addr & 0xFFFF, b & 0xFF );
410         addr += 1;
411 }
412
413
414 /* ----------------------------------------------------------------------
415  * "od", this format shows 16 bytes per line, with address.
416  *      It also includes ascii on one side.
417  *
418  * The format is similar to the od(1) program under Unix.
419  *
420  */
421
422 static int od_pos;
423 static unsigned char od_buf[16];
424 static unsigned long saveaddr;
425
426 void dumpline(unsigned long a, unsigned char *b, int len)
427 {
428         int i;
429
430         if (fout == NULL) return;
431         if(len <= 0 ) return;
432
433         fprintf(fout,"%04lx: ", a & 0xFFFF);
434
435         for(i=0; i<8; i++ ) {
436                 if( i <= len )
437                         fprintf(fout,"%02x ",b[i]);
438                 else
439                         fprintf(fout,"   ");
440         }
441
442         fprintf(fout,"- ");
443
444         for(i=8; i<16; i++ ) {
445                 if( i <= len )
446                         fprintf(fout,"%02x ",b[i]);
447                 else
448                         fprintf(fout,"   ");
449         }
450         fprintf(fout,"   ");
451
452         for(i=0; i<16; i++ ) {
453                 if( i <= len )
454                         fprintf(fout,"%c",
455                                 (b[i]>=' ' && b[i]<='~') ? b[i] : '.' );
456                 else
457                         break;
458         }
459         fprintf(fout,"\n");
460 }
461
462 static int open_od(const char *file, const char *ftype, const char *arg)
463 {
464         if (file == NULL) fout = stdout;
465         else fout = fopen(file,"w");
466
467         if( fout == NULL ) {
468                 mesg_f("Cannot open %s for writing.\n",file);
469                 return -1;
470         }
471         return 0;
472 }
473
474 static void close_od(void)
475 {
476         if (fout == NULL) return;
477         dumpline(saveaddr, od_buf, od_pos-1);
478         fclose(fout);
479 }
480
481 static void addr_od(unsigned long a)
482 {
483         newaddr = 1;
484         addr = a;
485 }
486
487 static void byte_od(unsigned char b)
488 {
489         if( newaddr ) {
490                 dumpline(saveaddr, od_buf, od_pos-1);
491                 od_pos = 0;
492                 newaddr = 0;
493                 saveaddr = addr;
494         } else if( od_pos == 16 ) {
495                 dumpline(saveaddr, od_buf, od_pos-1);
496                 od_pos = 0;
497                 saveaddr = addr;
498         }
499         od_buf[od_pos++] = b & 0x00ff;
500
501         addr += 1;
502 }
503
504
505 /* ----------------------------------------------------------------------
506  * srecord format. This is called with "-Fsrec2", "-Fsrec3", or
507  * "-Fsrec4"...
508  *
509  * arg: This is a number in decimal which specifies
510  *      the offset, -Fsrec3 -A0000
511  *
512  *      These options specifies the tdr format, with an argument
513  *      of 0. This becomes the offset used in generating the
514  *      script file. The default if no A is present is 0x0000.
515  * 
516  */
517
518 #define SREC_BYTESPERLINE 32
519
520 static int srec_format;
521 static int srec_check, srec_index;
522 static char srec_buf[SREC_BYTESPERLINE];
523 static long srec_address;
524
525 void srec_finishline(void)
526 {
527         int i;
528
529         if (fout == NULL) return;
530         srec_check = srec_index + (srec_address & 0xff) + ((srec_address>>8) & 0xff) + 4;
531
532         switch(srec_format) {
533         case 2:
534                 fprintf(fout, "S1%02X%04lX", srec_index + 4,
535                         srec_address & 0xFFFF);
536                 break;
537         case 3:
538                 fprintf(fout, "S2%02X%06lX", srec_index + 6,
539                         srec_address & 0xFFFFFF);
540                 srec_check += ((srec_address>>16) & 0xff) + 2;
541                 break;
542         case 4:
543                 fprintf(fout, "S3%02X%08lX", srec_index + 8, srec_address);
544                 srec_check += ((srec_address>>16) & 0xff) +
545                         ((srec_address>>24) & 0xff) + 4;
546                 break;
547         }
548
549         for(i=0; i<srec_index; i++) {
550                 fprintf(fout, "%02X", srec_buf[i] & 0xff);
551                 srec_check += srec_buf[i];
552         }
553
554         fprintf(fout, "%02X\n", (~srec_check & 0xff) );
555         srec_index = 0;
556 }
557
558 static int open_srec(const char *file, const char *ftype, const char *arg)
559 {
560         if (ftype == NULL) {
561                 mesg_f("No S Record Format\n");
562                 return -1;
563         }
564
565         if (sscanf(ftype, "srec%d", &srec_format) != 1) {
566                 mesg_f("Illegal S Record format \"%s\", must be \"srec2\", \"srec3\", or \"srec4\"\n", ftype);
567                 return -1;
568         }
569
570         if (srec_format < 2 || srec_format > 4) {
571                 mesg_f("Illegal S Record format %d %s (must be 2, 3, or 4)\n",
572                         srec_format, ftype);
573                 return -1;
574         }
575
576         if (file == NULL) fout = stdout;
577         else fout = fopen(file,"w");
578
579         if( fout == NULL ) {
580                 mesg_f("Cannot open %s for writing.\n",file);
581                 return -1;
582         }
583
584         if(arg) offset = atoi(arg);
585         else    offset = 0;
586
587         fprintf(fout, "S0030000%02X\n", (~3 & 0xff) );
588         return 0;
589 }
590
591 static void close_srec(void)
592 {
593         if (fout == NULL) return;
594         if(srec_index)
595                 srec_finishline();
596         switch(srec_format) {
597         case 2:
598                 fprintf(fout, "S9030000%02X\n", ~3 & 0xff);
599                 break;
600         case 3:
601                 fprintf(fout, "S804000000%02X\n", ~4 & 0xff);
602                 break;
603         case 4:
604                 fprintf(fout, "S70500000000%02X\n", ~5 & 0xff);
605                 break;
606         }
607         fclose(fout);
608 }
609
610 static void addr_srec(unsigned long a)
611 {
612         if(srec_index>0)
613                 srec_finishline();
614         srec_address = a + offset;
615 }
616
617 static void byte_srec(unsigned char b)
618 {
619         srec_buf[srec_index++] = b;
620         if(srec_index==SREC_BYTESPERLINE) {
621                 srec_finishline();
622                 srec_address += SREC_BYTESPERLINE;
623         }
624 }
625
626