]> git.sur5r.net Git - cc65/blob - src/sp65/asm.c
Changed most "backticks" (grave accents) into apostrophes.
[cc65] / src / sp65 / asm.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                   asm.c                                   */
4 /*                                                                           */
5 /*          Assembler output for the sp65 sprite and bitmap utility          */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2012,      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 <errno.h>
37 #include <stdio.h>
38 #include <string.h>
39
40 /* common */
41 #include "chartype.h"
42 #include "check.h"
43 #include "cmdline.h"
44 #include "version.h"
45
46 /* sp65 */
47 #include "attr.h"
48 #include "asm.h"
49 #include "error.h"
50
51
52
53 /*****************************************************************************/
54 /*                                   Code                                    */
55 /*****************************************************************************/
56
57
58
59 static int ValidIdentifier (const char* L)
60 /* Check an assembler label for validity */
61 {
62     /* Must begin with underscore or alphabetic character */
63     if (*L != '_' && !IsAlpha (*L)) {
64         return 0;
65     }
66     ++L;
67
68     /* Remainder must be as above plus digits */
69     while (*L) {
70         if (*L != '_' && !IsAlNum (*L)) {
71             return 0;
72         }
73         ++L;
74     }
75
76     /* Ok */
77     return 1;
78 }
79
80
81
82 static unsigned GetBytesPerLine (const Collection* A)
83 /* Return the number of bytes per line from the attribute collection A */
84 {
85     char        C;
86     unsigned    BytesPerLine = 16;
87
88     /* Check for a bytesperline attribute */
89     const char* V = GetAttrVal (A, "bytesperline");
90     if ((V && sscanf (V, "%u%c", &BytesPerLine, &C) != 1) ||
91         (BytesPerLine < 1 || BytesPerLine > 64)) {
92         Error ("Invalid value for attribute 'bytesperline'");
93     }
94     return BytesPerLine;
95 }
96
97
98
99 static unsigned GetBase (const Collection* A)
100 /* Return the number base from the attribute collection A */
101 {
102     char        C;
103     unsigned    Base = 16;
104
105     /* Check for a base attribute */
106     const char* V = GetAttrVal (A, "base");
107     if ((V && sscanf (V, "%u%c", &Base, &C) != 1) ||
108         (Base != 2 && Base != 10 && Base != 16)) {
109         Error ("Invalid value for attribute 'base'");
110     }
111     return Base;
112 }
113
114
115
116 static const char* GetIdentifier (const Collection* A)
117 /* Return the label identifier from the attribute collection A */
118 {
119     /* Check for a ident attribute */
120     const char* Ident = GetAttrVal (A, "ident");
121     if (Ident && !ValidIdentifier (Ident)) {
122         Error ("Invalid value for attribute 'ident'");
123     }
124     return Ident;
125 }
126
127
128
129 void WriteAsmFile (const StrBuf* Data, const Collection* A, const Bitmap* B)
130 /* Write the contents of Data to the given file in assembler (ca65) format */
131 {
132     FILE*       F;
133     const char* D;
134     unsigned    Size;
135
136
137     /* Get the name of the image */
138     const StrBuf* S = GetBitmapName (B);
139
140     /* Get the file name */
141     const char* Name = NeedAttrVal (A, "name", "write");
142
143     /* Check the number of bytes per line */
144     unsigned BytesPerLine = GetBytesPerLine (A);
145
146     /* Get the number base */
147     unsigned Base = GetBase (A);
148
149     /* Get the identifier */
150     const char* Ident = GetIdentifier (A);
151
152     /* Open the output file */
153     F = fopen (Name, "w");
154     if (F == 0) {
155         Error ("Cannot open output file '%s': %s", Name, strerror (errno));
156     }
157
158     /* Write a readable header */
159     fprintf (F,
160              ";\n"
161              "; This file was generated by %s %s from\n"
162              "; %.*s (%ux%u, %u colors%s)\n"
163              ";\n"
164              "\n",
165              ProgName,
166              GetVersionAsString (),
167              SB_GetLen (S), SB_GetConstBuf (S),
168              GetBitmapWidth (B), GetBitmapHeight (B),
169              GetBitmapColors (B),
170              BitmapIsIndexed (B)? ", indexed" : "");
171
172     /* If we have an assembler label, output that */
173     if (Ident) {
174         fprintf (F,
175                  ".proc   %s\n"
176                  "        COLORS = %u\n"
177                  "        WIDTH  = %u\n"
178                  "        HEIGHT = %u\n",
179                  Ident,
180                  GetBitmapColors (B),
181                  GetBitmapWidth (B),
182                  GetBitmapHeight (B));
183     }
184
185     /* Write the data */
186     D    = SB_GetConstBuf (Data);
187     Size = SB_GetLen (Data);
188     while (Size) {
189
190         unsigned I;
191
192         /* Output one line */
193         unsigned Chunk = Size;
194         if (Chunk > BytesPerLine) {
195             Chunk = BytesPerLine;
196         }
197         fputs ("        .byte   ", F);
198         for (I = 0; I < Chunk; ++I) {
199             unsigned char V = *D++;
200             if (I > 0) {
201                 fputc (',', F);
202             }
203             switch (Base) {
204                 case 2:
205                     fprintf (F, "%%%u%u%u%u%u%u%u%u",
206                              (V >> 7) & 0x01, (V >> 6) & 0x01,
207                              (V >> 5) & 0x01, (V >> 4) & 0x01,
208                              (V >> 3) & 0x01, (V >> 2) & 0x01,
209                              (V >> 1) & 0x01, (V >> 0) & 0x01);
210                     break;
211
212                 case 10:
213                     fprintf (F, "%u", V);
214                     break;
215
216                 case 16:
217                     fprintf (F, "$%02X", V);
218                     break;
219
220             }
221         }
222         fputc ('\n', F);
223
224         /* Bump the counters */
225         Size -= Chunk;
226     }
227
228     /* Terminate the .proc if we had an identifier */
229     if (Ident) {
230         fputs (".endproc\n", F);
231     }
232
233     /* Add an empty line at the end */
234     fputc ('\n', F);
235
236     /* Close the file */
237     if (fclose (F) != 0) {
238         Error ("Error closing output file '%s': %s", Name, strerror (errno));
239     }
240 }