1 /* .cod file support
2 Copyright (C) 2003, 2004, 2005 Craig Franklin
3 Copyright (C) 2012 Borut Razem
4 Copyright (C) 2015-2016 Molnar Karoly
5
6 This file is part of gputils.
7
8 gputils is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 gputils is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with gputils; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
22
23 #include "stdhdr.h"
24 #include "libgputils.h"
25
26 /*------------------------------------------------------------------------------------------------*/
27
28 static void
_cod_time(uint8_t * Buffer,size_t Sizeof_buffer)29 _cod_time(uint8_t *Buffer, size_t Sizeof_buffer)
30 {
31 time_t now;
32 struct tm *local;
33 unsigned int value;
34
35 time(&now);
36 local = localtime(&now);
37 value = (local->tm_hour * 100) + local->tm_min;
38 gp_putl16(Buffer, value);
39 /* No space for the seconds. */
40 }
41
42 /*------------------------------------------------------------------------------------------------*/
43
44 static void
_cod_Pdate(uint8_t * Pascal_str,size_t Pascal_max_size)45 _cod_Pdate(uint8_t *Pascal_str, size_t Pascal_max_size)
46 {
47 time_t now;
48 char temp[16];
49 size_t length;
50
51 time(&now);
52 #ifdef HAVE_LOCALE_H
53 setlocale(LC_ALL, "C");
54 #endif
55 length = strftime(temp, sizeof(temp), "%d%b%g", localtime(&now));
56 assert(length < Pascal_max_size);
57
58 *Pascal_str = (uint8_t)length;
59 ++Pascal_str;
60 memcpy(Pascal_str, temp, length);
61 }
62
63 /*------------------------------------------------------------------------------------------------*/
64
65 void
gp_cod_create(Block * B)66 gp_cod_create(Block *B)
67 {
68 assert(B != NULL);
69
70 B->block = GP_Calloc(1, COD_BLOCK_SIZE);
71 }
72
73 /*------------------------------------------------------------------------------------------------*/
74
75 DirBlockInfo *
gp_cod_new_dir_block(void)76 gp_cod_new_dir_block(void)
77 {
78 DirBlockInfo *dir;
79
80 /* initialize eveything to zero */
81 dir = GP_Calloc(1, sizeof(DirBlockInfo));
82 gp_putl16(&dir->dir[COD_DIR_CODTYPE], 1);
83 return dir;
84 }
85
86 /*------------------------------------------------------------------------------------------------*/
87
88 DirBlockInfo *
gp_cod_init_dir_block(const char * File_name,const char * Compiler)89 gp_cod_init_dir_block(const char *File_name, const char *Compiler)
90 {
91 DirBlockInfo *dir;
92 uint8_t *block;
93
94 dir = gp_cod_new_dir_block();
95 block = dir->dir;
96 /* Initialize the directory block with known data. It'll be written
97 * to the .cod file after everything else. */
98 gp_Pstr_from_str(&block[COD_DIR_SOURCE], COD_DIR_SOURCE_SIZE, File_name, NULL);
99 _cod_Pdate (&block[COD_DIR_DATE], COD_DIR_DATE_SIZE);
100 _cod_time (&block[COD_DIR_TIME], COD_DIR_TIME_SIZE);
101 gp_Pstr_from_str(&block[COD_DIR_VERSION], COD_DIR_VERSION_SIZE, VERSION, NULL);
102 gp_Pstr_from_str(&block[COD_DIR_COMPILER], COD_DIR_COMPILER_SIZE, Compiler, NULL);
103 gp_Pstr_from_str(&block[COD_DIR_NOTICE], COD_DIR_NOTICE_SIZE, GPUTILS_COPYRIGHT_STRING, NULL);
104
105 /* The address is always two shorts or 4 bytes long. */
106 block[COD_DIR_ADDRSIZE] = 0;
107
108 return dir;
109 }
110
111 /*------------------------------------------------------------------------------------------------*/
112
113 DirBlockInfo *
gp_cod_find_dir_block_by_high_addr(DirBlockInfo * Main,unsigned int High_addr)114 gp_cod_find_dir_block_by_high_addr(DirBlockInfo *Main, unsigned int High_addr)
115 {
116 DirBlockInfo *dbi;
117
118 dbi = Main;
119 /* find the directory containing high_addr 64k segment */
120 while (gp_getl16(&dbi->dir[COD_DIR_HIGHADDR]) != High_addr) {
121 /* If the next directory block (in the linked list of directory
122 blocks) is NULL, then this is the first time to encounter this
123 _64k segment. So we need to create a new segment. */
124 if (dbi->next == NULL) {
125 dbi->next = gp_cod_new_dir_block();
126 gp_putl16(&dbi->next->dir[COD_DIR_HIGHADDR], High_addr);
127 dbi = dbi->next;
128 break;
129 }
130 else {
131 dbi = dbi->next;
132 }
133 }
134
135 return dbi;
136 }
137
138 /*------------------------------------------------------------------------------------------------*/
139
140 /* gp_cod_emit_opcode - write one opcode to a cod_image_block */
141
142 void
gp_cod_emit_opcode(DirBlockInfo * Dbi,unsigned int Address,unsigned int Opcode)143 gp_cod_emit_opcode(DirBlockInfo *Dbi, unsigned int Address, unsigned int Opcode)
144 {
145 unsigned int block_index;
146
147 /* The code image blocks are handled in a different manner than the
148 * other cod blocks. In theory, it's possible to emit opcodes in a
149 * non-sequential manner. Furthermore, it's possible that there may
150 * be gaps in the program memory. These cases are handled by an array
151 * of code blocks. The lower 8 bits of the opcode's address form an
152 * index into the code block, while bits 9-15 are an index into the
153 * array of code blocks. The code image blocks are not written until
154 * all of the opcodes have been emitted.
155 */
156
157 block_index = (Address >> COD_BLOCK_BITS) & (COD_CODE_IMAGE_BLOCKS - 1);
158
159 if (Dbi->cod_image_blocks[block_index].block == NULL) {
160 gp_cod_create(&Dbi->cod_image_blocks[block_index]);
161 }
162
163 gp_putl16(&Dbi->cod_image_blocks[block_index].block[Address & (COD_BLOCK_SIZE - 1)], Opcode);
164 }
165
166 /*------------------------------------------------------------------------------------------------*/
167
168 /* gp_cod_write_code - write all of the assembled pic code to the .cod file */
169
170 void
gp_cod_write_code(proc_class_t Class,const MemBlock_t * Mem,DirBlockInfo * Main)171 gp_cod_write_code(proc_class_t Class, const MemBlock_t *Mem, DirBlockInfo *Main)
172 {
173 DirBlockInfo *dbi;
174 const MemBlock_t *m;
175 int i;
176 int mem_base;
177 int high_addr;
178 int start_address;
179 gp_boolean used_flag;
180 BlockList *rb;
181 int _64k_base;
182 uint16_t insn;
183 uint8_t *record;
184
185 start_address = 0;
186 used_flag = false;
187 dbi = NULL;
188 _64k_base = 0;
189 m = Mem;
190
191 while (m != NULL) {
192 mem_base = IMemAddrFromBase(m->base);
193 high_addr = IMemBaseFromAddr(mem_base);
194
195 if ((dbi == NULL) || (high_addr != _64k_base)) {
196 _64k_base = high_addr;
197 dbi = gp_cod_find_dir_block_by_high_addr(Main, _64k_base);
198 }
199
200 for (i = mem_base; (i - mem_base) <= I_MEM_MAX; i += 2) {
201 if (((i - mem_base) < I_MEM_MAX) &&
202 (Class->i_memory_get(Mem, i, &insn, NULL, NULL) == W_USED_ALL)) {
203 gp_cod_emit_opcode(dbi, i, insn);
204
205 if (!used_flag) {
206 /* Save the start address in a range of opcodes */
207 start_address = i;
208 used_flag = true;
209 }
210 }
211 else {
212 /* No code at address i, but we need to check if this is the
213 first empty address after a range of address. */
214 if (used_flag) {
215 rb = gp_cod_block_get_last_or_new(&dbi->range);
216
217 if ((rb == NULL) || ((dbi->range.offset + COD_MAPENTRY_SIZE) >= COD_BLOCK_SIZE)) {
218 /* If there are a whole bunch of non-contiguous pieces of
219 code then we'll get here. But most pic apps will only need
220 one directory block (that will give you 64 ranges or non-
221 contiguous chunks of pic code). */
222 rb = gp_cod_block_append(&dbi->range, gp_cod_block_new());
223 }
224 /* We need to update dir map indicating a range of memory that is needed.
225 This is done by writing the start and end address to the directory map. */
226 record = &rb->block[dbi->range.offset];
227 gp_putl16(&record[COD_MAPTAB_START], start_address);
228 gp_putl16(&record[COD_MAPTAB_LAST], i - 1);
229
230 used_flag = false;
231
232 dbi->range.offset += COD_MAPENTRY_SIZE;
233 }
234 }
235 }
236
237 m = m->next;
238 }
239 }
240
241 /*------------------------------------------------------------------------------------------------*/
242
243 size_t
gp_cod_put_long_symbol(uint8_t * Record,const char * Name,gp_symvalue_t Value,unsigned int Type)244 gp_cod_put_long_symbol(uint8_t *Record, const char *Name, gp_symvalue_t Value, unsigned int Type)
245 {
246 size_t length;
247
248 assert(Record != NULL);
249
250 length = gp_Pstr_from_str(&Record[COD_LSYMBOL_NAME], COD_LSYMBOL_NAME_MAX_SIZE, Name, NULL);
251 gp_putl16(&Record[length + COD_LSYMBOL_TYPE], Type);
252 /* write 32 bits, big endian */
253 gp_putb32(&Record[length + COD_LSYMBOL_VALUE], Value);
254 return (length + COD_LSYMBOL_EXTRA);
255 }
256
257 /*------------------------------------------------------------------------------------------------*/
258
259 size_t
gp_cod_put_debug_symbol(uint8_t * Record,const char * String,gp_symvalue_t Value,char Command)260 gp_cod_put_debug_symbol(uint8_t *Record, const char *String, gp_symvalue_t Value, char Command)
261 {
262 assert(Record != NULL);
263
264 /* write 32 bits, big endian */
265 gp_putb32(&Record[COD_DEBUG_ADDR], Value);
266 Record[COD_DEBUG_CMD] = Command;
267 return (gp_Pstr_from_str(&Record[COD_DEBUG_MSG], COD_DEBUG_MSG_MAX_SIZE, String, NULL) + COD_DEBUG_EXTRA);
268 }
269
270 /*------------------------------------------------------------------------------------------------*/
271
272 size_t
gp_cod_put_line_number(uint8_t * Record,unsigned int File_id,unsigned int Line_number,unsigned int Address,unsigned int Flag)273 gp_cod_put_line_number(uint8_t *Record, unsigned int File_id, unsigned int Line_number,
274 unsigned int Address, unsigned int Flag)
275 {
276 assert(Record != NULL);
277
278 Record[COD_LS_SFILE] = File_id;
279 Record[COD_LS_SMOD] = Flag;
280
281 /* Write the source file line number corresponding to the list file line number (only lower 16 bits). */
282 gp_putl16(&Record[COD_LS_SLINE], (uint16_t)Line_number);
283
284 /* Write the address of the opcode (only lower 16 bits). */
285 gp_putl16(&Record[COD_LS_SLOC], (uint16_t)Address);
286 return COD_LINE_SYM_SIZE;
287 }
288
289 /*------------------------------------------------------------------------------------------------*/
290
291 BlockList *
gp_cod_block_new(void)292 gp_cod_block_new(void)
293 {
294 return (BlockList *)GP_Calloc(1, sizeof(BlockList));
295 }
296
297 /*------------------------------------------------------------------------------------------------*/
298
299 BlockList *
gp_cod_block_append(Blocks * Bl,BlockList * B)300 gp_cod_block_append(Blocks *Bl, BlockList *B)
301 {
302 if (Bl->first == NULL) {
303 Bl->first = B;
304 Bl->count = 1;
305 }
306 else {
307 Bl->last->next = B;
308 (Bl->count)++;
309 }
310
311 Bl->last = B;
312 Bl->offset = 0;
313 return B;
314 }
315
316 /*------------------------------------------------------------------------------------------------*/
317
318 BlockList *
gp_cod_block_get_last(Blocks * Bl)319 gp_cod_block_get_last(Blocks *Bl)
320 {
321 return Bl->last;
322 }
323
324 /*------------------------------------------------------------------------------------------------*/
325
326 BlockList *
gp_cod_block_get_last_or_new(Blocks * Bl)327 gp_cod_block_get_last_or_new(Blocks *Bl)
328 {
329 if (Bl->first != NULL) {
330 return gp_cod_block_get_last(Bl);
331 }
332 else {
333 Bl->first = gp_cod_block_new();
334 Bl->last = Bl->first;
335 Bl->offset = 0;
336 Bl->count = 1;
337 return Bl->first;
338 }
339 }
340
341 /*------------------------------------------------------------------------------------------------*/
342
343 int
gp_cod_block_count(const Blocks * Bl)344 gp_cod_block_count(const Blocks *Bl)
345 {
346 return ((Bl->first == NULL) ? 0 : Bl->count);
347 }
348
349 /*------------------------------------------------------------------------------------------------*/
350
351 void
gp_cod_block_enumerate(DirBlockInfo * Dir,unsigned int Offset,Blocks * Bl,unsigned int * Block_num)352 gp_cod_block_enumerate(DirBlockInfo *Dir, unsigned int Offset, Blocks *Bl, unsigned int *Block_num)
353 {
354 if (Bl->first != NULL) {
355 /* enumerate block list */
356 gp_putl16(&Dir->dir[Offset], ++(*Block_num));
357 *Block_num += gp_cod_block_count(Bl) - 1;
358 gp_putl16(&Dir->dir[Offset + 2], *Block_num);
359 }
360 }
361
362 /*------------------------------------------------------------------------------------------------*/
363
364 void
gp_cod_enumerate_directory(DirBlockInfo * Main_dir)365 gp_cod_enumerate_directory(DirBlockInfo *Main_dir)
366 {
367 DirBlockInfo *dbi;
368 unsigned int block_num;
369 unsigned int i;
370
371 block_num = 0;
372
373 /* enumerate directory blocks */
374 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
375 gp_putl16(&dbi->dir[COD_DIR_NEXTDIR], (dbi->next != NULL) ? ++block_num : 0);
376 }
377
378 /* enumerate code blocks */
379 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
380 for (i = 0; i < COD_CODE_IMAGE_BLOCKS; ++i) {
381 if (dbi->cod_image_blocks[i].block != NULL) {
382 gp_putl16(&dbi->dir[i * 2], ++block_num);
383 }
384 }
385 }
386
387 /* enumerate surce files blocks */
388 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
389 gp_cod_block_enumerate(dbi, COD_DIR_NAMTAB, &dbi->file, &block_num);
390 }
391
392 /* enumerate list lines blocks */
393 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
394 gp_cod_block_enumerate(dbi, COD_DIR_LSTTAB, &dbi->list, &block_num);
395 }
396
397 /* enumerate memory map blocks */
398 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
399 gp_cod_block_enumerate(dbi, COD_DIR_MEMMAP, &dbi->range, &block_num);
400 }
401
402 /* enumerate long symbol table blocks */
403 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
404 gp_cod_block_enumerate(dbi, COD_DIR_LSYMTAB, &dbi->lsym, &block_num);
405 }
406
407 /* enumerate debug messages table blocks */
408 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
409 gp_cod_block_enumerate(dbi, COD_DIR_MESSTAB, &dbi->debug, &block_num);
410 }
411 }
412
413 /*------------------------------------------------------------------------------------------------*/
414
415 void
gp_cod_block_write(FILE * F,const Blocks * Bl)416 gp_cod_block_write(FILE *F, const Blocks *Bl)
417 {
418 const BlockList *curr;
419
420 curr = Bl->first;
421 /* write block list */
422 while (curr != NULL) {
423 if (fwrite(curr->block, 1, COD_BLOCK_SIZE, F) != COD_BLOCK_SIZE) {
424 fprintf(stderr, "%s() -- Could not write cod file.\n", __func__);
425 exit(1);
426 }
427 curr = curr->next;
428 }
429 }
430
431 /*------------------------------------------------------------------------------------------------*/
432
433 void
gp_cod_write_directory(FILE * F,const DirBlockInfo * Main_dir)434 gp_cod_write_directory(FILE *F, const DirBlockInfo *Main_dir)
435 {
436 const DirBlockInfo *dbi;
437 unsigned int i;
438
439 /* write directory blocks */
440 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
441 if (fwrite(dbi->dir, 1, COD_BLOCK_SIZE, F) != COD_BLOCK_SIZE) {
442 fprintf(stderr, "%s() -- Could not write cod file.\n", __func__);
443 exit(1);
444 }
445 }
446
447 /* write code blocks */
448 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
449 for (i = 0; i < COD_CODE_IMAGE_BLOCKS; ++i) {
450 if (dbi->cod_image_blocks[i].block != NULL) {
451 if (fwrite(dbi->cod_image_blocks[i].block, 1, COD_BLOCK_SIZE, F) != COD_BLOCK_SIZE) {
452 fprintf(stderr, "%s() -- Could not write cod file.\n", __func__);
453 exit(1);
454 }
455 }
456 }
457 }
458
459 /* write source files blocks */
460 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
461 gp_cod_block_write(F, &dbi->file);
462 }
463
464 /* write list lines blocks */
465 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
466 gp_cod_block_write(F, &dbi->list);
467 }
468
469 /* write memory map blocks */
470 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
471 gp_cod_block_write(F, &dbi->range);
472 }
473
474 /* write long symbol table blocks */
475 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
476 gp_cod_block_write(F, &dbi->lsym);
477 }
478
479 /* write debug messages table blocks */
480 for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
481 gp_cod_block_write(F, &dbi->debug);
482 }
483 }
484
485 /*------------------------------------------------------------------------------------------------*/
486
487 void
gp_cod_block_free(Blocks * Bl)488 gp_cod_block_free(Blocks *Bl)
489 {
490 BlockList *curr;
491 BlockList *next;
492
493 curr = Bl->first;
494 while (curr != NULL) {
495 next = curr->next;
496 free(curr);
497 curr = next;
498 }
499
500 Bl->first = NULL;
501 Bl->last = NULL;
502 Bl->offset = 0;
503 Bl->count = 0;
504 }
505
506 /*------------------------------------------------------------------------------------------------*/
507
508 void
gp_cod_free_directory(DirBlockInfo * Main_dir)509 gp_cod_free_directory(DirBlockInfo *Main_dir)
510 {
511 DirBlockInfo *dbi;
512 DirBlockInfo *next;
513 unsigned int i;
514
515 dbi = Main_dir;
516 while (dbi != NULL) {
517 /* free code blocks */
518 for (i = 0; i < COD_CODE_IMAGE_BLOCKS; ++i) {
519 if (dbi->cod_image_blocks[i].block != NULL) {
520 free(dbi->cod_image_blocks[i].block);
521 }
522 }
523
524 /* free surce files blocks */
525 gp_cod_block_free(&dbi->file);
526
527 /* free list lines blocks */
528 gp_cod_block_free(&dbi->list);
529
530 /* free memory map blocks */
531 gp_cod_block_free(&dbi->range);
532
533 /* free long symbol table blocks */
534 gp_cod_block_free(&dbi->lsym);
535
536 /* free debug messages table blocks */
537 gp_cod_block_free(&dbi->debug);
538
539 next = dbi->next;
540 /* free directory blocks */
541 free(dbi);
542 dbi = next;
543 }
544 }
545