]> git.sur5r.net Git - cc65/blob - src/da65/output.c
Merge remote-tracking branch 'origin' into da65-synclines
[cc65] / src / da65 / output.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 output.c                                  */
4 /*                                                                           */
5 /*                       Disassembler output routines                        */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2014, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41
42 /* common */
43 #include "addrsize.h"
44 #include "cpu.h"
45 #include "version.h"
46
47 /* da65 */
48 #include "code.h"
49 #include "error.h"
50 #include "global.h"
51 #include "output.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 static FILE*    F       = 0;            /* Output stream */
62 static unsigned Col     = 1;            /* Current column */
63 static unsigned Line    = 0;            /* Current line on page */
64 static unsigned Page    = 1;            /* Current output page */
65
66 static const char* SegmentName = 0;     /* Name of current segment */
67
68
69
70 /*****************************************************************************/
71 /*                                   Code                                    */
72 /*****************************************************************************/
73
74
75
76 static void PageHeader (void)
77 /* Print a page header */
78 {
79     fprintf (F,
80              "; da65 V%s\n"
81              "; Created:    %s\n"
82              "; Input file: %s\n"
83              "; Page:       %u\n\n",
84              GetVersionAsString (),
85              Now,
86              InFile,
87              Page);
88 }
89
90
91
92 void OpenOutput (const char* Name)
93 /* Open the given file for output */
94 {
95     /* If we have a name given, open the output file, otherwise use stdout */
96     if (Name != 0) {
97         F = fopen (Name, "w");
98         if (F == 0) {
99             Error ("Cannot open `%s': %s", Name, strerror (errno));
100         }
101     } else {
102         F = stdout;
103     }
104
105     /* Output the header and initialize stuff */
106     PageHeader ();
107     Line = 5;
108     Col  = 1;
109 }
110
111
112
113 void CloseOutput (void)
114 /* Close the output file */
115 {
116     if (F != stdout && fclose (F) != 0) {
117         Error ("Error closing output file: %s", strerror (errno));
118     }
119 }
120
121
122
123 void Output (const char* Format, ...)
124 /* Write to the output file */
125 {
126     if (Pass == PassCount) {
127         va_list ap;
128         va_start (ap, Format);
129         Col += vfprintf (F, Format, ap);
130         va_end (ap);
131     }
132 }
133
134
135
136 void Indent (unsigned N)
137 /* Make sure the current line column is at position N (zero based) */
138 {
139     if (Pass == PassCount) {
140         while (Col < N) {
141             fputc (' ', F);
142             ++Col;
143         }
144     }
145 }
146
147
148
149 void LineFeed (void)
150 /* Add a linefeed to the output file */
151 {
152     if (Pass == PassCount) {
153         fputc ('\n', F);
154         if (PageLength > 0 && ++Line >= PageLength) {
155             if (FormFeeds) {
156                 fputc ('\f', F);
157             }
158             ++Page;
159             PageHeader ();
160             Line = 5;
161         }
162         Col = 1;
163     }
164 }
165
166
167
168 void DefLabel (const char* Name)
169 /* Define a label with the given name */
170 {
171     Output ("%s:", Name);
172     /* If the label is longer than the configured maximum, or if it runs into
173     ** the opcode column, start a new line.
174     */
175     if (Col > LBreak+2 || Col > MCol) {
176         LineFeed ();
177     }
178 }
179
180
181
182 void DefForward (const char* Name, const char* Comment, unsigned Offs)
183 /* Define a label as "* + x", where x is the offset relative to the
184 ** current PC.
185 */
186 {
187     if (Pass == PassCount) {
188         /* Flush existing output if necessary */
189         if (Col > 1) {
190             LineFeed ();
191         }
192
193         /* Output the forward definition */
194         Output ("%s", Name);
195         Indent (ACol);
196         if (UseHexOffs) {
197             Output (":= * + $%04X", Offs);
198         } else {
199             Output (":= * + %u", Offs);
200         }
201         if (Comment) {
202             Indent (CCol);
203             Output ("; %s", Comment);
204         }
205         LineFeed ();
206     }
207 }
208
209
210
211 void DefConst (const char* Name, const char* Comment, unsigned Addr)
212 /* Define an address constant */
213 {
214     if (Pass == PassCount) {
215         Output ("%s", Name);
216         Indent (ACol);
217         Output (":= $%04X", Addr);
218         if (Comment) {
219             Indent (CCol);
220             Output ("; %s", Comment);
221         }
222         LineFeed ();
223     }
224 }
225
226
227
228 void DataByteLine (unsigned ByteCount)
229 /* Output a line with bytes */
230 {
231     unsigned I;
232
233     Indent (MCol);
234     Output (".byte");
235     Indent (ACol);
236     for (I = 0; I < ByteCount; ++I) {
237         if (I > 0) {
238             Output (",$%02X", CodeBuf[PC+I]);
239         } else {
240             Output ("$%02X", CodeBuf[PC+I]);
241         }
242     }
243     LineComment (PC, ByteCount);
244     LineFeed ();
245 }
246
247
248
249 void DataDByteLine (unsigned ByteCount)
250 /* Output a line with dbytes */
251 {
252     unsigned I;
253
254     Indent (MCol);
255     Output (".dbyt");
256     Indent (ACol);
257     for (I = 0; I < ByteCount; I += 2) {
258         if (I > 0) {
259             Output (",$%04X", GetCodeDByte (PC+I));
260         } else {
261             Output ("$%04X", GetCodeDByte (PC+I));
262         }
263     }
264     LineComment (PC, ByteCount);
265     LineFeed ();
266 }
267
268
269
270 void DataWordLine (unsigned ByteCount)
271 /* Output a line with words */
272 {
273     unsigned I;
274
275     Indent (MCol);
276     Output (".word");
277     Indent (ACol);
278     for (I = 0; I < ByteCount; I += 2) {
279         if (I > 0) {
280             Output (",$%04X", GetCodeWord (PC+I));
281         } else {
282             Output ("$%04X", GetCodeWord (PC+I));
283         }
284     }
285     LineComment (PC, ByteCount);
286     LineFeed ();
287 }
288
289
290
291 void DataDWordLine (unsigned ByteCount)
292 /* Output a line with dwords */
293 {
294     unsigned I;
295
296     Indent (MCol);
297     Output (".dword");
298     Indent (ACol);
299     for (I = 0; I < ByteCount; I += 4) {
300         if (I > 0) {
301             Output (",$%08lX", GetCodeDWord (PC+I));
302         } else {
303             Output ("$%08lX", GetCodeDWord (PC+I));
304         }
305     }
306     LineComment (PC, ByteCount);
307     LineFeed ();
308 }
309
310
311
312 void SeparatorLine (void)
313 /* Print a separator line */
314 {
315     if (Pass == PassCount && Comments >= 1) {
316         Output ("; ----------------------------------------------------------------------------");
317         LineFeed ();
318     }
319 }
320
321
322
323 void StartSegment (const char* Name, unsigned AddrSize)
324 /* Start a segment */
325 {
326     if (Pass == PassCount) {
327         LineFeed ();
328         Output (".segment");
329         Indent (ACol);
330         SegmentName = Name;
331         Output ("\"%s\"", Name);
332         if (AddrSize != ADDR_SIZE_DEFAULT) {
333             Output (": %s", AddrSizeToStr (AddrSize));
334         }
335         LineFeed ();
336         LineFeed ();
337     }
338 }
339
340
341
342 void EndSegment (void)
343 /* End a segment */
344 {
345     LineFeed ();
346     Output ("; End of \"%s\" segment", SegmentName);
347     LineFeed ();
348     SeparatorLine ();
349     Output (".code");
350     LineFeed ();
351     LineFeed ();
352 }
353
354
355
356 void UserComment (const char* Comment)
357 /* Output a comment line */
358 {
359     Output ("; %s", Comment);
360     LineFeed ();
361 }
362
363
364
365 void LineComment (unsigned PC, unsigned Count)
366 /* Add a line comment with the PC and data bytes */
367 {
368     unsigned I;
369
370     if (Pass == PassCount && Comments >= 2) {
371         Indent (CCol);
372         Output ("; %04X", PC);
373         if (Comments >= 3) {
374             for (I = 0; I < Count; ++I) {
375                 Output (" %02X", CodeBuf [PC+I]);
376             }
377             if (Comments >= 4) {
378                 Indent (TCol);
379                 for (I = 0; I < Count; ++I) {
380                     unsigned char C = CodeBuf [PC+I];
381                     if (!isprint (C)) {
382                         C = '.';
383                     }
384                     Output ("%c", C);
385                 }
386             }
387         }
388     }
389 }
390
391
392
393 void OutputSettings (void)
394 /* Output CPU and other settings */
395 {
396     LineFeed ();
397     Indent (MCol);
398     Output (".setcpu");
399     Indent (ACol);
400     Output ("\"%s\"", CPUNames[CPU]);
401     LineFeed ();
402     LineFeed ();
403 }