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