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