1 /*
2  *      Short program to pad a binary block and get a fixed size ROM
3  *      Stefano Bodrato - Apr 2014
4  *      Alvin Albrecht - 2017
5  *
6  *      $Id: rom.c,v 1.13 2016/07/08 02:43:24 aralbrec Exp $
7  */
8 
9 
10 #include "appmake.h"
11 
12 static char              help         = 0;
13 static char             *binname      = NULL;
14 static int               binorg       = -1;
15 static char             *crtfile      = NULL;
16 static char             *romname      = NULL;
17 static int               romsize      = 0;
18 static int               rombase      = 0;
19 static int               romfill      = 255;
20 static int               chipsize     = 0;
21 static char              ihex         = 0;
22 static int               recsize      = 16;
23 static int               code_fence   = -1;
24 static int               data_fence   = -1;
25 static char              warn         = 0;
26 
27 
28 /* Options that are available for this module */
29 option_t rom_options[] = {
30     { 'h', "help",      "Display this help",                OPT_BOOL,  &help    },
31     { 'b', "binfile",   "Binary file to embed",             OPT_STR,   &binname },
32     {  0 , "org",       "Origin of the embedded binary",    OPT_INT,   &binorg  },
33     { 'c', "crt0file",  "crt0 used to link binary",         OPT_STR,   &crtfile },
34     { 'o', "output",    "Name of output rom",               OPT_STR,   &romname },
35     { 's', "romsize",   "Size of output rom",               OPT_INT,   &romsize },
36     {  0,  "rombase",   "Base address of output rom",       OPT_INT,   &rombase },
37     { 'f', "filler",    "Filler byte (default: 0xFF)",      OPT_INT,   &romfill },
38     {  0,  "chipsize",  "Single chip size in a ROM set",    OPT_INT,   &chipsize },
39     {  0,  "ihex",      "Generate an iHEX file",            OPT_BOOL,  &ihex    },
40     { 'w', "warn",      "Warn of colliding sections",       OPT_BOOL,  &warn },
41     {  0 , "code-fence","CODE restricted below this address", OPT_INT,   &code_fence },
42     {  0 , "data-fence","DATA restricted below this address", OPT_INT,   &data_fence },
43     { 'r', "recsize",   "Record size for iHEX file (default: 16)", OPT_INT, &recsize },
44     {  0,  NULL,        NULL,                               OPT_NONE,  NULL     }
45 };
46 
47 
48 /*
49  * Execution starts here
50  */
51 
rom_exec(char * target)52 int rom_exec(char* target)
53 {
54     FILE *fpin, *fpout;
55     char outname[FILENAME_MAX + 1];
56     char chipname[FILENAME_MAX + 1];
57     char file_ext[5];
58     int crt_model;
59     int pre_size, post_size, in_size;
60     int c, pos, cnt, chipcount;
61     int check;
62 
63     if (help)
64         return -1;
65     if ((binname == NULL) && (romsize == 0))
66         return -1;
67 
68     crt_model = (crtfile == NULL) ? (-1) : parameter_search(crtfile, ".sym", "__crt_model");
69 
70     if ((binorg == -1) && ((crtfile == NULL) || ((binorg = get_org_addr(crtfile)) == -1))) {
71         fprintf(stderr, "Warning: could not get the code ORG, binary ORG defaults to rombase = %d\n", rombase);
72         binorg = rombase;
73     }
74 
75     if (romname == NULL) {
76         if (binname == NULL)
77             exit_log(1, "No destination file specified\n");
78         else {
79             strcpy(outname, binname);
80             // choose bin suffix if new c lib compile and ram model chosen or romsize is set to zero
81             // not safe to use bin suffix in classic compile since the linker's output filename ends in .bin
82             suffix_change(outname, ((crt_model == 0) || ((crt_model != -1) && (romsize == 0))) ? ".bin" : ".rom");
83             if (!strcmp(outname, binname))
84                 suffix_change(outname, ".rom");
85         }
86     } else
87         strcpy(outname, romname);
88 
89     if ((pre_size = (romsize == 0) ? 0 : (binorg - rombase)) < 0)
90         exit_log(1, "Binary ORG %d is less than ROM base address %d\n", binorg, rombase);
91 
92     fpin = NULL;
93 
94     if (binname == NULL)
95         in_size = 0;
96     else if ((fpin = fopen_bin(binname, crtfile)) == NULL)
97         exit_log(1, "Can't open input file %s\n", binname);
98     else if (fseek(fpin, 0, SEEK_END)) {
99         fclose(fpin);
100         exit_log(1, "Couldn't determine size of file %s\n", binname);
101     } else {
102         in_size = ftell(fpin);
103         rewind(fpin);
104     }
105 
106     chipcount = 0;
107     if (chipsize > 0) {
108         if (romsize == 0)
109             exit_log(1, "ROM size must be specified as a multiple of [chipsize = %d]\n", chipsize);
110         if (romsize % chipsize != 0)
111             exit_log(1, "ROM size is %d, it can't be split for [chipsize = %d]\n", romsize, chipsize);
112         chipcount = romsize / chipsize;
113     }
114     if (chipcount > 16)
115         exit_log(1, "Too many ROM chips to be created, check [chipsize].\n");
116 
117     if ((post_size = (romsize == 0) ? 0 : (romsize - in_size - binorg + rombase)) < 0)
118         exit_log(1, "Embedded binary address range [%d,%d] exceeds ROM address range [%d,%d]\n", binorg, binorg + in_size - 1, rombase, rombase + romsize - 1);
119 
120     if ((fpout = fopen(outname, "wb")) == NULL) {
121         if (fpin != NULL)
122             fclose(fpin);
123         exit_log(1, "Can't open output file %s for writing\n", outname);
124     }
125 
126     while (pre_size-- > 0)
127         fputc(romfill, fpout);
128 
129     if (fpin != NULL)
130         while ((c = fgetc(fpin)) != EOF)
131             fputc(c, fpout);
132 
133     while (post_size-- > 0)
134         fputc(romfill, fpout);
135 
136     if (fpin != NULL)
137         fclose(fpin);
138     fclose(fpout);
139 
140     // check if section CODE extends past fence
141 
142     if (code_fence > 0) {
143 
144         long code_end_tail;
145 
146         code_end_tail = parameter_search(crtfile, ".map", "__CODE_END_tail");
147 
148         if (code_end_tail > code_fence) {
149 
150             fprintf(stderr, "\nWarning: The CODE section has exceeded the fence by %u bytes\n  (CODE_end 0x%04X, CODE fence 0x%04X)\n", (unsigned int)(code_end_tail - code_fence), (unsigned int)code_end_tail, (unsigned int)code_fence);
151         }
152 
153     }
154 
155     // check if section DATA extends past fence
156 
157     if (data_fence > 0) {
158 
159         long data_end_tail;
160 
161         data_end_tail = parameter_search(crtfile, ".map", "__DATA_END_tail");
162 
163         if (data_end_tail > data_fence) {
164 
165             fprintf(stderr, "\nWarning: The DATA section has exceeded the fence by %u bytes\n  (DATA_end 0x%04X, DATA fence 0x%04X)\n", (unsigned int)(data_end_tail - data_fence), (unsigned int)data_end_tail, (unsigned int)data_fence);
166         }
167     }
168 
169     // check if sections overlap
170 
171     if (warn) {
172 
173         long code_end_tail;
174         long data_head, data_end_tail;
175         long bss_head;
176 
177         code_end_tail = parameter_search(crtfile, ".map", "__CODE_END_tail");
178 
179         data_head = parameter_search(crtfile, ".map", "__DATA_head");
180         data_end_tail = parameter_search(crtfile, ".map", "__DATA_END_tail");
181 
182         bss_head  = parameter_search(crtfile, ".map", "__BSS_head");
183 
184         if (code_end_tail > data_head) {
185 
186             fprintf(stderr, "\nWarning: CODE section overlaps DATA section by %u bytes\n  (CODE_end 0x%04X, DATA_head 0x%04X)\n", (unsigned int)(code_end_tail - data_head), (unsigned int)code_end_tail, (unsigned int)data_head);
187         }
188 
189         if (data_end_tail > bss_head ) {
190 
191             fprintf(stderr, "\nWarning: DATA section overlaps BSS section by %u bytes\n  (DATA_end 0x%04X, BSS_head 0x%04X)\n", (unsigned int)(data_end_tail - bss_head), (unsigned int)data_end_tail, (unsigned int)bss_head);
192         }
193     }
194 
195     if (ihex) {
196         if (chipcount > 1) {
197             fclose(fpin);
198             exit_log(1, "Hex mode is not supported in multiple chip mode.\n");
199         }
200 
201         if ((fpin = fopen(outname, "rb")) == NULL)
202             exit_log(1, "Can't open %s for hex conversion\n", outname);
203 
204         suffix_change(outname, ".ihx");
205 
206         if ((fpout = fopen(outname, "wb")) == NULL) {
207             fclose(fpin);
208             exit_log(1, "Can't create %s for hex conversion\n", outname);
209         }
210 
211         bin2hex(fpin, fpout, (romsize == 0) ? binorg : rombase, -1, recsize, 1);
212 
213         fclose(fpin);
214         fclose(fpout);
215 
216     } else {
217 
218         /* Split into binary blocks */
219         if (chipcount > 1) {
220             if ((fpin = fopen(outname, "rb")) == NULL)
221                 exit_log(1, "Can't open %s to split into ROM chips\n", outname);
222 
223             for (cnt = 1; cnt <= chipcount; cnt++) {
224                 sprintf(file_ext, ".0%c", cnt + 'a' - 1);
225                 strcpy(chipname, outname);
226                 suffix_change(chipname, file_ext);
227                 if ((fpout = fopen(chipname, "wb")) == NULL) {
228                     fclose(fpin);
229                     exit_log(1, "Can't create %s romchip file\n", chipname);
230                 }
231                 check = 0;
232                 for (pos = 0; pos < chipsize; pos++) {
233                     c = fgetc(fpin);
234                     if (c != romfill)
235                         check++;
236                     fputc(c, fpout);
237                 }
238                 fclose(fpout);
239                 if (!check)
240                     fprintf(stderr, "WARNING: ROM chip file '%s' is empty, it can probably be omitted.\n", chipname);
241             }
242 
243             fclose(fpin);
244         }
245     }
246 
247     return 0;
248 }
249