1 /* ".COD" file output for gpasm
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 James Bowman, Scott Dattalo
4 Copyright (C) 2012 Borut Razem
5 Copyright (C) 2016 Molnar Karoly
6
7 This file is part of gputils.
8
9 gputils is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 gputils is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with gputils; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 #include "stdhdr.h"
25
26 #include "libgputils.h"
27 #include "gpasm.h"
28 #include "gpmsg.h"
29 #include "lst.h"
30 #include "cod.h"
31
32 #define COD_FILE_MAX_NUM 1000
33
34 static DirBlockInfo *main_dir = NULL;
35 static DirBlockInfo *dbi = NULL;
36 static unsigned int _64k_base = 0;
37
38 /*------------------------------------------------------------------------------------------------*/
39
40 /*
41 * _write_file_block - Write a code block that contains a list of the source files.
42 */
43
44 static void
_write_source_file_block(void)45 _write_source_file_block(void)
46 {
47 const file_context_t *fc;
48 BlockList *fb;
49 unsigned int length;
50 gp_boolean truncated;
51
52 if (state.file_list.first == NULL) {
53 return;
54 }
55
56 if (state.file_list.num_nodes >= COD_FILE_MAX_NUM) {
57 /* Too many files to handle in the .cod file. */
58 assert(0);
59 }
60
61 fb = NULL;
62 fc = state.file_list.first;
63 while (fc != NULL) {
64 if ((fb == NULL) || (main_dir->file.offset >= (COD_FILE_NAMES_PER_BLOCK * COD_FILE_NAME_SIZE))) {
65 fb = gp_cod_block_append(&main_dir->file, gp_cod_block_new());
66 }
67
68 /* The file id is used to define the index at which the file name is written within
69 * the file code block. (The id's are sequentially assigned when the files are opened.)
70 * If there are too many files, then gpasm will abort. Note: .cod files can handle
71 * larger file lists...
72 */
73
74 length = gp_Pstr_from_str(&fb->block[main_dir->file.offset], COD_FILE_NAME_SIZE, fc->name, &truncated);
75
76 if (truncated && (state.strict_level > 0)) {
77 gpmsg_vwarning(GPW_STRING_TRUNCATE, "(.COD)", fc->name, length);
78 }
79
80 main_dir->file.offset += COD_FILE_NAME_SIZE;
81
82 fc = fc->next;
83 }
84 }
85
86 /*------------------------------------------------------------------------------------------------*/
87
88 /* cod_init - Initialize the .cod file. */
89
90 void
cod_init(void)91 cod_init(void)
92 {
93 if (state.cod_file != OUT_NAMED) {
94 snprintf(state.cod_file_name, sizeof(state.cod_file_name), "%s.cod", state.base_file_name);
95 }
96
97 if (state.cod_file == OUT_SUPPRESS) {
98 state.cod.f = NULL;
99 state.cod.enabled = false;
100 unlink(state.cod_file_name);
101 }
102 else {
103 state.cod.f = fopen(state.cod_file_name, "wb");
104 if (state.cod.f == NULL) {
105 perror(state.cod_file_name);
106 exit(1);
107 }
108 state.cod.enabled = true;
109 }
110
111 if (!state.cod.enabled) {
112 main_dir = NULL;
113 return;
114 }
115
116 main_dir = gp_cod_init_dir_block(state.cod_file_name, "gpasm");
117 dbi = NULL;
118 _64k_base = 0;
119 }
120
121 /*------------------------------------------------------------------------------------------------*/
122
123 /* cod_lst_line - Add a line of information that cross references the
124 * the opcode's address, the source file, and the list file.
125 */
126
127 #define COD_LST_FIRST_LINE 7
128
129 void
cod_lst_line(unsigned int List_line)130 cod_lst_line(unsigned int List_line)
131 {
132 source_context_t *ctx;
133 uint8_t smod_flag;
134 BlockList *lb;
135 gp_boolean first_time;
136 unsigned int address;
137 unsigned int high_address;
138
139 if (!state.cod.enabled) {
140 return;
141 }
142
143 ctx = state.src_list.last;
144
145 /* Don't start until after the source is open. */
146 if (ctx == NULL) {
147 return;
148 }
149
150 /* Ignore the first few line numbers. */
151 /* if (state.lst.line_number < COD_LST_FIRST_LINE) {*/
152 if (state.lst.line_number < List_line) {
153 return;
154 }
155
156 address = gp_processor_insn_from_byte_c(state.device.class, state.lst.line.was_byte_addr);
157 high_address = IMemBaseFromAddr(address);
158
159 if ((dbi == NULL) || (high_address != _64k_base)) {
160 _64k_base = high_address;
161 dbi = gp_cod_find_dir_block_by_high_addr(main_dir, _64k_base);
162 }
163
164 first_time = (gp_cod_block_get_last(&dbi->list) == NULL) ? true : false;
165
166 lb = gp_cod_block_get_last_or_new(&dbi->list);
167
168 if (dbi->list.offset >= (COD_MAX_LINE_SYM * COD_LINE_SYM_SIZE)) {
169 lb = gp_cod_block_append(&dbi->list, gp_cod_block_new());
170 }
171
172 assert(ctx->fc != NULL);
173
174 smod_flag = (first_time) ? COD_LS_SMOD_FLAG_ALL :
175 ((state.cod.emitting != 0) ? COD_LS_SMOD_FLAG_C1 :
176 (COD_LS_SMOD_FLAG_C1 | COD_LS_SMOD_FLAG_D));
177
178 dbi->list.offset += gp_cod_put_line_number(&lb->block[dbi->list.offset], ctx->fc->id, ctx->line_number,
179 address, smod_flag);
180 }
181
182 /*------------------------------------------------------------------------------------------------*/
183
184 /* cod_write_symbols - Write the symbol table to the .cod file.
185 *
186 * This routine will read the symbol table that gpasm has created and convert it into
187 * a format suitable for .cod files. So far, only three variable types are supported:
188 * address, register and constants
189 *
190 */
191
192 void
cod_write_symbols(const symbol_t ** Symbol_list,size_t Num_symbols)193 cod_write_symbols(const symbol_t **Symbol_list, size_t Num_symbols)
194 {
195 size_t i;
196 unsigned int length;
197 unsigned int type;
198 const variable_t *var;
199 const char *name;
200 BlockList *sb;
201 gp_boolean truncated;
202
203 if ((Symbol_list == NULL) || (Num_symbols == 0)) {
204 return;
205 }
206
207 if (!state.cod.enabled) {
208 return;
209 }
210
211 sb = NULL;
212 for (i = 0; i < Num_symbols; i++) {
213 name = gp_sym_get_symbol_name(Symbol_list[i]);
214 var = (const variable_t *)gp_sym_get_symbol_annotation(Symbol_list[i]);
215 assert(var != NULL);
216
217 if (FlagIsSet(var->flags, VATRR_HAS_NO_VALUE)) {
218 msg_has_no_value("(.COD)", name);
219 }
220
221 length = gp_strlen_Plimit(name, COD_LSYMBOL_NAME_MAX_SIZE, &truncated);
222
223 if (truncated && (state.strict_level > 0)) {
224 /* This symbol name is too long. */
225 gpmsg_vwarning(GPW_STRING_TRUNCATE, "(.COD)", name, length);
226 }
227
228 /* If this symbol extends past the end of the cod block then write this block out. */
229
230 if ((sb == NULL) || ((main_dir->lsym.offset + length + COD_LSYMBOL_EXTRA) >= COD_BLOCK_SIZE)) {
231 sb = gp_cod_block_append(&main_dir->lsym, gp_cod_block_new());
232 }
233
234 switch (var->type) {
235 case VAL_CBLOCK:
236 type = COD_ST_C_SHORT; /* Byte Craft's nomenclature for a memory byte. */
237 break;
238
239 case VAL_ADDRESS:
240 type = COD_ST_ADDRESS;
241 break;
242
243 case VAL_CONSTANT:
244 case VAL_VARIABLE:
245 default:
246 type = COD_ST_CONSTANT;
247 }
248
249 main_dir->lsym.offset += gp_cod_put_long_symbol(&sb->block[main_dir->lsym.offset], name, var->value, type);
250 }
251 }
252
253 /*------------------------------------------------------------------------------------------------*/
254
255 void
cod_close_file(void)256 cod_close_file(void)
257 {
258 unsigned int length;
259 gp_boolean truncated;
260 const char *name;
261
262 if (!state.cod.enabled) {
263 return;
264 }
265
266 name = gp_processor_name(state.processor, 2);
267 /* The processor is unknown if not defined in command line at cod_init() call
268 so it should be set here. */
269 length = gp_Pstr_from_str(&main_dir->dir[COD_DIR_PROCESSOR], COD_DIR_PROCESSOR_SIZE, name, &truncated);
270
271 if (truncated && (state.strict_level > 0)) {
272 gpmsg_vwarning(GPW_STRING_TRUNCATE, "(.COD)", name, length);
273 }
274
275 _write_source_file_block();
276 gp_cod_write_code(state.device.class, state.i_memory, main_dir);
277 gp_cod_enumerate_directory(main_dir);
278 gp_cod_write_directory(state.cod.f, main_dir);
279 gp_cod_free_directory(main_dir);
280 fclose(state.cod.f);
281
282 main_dir = NULL;
283 dbi = NULL;
284 _64k_base = 0;
285 }
286