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 | |
53 | static 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 | |
85 | static 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 | |
132 | unsigned 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 | |
141 | unsigned 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 | |
150 | unsigned 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 | |
159 | unsigned 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 | |
168 | unsigned 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 | |
234 | unsigned 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 | |
300 | unsigned 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 | |