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
61static FILE* F = 0; /* Output stream */
62static unsigned Col = 1; /* Current column */
63static unsigned Line = 0; /* Current line on page */
64static unsigned Page = 1; /* Current output page */
65
66static const char* SegmentName = 0; /* Name of current segment */
67
68
69
70/*****************************************************************************/
71/* Code */
72/*****************************************************************************/
73
74
75
76static 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
92void 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
113void 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
123void 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
136void 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
149void 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
168void 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
182void 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
211void 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
228void 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
249void 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
270void 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
291void 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
312void SeparatorLine (void)
313/* Print a separator line */
314{
315 if (Pass == PassCount && Comments >= 1) {
316 Output ("; ----------------------------------------------------------------------------");
317 LineFeed ();
318 }
319}
320
321
322
323void 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
342void 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
356void UserComment (const char* Comment)
357/* Output a comment line */
358{
359 Output ("; %s", Comment);
360 LineFeed ();
361}
362
363
364
365void 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
393void 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}
404