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&&currentPage->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