1/*****************************************************************************/
2/* */
3/* data.c */
4/* */
5/* Data 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/* da65 */
37#include "attrtab.h"
38#include "code.h"
39#include "error.h"
40#include "global.h"
41#include "labels.h"
42#include "output.h"
43#include "data.h"
44
45
46
47/*****************************************************************************/
48/* Code */
49/*****************************************************************************/
50
51
52
53static unsigned GetSpan (attr_t Style)
54/* Get the number of bytes for a given style */
55{
56 /* Get the number of bytes still available */
57 unsigned RemainingBytes = GetRemainingBytes ();
58
59 /* Count how many bytes are available. This number is limited by the
60 ** number of remaining bytes, a label, a segment change, or the end of
61 ** the given Style attribute.
62 */
63 unsigned Count = 1;
64 while (Count < RemainingBytes) {
65 attr_t Attr;
66 if (MustDefLabel(PC+Count)) {
67 break;
68 }
69 Attr = GetAttr (PC+Count);
70 if ((Attr & atStyleMask) != Style) {
71 break;
72 }
73 if ((Attr & (atSegmentStart | atSegmentEnd))) {
74 break;
75 }
76 ++Count;
77 }
78
79 /* Return the number of bytes */
80 return Count;
81}
82
83
84
85static unsigned DoTable (attr_t Style, unsigned MemberSize, void (*TableFunc) (unsigned))
86/* Output a table of bytes */
87{
88 unsigned BytesLeft;
89
90 /* Count how many bytes may be output. */
91 unsigned Count = GetSpan (Style);
92
93 /* If the count is less than the member size, print a row of Count data
94 ** bytes. We assume here that there is no member with a size that is less
95 ** than BytesPerLine.
96 */
97 if (Count < MemberSize) {
98 DataByteLine (Count);
99 PC += Count;
100 return Count;
101 }
102
103 /* Make Count an even number of multiples of MemberSize */
104 Count &= ~(MemberSize-1);
105
106 /* Output as many data bytes lines as needed */
107 BytesLeft = Count;
108 while (BytesLeft > 0) {
109
110 /* Calculate the number of bytes for the next line */
111 unsigned Chunk = (BytesLeft > BytesPerLine)? BytesPerLine : BytesLeft;
112
113 /* Output a line with these bytes */
114 TableFunc (Chunk);
115
116 /* Next line */
117 BytesLeft -= Chunk;
118 PC += Chunk;
119 }
120
121 /* If the next line is not the same style, add a separator */
122 if (CodeLeft() && GetStyleAttr (PC) != Style) {
123 SeparatorLine ();
124 }
125
126 /* Return the number of bytes output */
127 return Count;
128}
129
130
131
132unsigned ByteTable (void)
133/* Output a table of bytes */
134{
135 /* Call the low level function */
136 return DoTable (atByteTab, 1, DataByteLine);
137}
138
139
140
141unsigned DByteTable (void)
142/* Output a table of dbytes */
143{
144 /* Call the low level function */
145 return DoTable (atDByteTab, 2, DataDByteLine);
146}
147
148
149
150unsigned WordTable (void)
151/* Output a table of words */
152{
153 /* Call the low level function */
154 return DoTable (atWordTab, 2, DataWordLine);
155}
156
157
158
159unsigned DWordTable (void)
160/* Output a table of double words */
161{
162 /* Call the low level function */
163 return DoTable (atDWordTab, 4, DataDWordLine);
164}
165
166
167
168unsigned AddrTable (void)
169/* Output a table of addresses */
170{
171 unsigned long BytesLeft = GetRemainingBytes ();
172 unsigned long Start = PC;
173
174 /* Loop while table bytes left and we don't need to create a label at the
175 ** current position.
176 */
177 while (BytesLeft && GetStyleAttr (PC) == atAddrTab) {
178
179 unsigned Addr;
180
181 /* If just one byte is left, define it and bail out */
182 if (BytesLeft == 1 || GetStyleAttr (PC+1) != atAddrTab) {
183 DataByteLine (1);
184 ++PC;
185 break;
186 }
187
188 /* More than one byte left. Define a forward label if necessary */
189 ForwardLabel (1);
190
191 /* Now get the address from the PC */
192 Addr = GetCodeWord (PC);
193
194 /* In pass 1, define a label, in pass 2 output the line */
195 if (Pass == 1) {
196 if (!HaveLabel (Addr)) {
197 AddIntLabel (Addr);
198 }
199 } else {
200 const char* Label = GetLabel (Addr, PC);
201 if (Label == 0) {
202 /* OOPS! Should not happen */
203 Internal ("OOPS - Label for address 0x%06X disappeard!", Addr);
204 }
205 Indent (MCol);
206 Output (".addr");
207 Indent (ACol);
208 Output ("%s", Label);
209 LineComment (PC, 2);
210 LineFeed ();
211 }
212
213 /* Next table entry */
214 PC += 2;
215 BytesLeft -= 2;
216
217 /* If we must define a label here, bail out */
218 if (BytesLeft && MustDefLabel (PC)) {
219 break;
220 }
221 }
222
223 /* If the next line is not an address table line, add a separator */
224 if (CodeLeft() && GetStyleAttr (PC) != atAddrTab) {
225 SeparatorLine ();
226 }
227
228 /* Return the number of bytes output */
229 return PC - Start;
230}
231
232
233
234unsigned RtsTable (void)
235/* Output a table of RTS addresses (address - 1) */
236{
237 unsigned long BytesLeft = GetRemainingBytes ();
238 unsigned long Start = PC;
239
240 /* Loop while table bytes left and we don't need to create a label at the
241 ** current position.
242 */
243 while (BytesLeft && GetStyleAttr (PC) == atRtsTab) {
244
245 unsigned Addr;
246
247 /* If just one byte is left, define it and bail out */
248 if (BytesLeft == 1 || GetStyleAttr (PC+1) != atRtsTab) {
249 DataByteLine (1);
250 ++PC;
251 break;
252 }
253
254 /* More than one byte left. Define a forward label if necessary */
255 ForwardLabel (1);
256
257 /* Now get the address from the PC */
258 Addr = (GetCodeWord (PC) + 1) & 0xFFFF;
259
260 /* In pass 1, define a label, in pass 2 output the line */
261 if (Pass == 1) {
262 if (!HaveLabel (Addr)) {
263 AddIntLabel (Addr);
264 }
265 } else {
266 const char* Label = GetLabel (Addr, PC);
267 if (Label == 0) {
268 /* OOPS! Should not happen */
269 Internal ("OOPS - Label for address 0x%06X disappeard!", Addr);
270 }
271 Indent (MCol);
272 Output (".word");
273 Indent (ACol);
274 Output ("%s-1", Label);
275 LineComment (PC, 2);
276 LineFeed ();
277 }
278
279 /* Next table entry */
280 PC += 2;
281 BytesLeft -= 2;
282
283 /* If we must define a label here, bail out */
284 if (BytesLeft && MustDefLabel (PC)) {
285 break;
286 }
287 }
288
289 /* If the next line is not a return address table line, add a separator */
290 if (CodeLeft() && GetStyleAttr (PC) != atRtsTab) {
291 SeparatorLine ();
292 }
293
294 /* Return the number of bytes output */
295 return PC - Start;
296}
297
298
299
300unsigned TextTable (void)
301/* Output a table of text messages */
302{
303 /* Count how many bytes may be output. */
304 unsigned ByteCount = GetSpan (atTextTab);
305
306 /* Output as many data bytes lines as needed. */
307 unsigned BytesLeft = ByteCount;
308 while (BytesLeft > 0) {
309
310 unsigned I;
311
312 /* Count the number of characters that can be output as such */
313 unsigned Count = 0;
314 while (Count < BytesLeft && Count < BytesPerLine*4-1) {
315 unsigned char C = GetCodeByte (PC + Count);
316 if (C >= 0x20 && C <= 0x7E && C != '\"') {
317 ++Count;
318 } else {
319 break;
320 }
321 }
322
323 /* If we have text, output it */
324 if (Count > 0) {
325 unsigned CBytes;
326 Indent (MCol);
327 Output (".byte");
328 Indent (ACol);
329 Output ("\"");
330 for (I = 0; I < Count; ++I) {
331 Output ("%c", GetCodeByte (PC+I));
332 }
333 Output ("\"");
334 CBytes = Count;
335 while (CBytes > 0) {
336 unsigned Chunk = CBytes;
337 if (Chunk > BytesPerLine) {
338 Chunk = BytesPerLine;
339 }
340 LineComment (PC, Chunk);
341 LineFeed ();
342 CBytes -= Chunk;
343 PC += Chunk;
344 }
345 BytesLeft -= Count;
346 }
347
348 /* Count the number of bytes that must be output as bytes */
349 Count = 0;
350 while (Count < BytesLeft && Count < BytesPerLine) {
351 unsigned char C = GetCodeByte (PC + Count);
352 if (C < 0x20 || C > 0x7E || C == '\"') {
353 ++Count;
354 } else {
355 break;
356 }
357 }
358
359 /* If we have raw output bytes, print them */
360 if (Count > 0) {
361 DataByteLine (Count);
362 PC += Count;
363 BytesLeft -= Count;
364 }
365
366 }
367
368 /* If the next line is not a byte table line, add a separator */
369 if (CodeLeft() && GetStyleAttr (PC) != atTextTab) {
370 SeparatorLine ();
371 }
372
373 /* Return the number of bytes output */
374 return ByteCount;
375}
376