]> Shamusworld >> Repos - rmac/blob - listing.c
6502 mode: fix clearing of its RAM space with each .6502 invocation. Also fixed chptr...
[rmac] / listing.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // LISTING.C - Listing Output
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8 // --------------------------------------------------------------------------
9 // 0    0    1    1    2    2    3    3    4    4    5    5    6    6    7    7
10 // 012345678901234567890123456789012345678901234567890123456789012345678901234567
11 // filename....                         Reboot's Macro Assembler N.N.NN (Unknown)
12 // nnnnn  aaaaaaaa  dddddddddddddddddddd T source code
13 // nnnnn  aaaaaaaa  dddddddddddddddd
14 // nnnnn           =vvvvvvvv
15
16 #include "listing.h"
17 #include "version.h"
18 #include "token.h"
19 #include "procln.h"
20 #include "sect.h"
21 #include "error.h"
22
23 char * list_fname;                                      // Listing filename
24 uint8_t subttl[TITLESIZ];                       // Current subtitle
25 int listing;                                            // Listing level
26 int pagelen = 61;                                       // Lines on a page
27 int nlines;                                                     // #lines on page so far
28 LONG lsloc;                                                     // `sloc' at start of line
29
30 // Private
31 static int lcursect;                            // `cursect' at start of line
32 static int llineno;                                     // `curlineno' at start of line
33 static int pageno;                                      // Current page number
34 static int pagewidth;                           // #columns on a page
35 static int subflag;                                     // 0, don't do .eject on subttl (set 1)
36 static char lnimage[IMAGESIZ];          // Image of output line
37 static char title[TITLESIZ];            // Current title
38 static char datestr[20];                        // Current date dd-mon-yyyy
39 static char timestr[20];                        // Current time hh:mm:ss [am|pm]
40 static char buf[IMAGESIZ];                      // Buffer for numbers
41 static long unused;                                     // For supressing 'write' warnings
42
43 static char * month[16] = {
44         "",    "Jan", "Feb", "Mar",
45         "Apr", "May", "Jun", "Jul",
46         "Aug", "Sep", "Oct", "Nov",
47         "Dec", "",    "",    ""
48 };
49
50
51 //
52 // Eject the page, reset the line count and bump the page number
53 //
54 int eject(void)
55 {
56         if (listing > 0)
57         {
58                 println("\f");
59                 nlines = 0;
60         }
61
62         return 0;
63 }
64
65
66 //
67 // Return GEMDOS format date
68 //
69 VALUE dos_date(void)
70 {
71         VALUE v;
72         struct tm * tm;
73         time_t tloc;
74
75         time(&tloc);
76         tm = localtime(&tloc);
77         v = ((tm->tm_year - 80) << 9) | ((tm->tm_mon + 1) << 5) | tm->tm_mday;
78
79         return v;
80 }
81
82
83 //
84 // Return GEMDOS format time
85 //
86 VALUE dos_time(void)
87 {
88         VALUE v;
89         struct tm * tm;
90         time_t tloc;
91
92         time(&tloc);
93         tm = localtime(&tloc);
94         v = (tm->tm_hour << 11) | (tm->tm_min) << 5 | tm->tm_sec;
95
96         return v;
97 }
98
99
100 //
101 // Generate a time string
102 //
103 void time_string(char * buf, VALUE time)
104 {
105         int hour;
106         char * ampm;
107
108         hour = (time >> 11);
109
110         if (hour > 12)
111         {
112                 hour -= 12;
113                 ampm = "pm";
114         }
115         else
116                 ampm = "am";
117
118         sprintf(buf, "%d:%02d:%02d %s",
119                 hour, (int)((time >> 5) & 0x3F), (int)((time & 0x1F) << 1), ampm);
120 }
121
122
123 //
124 // Generate a date string
125 //
126 void date_string(char * buf, VALUE date)
127 {
128         sprintf(buf, "%d-%s-%d",
129                 (int)(date & 0x1F), month[(date >> 5) & 0xF], (int)((date >> 9) + 1980));
130 }
131
132
133 //
134 // Transform letters a-f in the address and data columns of the listing to
135 // uppercase. (People seem  to like uppercase hex better in assembly-language
136 // listings....)
137 //
138 void uc_ln(char * ln)
139 {
140         int i;
141         char j;
142
143         for(i=LOC_COL; i<SRC_COL; ++i)
144         {
145                 if ((j = ln[i]) >= 'a' && j <= 'f')
146                         ln[i] = (char)(j - 0x20);
147         }
148 }
149
150
151 //
152 // Fill region 'dest' with 'len' characters 'c' and null terminate the region
153 //
154 void lnfill(char * dest, int len, char chr)
155 {
156         while (len--)
157                 *dest++ = chr;
158
159         *dest = EOS;
160 }
161
162
163 //
164 // Create listing file with the appropriate name
165 //
166 void list_setup(void)
167 {
168         char fnbuf[FNSIZ];
169
170         strcpy(fnbuf, list_fname);
171
172         if (*fnbuf == EOS)
173         {
174                 strcpy(fnbuf, firstfname);
175                 fext(fnbuf, ".prn", 1);
176         }
177
178         list_fname = NULL;
179
180         if ((list_fd = open(fnbuf, _OPEN_FLAGS, _PERM_MODE)) < 0)
181                 cantcreat(fnbuf);
182 }
183
184
185 //
186 // Tag listing with a character, typically for errors or warnings
187 //
188 void taglist(char chr)
189 {
190         lnimage[TAG_COL + 1] = chr;
191 }
192
193
194 //
195 // Print a line to the listing file
196 //
197 void println(const char * ln)
198 {
199         unsigned int length;
200
201         //  Create listing file, if necessary
202         if (list_fname != NULL)
203                 list_setup();
204
205         length = strlen(ln);
206         unused = write(list_fd, ln, length);
207         unused = write(list_fd, "\n", 1L);
208 }
209
210
211 //
212 // Ship line 'ln' out; do page breaks and title stuff
213 //
214 void ship_ln(const char * ln)
215 {
216         // If listing level is <= 0, then don't print anything
217         if (listing <= 0)
218                 return;
219
220         // Notice bottom of page
221         if (nlines >= pagelen - BOT_MAR)
222                 eject();
223
224         // Print title, boilerplate, and subtitle at top of page
225         if (nlines == 0)
226         {
227                 pageno++;
228                 println("");
229                 date_string(datestr, dos_date());
230                 time_string(timestr, dos_time());
231                 sprintf(buf,
232                         "%-40s%-20s Page %-4d    %s %s        RMAC %01i.%01i.%02i (%s)",
233                         title, curfname, pageno, timestr, datestr, MAJOR, MINOR, PATCH,
234                         PLATFORM);
235                 println(buf);
236                 sprintf(buf, "%s", subttl);
237                 println(buf);
238                 println("");
239                 nlines = 4;
240         }
241
242         println(ln);
243         nlines++;
244 }
245
246
247 //
248 // Initialize listing generator
249 //
250 void InitListing(void)
251 {
252         extern VALUE dos_date(), dos_time();
253
254         subflag = 0;
255         pageno = 0;
256         nlines = 0;
257         pagelen = 61;
258         pagewidth = 132;
259         strcpy(title, "");
260         strcpy(subttl, "");
261         date_string(datestr, dos_date());
262         time_string(timestr, dos_time());
263 }
264
265
266 //
267 // Listing EOL
268 //
269 void listeol(void)
270 {
271         CHUNK * ch;
272         char * p;
273         int col;
274         LONG count;
275         int fixcount;
276
277         DEBUG printf("~list: lsloc=$%X sloc=$%X\n", lsloc, sloc);
278
279         if (lsloc != sloc)
280         {
281                 sprintf(buf, "%08X", lsloc);
282                 strncpy(lnimage + LOC_COL, buf, 8);
283         }
284
285         if (llineno != curlineno)
286         {
287                 sprintf(buf, "%5d", llineno);
288                 strncpy(lnimage + LN_COL, buf, 5);
289         }
290
291         // List bytes only when section stayed the same and the section is not a
292         // "no-data" (SBSS) section. An extra annoyance is caused by "ds.b" in a
293         // microprocessor mode, which prints out bytes of zero as if they had been
294         // deposited with dcb. The fix (kludge) is an extra variable which records
295         // the fact that a 'ds.x' directive generated all the data, and it
296         // shouldn't be listed
297         SaveSection();          // Update section variables
298
299         if (lcursect == cursect && (sect[lcursect].scattr & SBSS) == 0
300                 && lsloc != sloc && just_bss == 0)
301         {
302                 ch = sect[lcursect].sfcode;
303
304                 if (lcursect != M6502)
305         {
306                 for(; ch!=NULL; ch=ch->chnext)
307                 {
308                         if (lsloc >= ch->chloc && lsloc < (ch->chloc + ch->ch_size))
309                                 break;
310                 }
311         }
312
313                 // Fatal: Can't find chunk holding code
314                 if (ch == NULL)
315                 {
316 nochunk:
317                         interror(6);    // Can't find generated code in section
318                 }
319
320                 p =  ch->chptr + (lsloc - ch->chloc);
321                 col = DATA_COL;
322                 fixcount = 0;
323
324                 for(count=sloc-lsloc; count--; col+=2, ++lsloc)
325                 {
326                         if (col >= DATA_END)
327                         {
328                                 // Ship the line
329                                 col = DATA_COL;
330                                 uc_ln(lnimage);
331                                 ship_ln(lnimage);
332                                 lnfill(lnimage, SRC_COL, SPACE);        // Fill with spaces
333                                 sprintf(buf, "%08X", lsloc);
334                                 strncpy(lnimage + LOC_COL, buf, 8);
335                         }
336
337                         if (lcursect != M6502 &&
338                     lsloc >= (ch->chloc + ch->ch_size))
339                         {
340                                 if ((ch = ch->chnext) == NULL)
341                                         goto nochunk;
342
343                                 p = ch->chptr;
344                         }
345
346                         if (!fixcount)
347                                 fixcount = fixtest(lcursect, lsloc);
348
349                         if (fixcount)
350                         {
351                                 fixcount--;
352                                 strcpy(buf, "xx");
353                                 p++;            // Advance anyway
354                         }
355                         else
356                                 sprintf(buf, "%02x", *p++ & 0xff);
357
358                         strncpy(lnimage + col, buf, 2);
359                 }
360
361                 // Flush partial line
362                 if (col > DATA_COL)
363                 {
364                         uc_ln(lnimage);
365                         ship_ln(lnimage);
366                 }
367         }
368         else
369         {
370                 uc_ln(lnimage);
371                 ship_ln(lnimage);
372         }
373 }
374
375
376 //
377 // Copy current (saved) line to output buffer and tag it with a character
378 //
379 void lstout(char tag)
380 {
381         char * s;
382         char * d;
383
384         lsloc = sloc;
385         lcursect = cursect;
386         llineno = curlineno;
387
388         lnfill(lnimage, SRC_COL, SPACE);        // Fill with spaces
389         lnimage[TAG_COL] = tag;
390
391         // Copy line image and handle control characters
392         d = lnimage + SRC_COL;
393
394         for(s=lnbuf; *s; ++s)
395         {
396                 if (*s >= 0x20 || *s == '\t')
397                         *d++ = *s;
398                 else
399                 {
400                         *d++ = '^';
401                         *d++ = (char)(*s + 0x40);
402                 }
403         }
404
405         *d++ = EOS;
406 }
407
408
409 //
410 // Output a value to listing
411 //
412 int listvalue(VALUE v)
413 {
414         sprintf(buf, "=%08X", v);
415         strncpy(lnimage + DATA_COL - 1, buf, 9);
416         return 0;
417 }
418
419
420 /*
421  *  .subttl [-] "string"
422  *
423  *  Set subtitle;
424  *    o  leading '-' supresses page eject
425  *    o  don't .eject on first .subttl, but do so on all other ones,
426  *    o  arrange not to print the .subttl directive
427  *
428  */
429 int d_subttl(void)
430 {
431         int ejectok;
432         ejectok = 1;
433
434         if (*tok == '-')
435         {
436                 ejectok = 0;
437                 ++tok;
438         }
439
440         if (*tok != STRING)
441                 return error("missing string");
442
443 //      strcpy(subttl, (char *)tok[1]);
444         strcpy(subttl, string[tok[1]]);
445
446         tok += 2;
447
448         // Always eject on pages 2+
449         if (ejectok && (subflag || pageno > 1))
450                 eject();
451
452         subflag = 1;
453
454         return 0;
455 }
456
457
458 //
459 // Set title on titles not on the first page, do an eject and clobber the
460 // subtitle
461 //
462 int d_title(void)
463 {
464         if (*tok != STRING)
465                 return error("missing string");
466
467 //      strcpy(title, (char*)tok[1]);
468         strcpy(title, string[tok[1]]);
469         tok += 2;
470
471         if (pageno > 1)
472         {
473                 strcpy(subttl, "");
474                 eject();
475         }
476
477         return 0;
478 }
479