1 // Copyright (C) 1999-2012 Core Technologies.
2 //
3 // This file is part of tpasm.
4 //
5 // tpasm is free software; you can redistribute it and/or modify
6 // it under the terms of the tpasm LICENSE AGREEMENT.
7 //
8 // tpasm is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // tpasm LICENSE AGREEMENT for more details.
12 //
13 // You should have received a copy of the tpasm LICENSE AGREEMENT
14 // along with tpasm; see the file "LICENSE.TXT".
15
16
17 // Handle creation and manipulation of segments
18
19 #include "include.h"
20
21 static SYM_TABLE
22 *segmentSymbols; // segment symbol list is kept here
23
FindCodePage(SEGMENT_RECORD * segment,unsigned int address)24 static CODE_PAGE *FindCodePage(SEGMENT_RECORD *segment,unsigned int address)
25 // find the code page of address, or the one immediately before it in the linked
26 // list of code pages hanging off segment
27 // NOTE: if the address is earlier than any code page within segment,
28 // NULL will be returned
29 // NOTE: this should probably be made faster
30 {
31 CODE_PAGE
32 *currentPage,
33 *bestPage;
34
35 bestPage=NULL;
36 currentPage=segment->firstPage;
37
38 if(segment->pageCache&&segment->pageCache->address<=address)
39 {
40 currentPage=segment->firstPage;
41 }
42
43 while(currentPage&¤tPage->address<=address)
44 {
45 bestPage=currentPage;
46 currentPage=currentPage->next;
47 }
48 segment->pageCache=bestPage;
49 return(bestPage);
50 }
51
DestroyCodePage(SEGMENT_RECORD * segment,CODE_PAGE * page)52 static void DestroyCodePage(SEGMENT_RECORD *segment,CODE_PAGE *page)
53 // unlink page from segment, and destroy it
54 {
55 if(page->next)
56 {
57 page->next->previous=page->previous;
58 }
59 if(page->previous)
60 {
61 page->previous->next=page->next;
62 }
63 else
64 {
65 segment->firstPage=page->next;
66 }
67 if(segment->pageCache==page) // update the cache if needed
68 {
69 segment->pageCache=page->previous;
70 }
71 DisposePtr(page);
72 }
73
CreateCodePage(SEGMENT_RECORD * segment,CODE_PAGE * pageBefore)74 static CODE_PAGE *CreateCodePage(SEGMENT_RECORD *segment,CODE_PAGE *pageBefore)
75 // create a new code page
76 // link it to segment after pageBefore
77 // NOTE: pageBefore can be passed in as NULL to link it to the start of the
78 // segment
79 // NOTE: the code page's usage map is initialized to be completely unused
80 // NOTE: if this fails, it will return NULL
81 {
82 CODE_PAGE
83 *page;
84 int
85 i;
86
87 if((page=(CODE_PAGE *)NewPtr(sizeof(CODE_PAGE))))
88 {
89 for(i=0;i<32;i++)
90 {
91 page->usageMap[i]=0;
92 }
93 if(pageBefore)
94 {
95 page->next=pageBefore->next;
96 page->previous=pageBefore;
97 pageBefore->next=page;
98 }
99 else
100 {
101 if((page->next=segment->firstPage))
102 {
103 page->next->previous=page;
104 }
105 page->previous=NULL;
106 segment->firstPage=page;
107 }
108 return(page);
109 }
110 return(NULL);
111 }
112
AddBytesToSegment(SEGMENT_RECORD * segment,unsigned int address,unsigned char * bytes,unsigned int numBytes)113 bool AddBytesToSegment(SEGMENT_RECORD *segment,unsigned int address,unsigned char *bytes,unsigned int numBytes)
114 // add bytes to segment at address
115 // if there is a problem, report it, and return false
116 // NOTE: this manages creating code pages, and linking them to segment
117 // in the proper location.
118 {
119 CODE_PAGE
120 *page;
121 unsigned int
122 baseAddress;
123 unsigned int
124 index;
125 bool
126 fail;
127
128 fail=false;
129 while(numBytes&&!fail)
130 {
131 page=FindCodePage(segment,address); // get the nearest page to the one we want to write into
132 baseAddress=address&~0xFF; // mask off low part of address
133 if(!page||(page->address!=baseAddress)) // see if a new page needs to be created
134 {
135 if((page=CreateCodePage(segment,page)))
136 {
137 page->address=baseAddress; // set up the base address for this page
138 }
139 else
140 {
141 ReportComplaint(true,"Failed to create code page\n");
142 fail=true;
143 }
144 }
145 if(!fail) // make sure there's a good page to use
146 {
147 index=address&0xFF;
148 while(numBytes&&(index<0x100)) // copy bytes into the page
149 {
150 if(page->usageMap[index>>3]&(1<<(index&7)))
151 {
152 AssemblyComplaint(NULL,false,"Overwriting address 0x%08X in segment '%s'\n",address,STNodeName(segment->symbol));
153 }
154 page->usageMap[index>>3]|=(1<<(index&7)); // update the usage map
155 page->pageData[index]=*bytes; // drop the bytes into the page
156 bytes++;
157 index++;
158 address++;
159 numBytes--;
160 }
161 }
162 }
163 return(!fail);
164 }
165
AddSpaceToSegment(SEGMENT_RECORD * segment,unsigned int address,unsigned int numBytes)166 bool AddSpaceToSegment(SEGMENT_RECORD *segment,unsigned int address,unsigned int numBytes)
167 // add bytes of empty space to segment at address
168 // Call this in response to a DS (define space) command
169 {
170 if(segment->sawDS)
171 {
172 if(segment->minDS>address)
173 {
174 segment->minDS=address;
175 }
176 if(segment->maxDS<address+numBytes-1)
177 {
178 segment->maxDS=address+numBytes-1;
179 }
180 }
181 else
182 {
183 if(numBytes)
184 {
185 segment->sawDS=true;
186 segment->minDS=address;
187 segment->maxDS=address+numBytes-1;
188 }
189 }
190 return(true);
191 }
192
MatchSegment(const char * segment)193 SEGMENT_RECORD *MatchSegment(const char *segment)
194 // try to match segment against the list of segments which currently exist
195 {
196 void
197 *resultValue;
198
199 if((resultValue=STFindDataForName(segmentSymbols,segment)))
200 {
201 return((SEGMENT_RECORD *)resultValue);
202 }
203 return(NULL);
204 }
205
DestroySegment(SEGMENT_RECORD * segment)206 void DestroySegment(SEGMENT_RECORD *segment)
207 // remove segment from existence
208 {
209 while(segment->firstPage) // get rid of code page list
210 {
211 DestroyCodePage(segment,segment->firstPage);
212 }
213
214 STRemoveEntry(segmentSymbols,segment->symbol);
215
216 if(segment->next)
217 {
218 segment->next->previous=segment->previous;
219 }
220 else
221 {
222 segmentsTail=segment->previous;
223 }
224
225 if(segment->previous)
226 {
227 segment->previous->next=segment->next;
228 }
229 else
230 {
231 segmentsHead=segment->next;
232 }
233 DisposePtr(segment);
234 }
235
DestroySegments()236 void DestroySegments()
237 // remove all segments
238 {
239 while(segmentsHead)
240 {
241 DestroySegment(segmentsHead);
242 }
243 }
244
CreateSegment(const char * segmentName,bool generateOutput)245 SEGMENT_RECORD *CreateSegment(const char *segmentName,bool generateOutput)
246 // Create a segment record, link it into the end of the global list,
247 // create a symbol table entry for it
248 {
249 SEGMENT_RECORD
250 *record;
251
252 if((record=(SEGMENT_RECORD *)NewPtr(sizeof(SEGMENT_RECORD))))
253 {
254 record->generateOutput=generateOutput;
255 record->pageCache=NULL;
256 record->firstPage=NULL;
257 record->currentPC=0;
258 record->codeGenOffset=0;
259
260 record->sawDS=false;
261 record->minDS=0;
262 record->maxDS=0;
263
264 if((record->symbol=STAddEntryAtEnd(segmentSymbols,segmentName,record)))
265 {
266 if((record->previous=segmentsTail))
267 {
268 segmentsTail->next=record;
269 }
270 else
271 {
272 segmentsHead=record;
273 }
274 segmentsTail=record; // this record is the new tail
275 record->next=NULL; // no next for this one
276 return(record);
277 }
278 DisposePtr(record);
279 }
280 return(NULL);
281 }
282
GetSegmentMinMax(SEGMENT_RECORD * segment,unsigned int * minAddress,unsigned int * maxAddress)283 static void GetSegmentMinMax(SEGMENT_RECORD *segment,unsigned int *minAddress,unsigned int *maxAddress)
284 // Work out the minimum and maximum addresses occupied by segment
285 {
286 CODE_PAGE
287 *page;
288 int
289 i;
290
291 *minAddress=0;
292 *maxAddress=0;
293
294 if((page=segment->firstPage))
295 {
296 i=0;
297 while(i<256&&(page->usageMap[i>>3]&(1<<(i&7)))==0)
298 {
299 i++;
300 }
301 *minAddress=page->address+i;
302
303 while(page->next)
304 {
305 page=page->next;
306 }
307
308 i=255;
309 while(i>0&&(page->usageMap[i>>3]&(1<<(i&7)))==0)
310 {
311 i--;
312 }
313 *maxAddress=page->address+i;
314 }
315
316 if(segment->sawDS)
317 {
318 if((!segment->firstPage)||(segment->minDS<*minAddress))
319 {
320 *minAddress=segment->minDS;
321 }
322 if((!segment->firstPage)||(segment->maxDS>*maxAddress))
323 {
324 *maxAddress=segment->maxDS;
325 }
326 }
327 }
328
DumpSegmentListing(FILE * file,SEGMENT_RECORD * segment)329 static void DumpSegmentListing(FILE *file,SEGMENT_RECORD *segment)
330 // Create a listing of the given segment, and
331 // what memory ranges it spanned
332 {
333 unsigned int
334 minAddress,
335 maxAddress;
336
337 GetSegmentMinMax(segment,&minAddress,&maxAddress);
338 fprintf(file,"%08X %08X %s\n",minAddress,maxAddress,STNodeName(segment->symbol));
339 }
340
DumpSegmentsListing(FILE * file)341 void DumpSegmentsListing(FILE *file)
342 // Create a listing of which segments were specified, and
343 // what memory ranges they spanned
344 {
345 SEGMENT_RECORD
346 *segment;
347
348 fprintf(file,"Segment Listing\n");
349 fprintf(file,"MinAddr MaxAddr Segment\n");
350 fprintf(file,"-------- -------- -------\n");
351 segment=segmentsHead;
352 while(segment)
353 {
354 DumpSegmentListing(file,segment);
355 segment=segment->next;
356 }
357 }
358
UnInitSegments()359 void UnInitSegments()
360 // undo what InitSegments did
361 {
362 STDisposeSymbolTable(segmentSymbols);
363 }
364
InitSegments()365 bool InitSegments()
366 // initialize symbol table for segments
367 {
368 if((segmentSymbols=STNewSymbolTable(100)))
369 {
370 return(true);
371 }
372 return(false);
373 }
374