@@ -0,0 +1,560 @@ |
|
|
1 |
program rgb2gbdk; |
|
|
2 |
|
|
|
3 |
{$mode objfpc}{$H+} |
|
|
4 |
|
|
|
5 |
uses |
|
|
6 |
{$IFDEF UNIX}{$IFDEF UseCThreads} |
|
|
7 |
cthreads, |
|
|
8 |
{$ENDIF}{$ENDIF} |
|
|
9 |
Classes, SysUtils, strutils, math |
|
|
10 |
{ you can add units after this }; |
|
|
11 |
|
|
|
12 |
type |
|
|
13 |
TRSymbol = packed record |
|
|
14 |
ID: Integer; |
|
|
15 |
Name: String; |
|
|
16 |
SymType: Byte; |
|
|
17 |
|
|
|
18 |
No: Integer; |
|
|
19 |
|
|
|
20 |
FileName: String; |
|
|
21 |
LineNum, SectionID, Value: LongInt; |
|
|
22 |
end; |
|
|
23 |
|
|
|
24 |
TRPatch = packed record |
|
|
25 |
SourceFile: String; |
|
|
26 |
Offset: LongInt; |
|
|
27 |
PCSectionID: LongInt; |
|
|
28 |
PCOffset: LongInt; |
|
|
29 |
PatchType: Byte; |
|
|
30 |
RPNSize: LongInt; |
|
|
31 |
RPN: array of Byte; |
|
|
32 |
end; |
|
|
33 |
|
|
|
34 |
TRSection = packed record |
|
|
35 |
ID: Integer; |
|
|
36 |
Name: String; |
|
|
37 |
Size: LongInt; |
|
|
38 |
SectType: Byte; |
|
|
39 |
Org: LongInt; |
|
|
40 |
Bank: LongInt; |
|
|
41 |
Align: Byte; |
|
|
42 |
Ofs: LongInt; |
|
|
43 |
|
|
|
44 |
Data: array of Byte; |
|
|
45 |
NumberOfPatches: LongInt; |
|
|
46 |
Patches: array of TRPatch; |
|
|
47 |
end; |
|
|
48 |
|
|
|
49 |
TRObj = packed record |
|
|
50 |
ID: array[0..3] of AnsiChar; |
|
|
51 |
RevisionNumber: LongInt; |
|
|
52 |
NumberOfSymbols: LongInt; |
|
|
53 |
NumberOfSections: LongInt; |
|
|
54 |
|
|
|
55 |
Symbols: array of TRSymbol; |
|
|
56 |
Sections: array of TRSection; |
|
|
57 |
end; |
|
|
58 |
|
|
|
59 |
TRPNTag = ( |
|
|
60 |
rpnPlus, |
|
|
61 |
rpnMinus, |
|
|
62 |
rpnTimes, |
|
|
63 |
rpnDiv, |
|
|
64 |
rpnMod, |
|
|
65 |
rpnNegate, |
|
|
66 |
rpnOr, |
|
|
67 |
rpnAnd, |
|
|
68 |
rpnXor, |
|
|
69 |
rpnComplement, |
|
|
70 |
rpnBoolAnd, |
|
|
71 |
rpnBoolOr, |
|
|
72 |
rpnBoolNeg, |
|
|
73 |
rpnEqual, |
|
|
74 |
rpnNotEqual, |
|
|
75 |
rpnGreater, |
|
|
76 |
rpnLess, |
|
|
77 |
rpnGreaterEqual, |
|
|
78 |
rpnLessEqual, |
|
|
79 |
rpnShl, |
|
|
80 |
rpnShr, |
|
|
81 |
rpnBankSymbol, |
|
|
82 |
rpnBankSection, |
|
|
83 |
rpnCurrentBank, |
|
|
84 |
rpnHramCheck, |
|
|
85 |
rpnRstCheck, |
|
|
86 |
rpnInteger, |
|
|
87 |
rpnSymbol); |
|
|
88 |
|
|
|
89 |
TRPNNode = record |
|
|
90 |
case Tag: TRPNTag of |
|
|
91 |
rpnBankSymbol: (BankSymbol: Integer); |
|
|
92 |
rpnBankSection: (BankSection: Integer); |
|
|
93 |
rpnInteger: (IntValue: Integer); |
|
|
94 |
rpnSymbol: (SymbolID: Integer); |
|
|
95 |
end; |
|
|
96 |
TRPN = array of TRPNNode; |
|
|
97 |
|
|
|
98 |
type |
|
|
99 |
TObjFileStream = class(TFileStream) |
|
|
100 |
function ReadNullTerm: string; virtual; |
|
|
101 |
end; |
|
|
102 |
|
|
|
103 |
function TObjFileStream.ReadNullTerm: string; |
|
|
104 |
var B: Byte; |
|
|
105 |
begin |
|
|
106 |
Result := ''; |
|
|
107 |
while True do begin |
|
|
108 |
B := ReadByte; |
|
|
109 |
if B = 0 then Exit; |
|
|
110 |
Result += Chr(B); |
|
|
111 |
end |
|
|
112 |
end; |
|
|
113 |
|
|
|
114 |
const |
|
|
115 |
WRAM0 = 0; |
|
|
116 |
VRAM = 1; |
|
|
117 |
ROMX = 2; |
|
|
118 |
ROM0 = 3; |
|
|
119 |
HRAM = 4; |
|
|
120 |
WRAMX = 5; |
|
|
121 |
SRAM = 6; |
|
|
122 |
OAM = 7; |
|
|
123 |
|
|
|
124 |
const |
|
|
125 |
SYM_LOCAL = 0; |
|
|
126 |
SYM_IMPORT = 1; |
|
|
127 |
SYM_EXPORT = 2; |
|
|
128 |
|
|
|
129 |
const |
|
|
130 |
PATCH_BYTE = 0; |
|
|
131 |
PATCH_LE_WORD = 1; |
|
|
132 |
PATCH_LE_LONG = 2; |
|
|
133 |
PATCH_JR = 3; |
|
|
134 |
|
|
|
135 |
procedure Die(const S: String); overload; |
|
|
136 |
begin WriteLn('ERROR:', S); Halt; end; |
|
|
137 |
procedure Die(const fmt: String; const params: array of const); overload; |
|
|
138 |
begin Die(format(fmt, params)); end; |
|
|
139 |
|
|
|
140 |
function ReadObjFile(const afilename: string): TRObj; |
|
|
141 |
const Sign : array[0..3] of AnsiChar = 'RGB9'; |
|
|
142 |
var I, J: Integer; |
|
|
143 |
begin |
|
|
144 |
with TObjFileStream.Create(afilename, fmOpenRead) do try |
|
|
145 |
Read(Result, SizeOf(TRObj) - SizeOf(Result.Symbols) - SizeOf(Result.Sections)); |
|
|
146 |
if not (CompareMem(@Result.ID, @Sign, sizeof(Result.ID)) and (Result.RevisionNumber = 5)) then Die('Unsupported object file version!'); |
|
|
147 |
SetLength(Result.Symbols, Result.NumberOfSymbols); |
|
|
148 |
SetLength(Result.Sections, Result.NumberOfSections); |
|
|
149 |
|
|
|
150 |
for I := 0 to Result.NumberOfSymbols-1 do begin |
|
|
151 |
Result.Symbols[I] := Default(TRSymbol); |
|
|
152 |
with Result.Symbols[I] do begin |
|
|
153 |
ID := I; |
|
|
154 |
Name := ReadNullTerm; |
|
|
155 |
Read(SymType, 1); |
|
|
156 |
if ((SymType and $7F) <> SYM_IMPORT) then begin |
|
|
157 |
FileName := ReadNullTerm; |
|
|
158 |
Read(LineNum, SizeOf(LineNum)); |
|
|
159 |
Read(SectionID, SizeOf(SectionID)); |
|
|
160 |
Read(Value, SizeOf(Value)); |
|
|
161 |
end; |
|
|
162 |
end; |
|
|
163 |
end; |
|
|
164 |
|
|
|
165 |
for I := 0 to Result.NumberOfSections-1 do begin |
|
|
166 |
Result.Sections[I] := Default(TRSection); |
|
|
167 |
with Result.Sections[I] do begin |
|
|
168 |
ID := I; |
|
|
169 |
Name := ReadNullTerm; |
|
|
170 |
Read(Size, SizeOf(Size)); |
|
|
171 |
Read(SectType, SizeOf(SectType)); |
|
|
172 |
Read(Org, SizeOf(Org)); |
|
|
173 |
Read(Bank, SizeOf(Bank)); |
|
|
174 |
Read(Align, SizeOf(Align)); |
|
|
175 |
Read(Ofs, SizeOf(Ofs)); |
|
|
176 |
if ((SectType = ROMX) or (SectType = ROM0)) then begin |
|
|
177 |
SetLength(Data, Size); |
|
|
178 |
Read(Data[0], Size); |
|
|
179 |
Read(NumberOfPatches, SizeOf(NumberOfPatches)); |
|
|
180 |
SetLength(Patches, NumberOfPatches); |
|
|
181 |
end; |
|
|
182 |
end; |
|
|
183 |
|
|
|
184 |
for J := 0 to Result.Sections[I].NumberOfPatches-1 do begin |
|
|
185 |
with Result.Sections[I].Patches[J] do begin |
|
|
186 |
SourceFile := ReadNullTerm; |
|
|
187 |
Read(Offset, SizeOf(Offset)); |
|
|
188 |
Read(PCSectionID, SizeOf(PCSectionID)); |
|
|
189 |
Read(PCOffset, SizeOf(PCOffset)); |
|
|
190 |
Read(PatchType, SizeOf(PatchType)); |
|
|
191 |
Read(RPNSize, SizeOf(RPNSize)); |
|
|
192 |
SetLength(RPN, RPNSize); |
|
|
193 |
Read(RPN[0], RPNSize); |
|
|
194 |
end; |
|
|
195 |
end; |
|
|
196 |
end; |
|
|
197 |
finally free; end; |
|
|
198 |
end; |
|
|
199 |
|
|
|
200 |
function RPNToString(const RPN: array of Byte; const Syms: array of TRSymbol): String; |
|
|
201 |
var |
|
|
202 |
I: Integer; |
|
|
203 |
|
|
|
204 |
function ReadLong: LongWord; |
|
|
205 |
begin |
|
|
206 |
Inc(I); |
|
|
207 |
Result := RPN[I]; |
|
|
208 |
Inc(I); |
|
|
209 |
Result := (Result shl 8) or RPN[I]; |
|
|
210 |
Inc(I); |
|
|
211 |
Result := (Result shl 8) or RPN[I]; |
|
|
212 |
Inc(I); |
|
|
213 |
Result := (Result shl 8) or RPN[I]; |
|
|
214 |
Inc(I); |
|
|
215 |
Result := SwapEndian(Result); |
|
|
216 |
end; |
|
|
217 |
|
|
|
218 |
begin |
|
|
219 |
Result := ''; |
|
|
220 |
|
|
|
221 |
I := Low(RPN); |
|
|
222 |
while I <= High(RPN) do begin |
|
|
223 |
case RPN[I] of |
|
|
224 |
$00: begin Result += '+ '; Inc(I); end; |
|
|
225 |
$01: begin Result += '- '; Inc(I); end; |
|
|
226 |
$02: begin Result += '* '; Inc(I); end; |
|
|
227 |
$03: begin Result += '/ '; Inc(I); end; |
|
|
228 |
$04: begin Result += '% '; Inc(I); end; |
|
|
229 |
$05: begin Result += 'neg '; Inc(I); end; |
|
|
230 |
$10: begin Result += '| '; Inc(I); end; |
|
|
231 |
$11: begin Result += '& '; Inc(I); end; |
|
|
232 |
$12: begin Result += '^ '; Inc(I); end; |
|
|
233 |
$13: begin Result += '~ '; Inc(I); end; |
|
|
234 |
$21: begin Result += '&& '; Inc(I); end; |
|
|
235 |
$22: begin Result += '|| '; Inc(I); end; |
|
|
236 |
$23: begin Result += '! '; Inc(I); end; |
|
|
237 |
$30: begin Result += '== '; Inc(I); end; |
|
|
238 |
$31: begin Result += '!= '; Inc(I); end; |
|
|
239 |
$32: begin Result += '> '; Inc(I); end; |
|
|
240 |
$33: begin Result += '< '; Inc(I); end; |
|
|
241 |
$34: begin Result += '>= '; Inc(I); end; |
|
|
242 |
$35: begin Result += '<= '; Inc(I); end; |
|
|
243 |
$40: begin Result += '<< '; Inc(I); end; |
|
|
244 |
$41: begin Result += '>> '; Inc(I); end; |
|
|
245 |
$50: begin Result += '(bank-sym ' + IntToStr(ReadLong)+') '; end; |
|
|
246 |
$51: begin Result += '(bank-section ' + IntToStr(ReadLong)+') '; end; |
|
|
247 |
$52: begin Result += 'current-bank'; Inc(I); end; |
|
|
248 |
$60: begin Result += 'hram-check'; Inc(I); end; |
|
|
249 |
$61: begin Result += 'rst-check'; Inc(I); end; |
|
|
250 |
$80: begin Result += '(int ' + IntToStr(ReadLong)+') '; end; |
|
|
251 |
$81: begin Result += '(sym ' + Syms[ReadLong].Name+') '; end; |
|
|
252 |
else Exit('INVALID!'); |
|
|
253 |
end; |
|
|
254 |
end; |
|
|
255 |
end; |
|
|
256 |
|
|
|
257 |
function ParseRPN(const RPN: array of Byte): TRPN; |
|
|
258 |
var |
|
|
259 |
I: Integer; |
|
|
260 |
Node: TRPNNode; |
|
|
261 |
|
|
|
262 |
function ReadLong: LongWord; |
|
|
263 |
begin |
|
|
264 |
Inc(I); |
|
|
265 |
Result := RPN[I]; |
|
|
266 |
Inc(I); |
|
|
267 |
Result := (Result shl 8) or RPN[I]; |
|
|
268 |
Inc(I); |
|
|
269 |
Result := (Result shl 8) or RPN[I]; |
|
|
270 |
Inc(I); |
|
|
271 |
Result := (Result shl 8) or RPN[I]; |
|
|
272 |
Inc(I); |
|
|
273 |
Result := SwapEndian(Result); |
|
|
274 |
end; |
|
|
275 |
|
|
|
276 |
function nd(Tag: TRPNTag): TRPNNode; |
|
|
277 |
begin Result.Tag := Tag; end; |
|
|
278 |
|
|
|
279 |
procedure PushRPN(Node: TRPNNode); |
|
|
280 |
begin |
|
|
281 |
SetLength(Result, Length(Result)+1); |
|
|
282 |
Result[High(Result)] := Node; |
|
|
283 |
end; |
|
|
284 |
|
|
|
285 |
begin |
|
|
286 |
SetLength(Result, 0); |
|
|
287 |
I := Low(RPN); |
|
|
288 |
while I <= High(RPN) do begin |
|
|
289 |
//Writeln(Format('Parsing %x, len=%d', [RPN[I], Length(Result)])); |
|
|
290 |
case RPN[I] of |
|
|
291 |
$00: begin PushRPN(Nd(rpnPlus)); Inc(I); end; |
|
|
292 |
$01: begin PushRPN(Nd(rpnMinus)); Inc(I); end; |
|
|
293 |
$02: begin PushRPN(Nd(rpnTimes)); Inc(I); end; |
|
|
294 |
$03: begin PushRPN(Nd(rpnDiv)); Inc(I); end; |
|
|
295 |
$04: begin PushRPN(Nd(rpnMod)); Inc(I); end; |
|
|
296 |
$05: begin PushRPN(Nd(rpnNegate)); Inc(I); end; |
|
|
297 |
$10: begin PushRPN(Nd(rpnOr)); Inc(I); end; |
|
|
298 |
$11: begin PushRPN(Nd(rpnAnd)); Inc(I); end; |
|
|
299 |
$12: begin PushRPN(Nd(rpnXor)); Inc(I); end; |
|
|
300 |
$13: begin PushRPN(Nd(rpnComplement)); Inc(I); end; |
|
|
301 |
$21: begin PushRPN(Nd(rpnBoolAnd)); Inc(I); end; |
|
|
302 |
$22: begin PushRPN(Nd(rpnBoolOr)); Inc(I); end; |
|
|
303 |
$23: begin PushRPN(Nd(rpnBoolNeg)); Inc(I); end; |
|
|
304 |
$30: begin PushRPN(Nd(rpnEqual)); Inc(I); end; |
|
|
305 |
$31: begin PushRPN(Nd(rpnNotEqual)); Inc(I); end; |
|
|
306 |
$32: begin PushRPN(Nd(rpnGreater)); Inc(I); end; |
|
|
307 |
$33: begin PushRPN(Nd(rpnLess)); Inc(I); end; |
|
|
308 |
$34: begin PushRPN(Nd(rpnGreaterEqual)); Inc(I); end; |
|
|
309 |
$35: begin PushRPN(Nd(rpnLessEqual)); Inc(I); end; |
|
|
310 |
$40: begin PushRPN(Nd(rpnShl)); Inc(I); end; |
|
|
311 |
$41: begin PushRPN(Nd(rpnShr)); Inc(I); end; |
|
|
312 |
$50: begin |
|
|
313 |
Node.Tag := rpnBankSymbol; |
|
|
314 |
Node.BankSymbol := ReadLong; |
|
|
315 |
PushRPN(Node); |
|
|
316 |
end; |
|
|
317 |
$51: begin |
|
|
318 |
Node.Tag := rpnBankSection; |
|
|
319 |
Node.BankSection := ReadLong; |
|
|
320 |
PushRPN(Node); |
|
|
321 |
end; |
|
|
322 |
$52: begin PushRPN(Nd(rpnCurrentBank)); Inc(I); end; |
|
|
323 |
$60: begin PushRPN(Nd(rpnHramCheck)); Inc(I); end; |
|
|
324 |
$61: begin PushRPN(Nd(rpnRstCheck)); Inc(I); end; |
|
|
325 |
$80: begin |
|
|
326 |
Node.Tag := rpnInteger; |
|
|
327 |
Node.IntValue := ReadLong; |
|
|
328 |
PushRPN(Node); |
|
|
329 |
end; |
|
|
330 |
$81: begin |
|
|
331 |
Node.Tag := rpnSymbol; |
|
|
332 |
Node.SymbolID := ReadLong; |
|
|
333 |
PushRPN(Node); |
|
|
334 |
end; |
|
|
335 |
else Die('Got malformed RPN!'); |
|
|
336 |
end; |
|
|
337 |
end; |
|
|
338 |
end; |
|
|
339 |
|
|
|
340 |
|
|
|
341 |
procedure PrintObjFile(O: TRObj); |
|
|
342 |
var |
|
|
343 |
Sym: TRSymbol; |
|
|
344 |
Sect: TRSection; |
|
|
345 |
Patch: TRPatch; |
|
|
346 |
SectSize: Integer; |
|
|
347 |
begin |
|
|
348 |
WriteLn('Symbols:'); |
|
|
349 |
for Sym in O.Symbols do |
|
|
350 |
Writeln(Format(' %s on %d: type=%d, section=%d, value=%d', |
|
|
351 |
[Sym.Name, Sym.LineNum, Sym.SymType, Sym.SectionID, Sym.Value])); |
|
|
352 |
|
|
|
353 |
SectSize := 0; |
|
|
354 |
for Sect in O.Sections do |
|
|
355 |
if (Sect.Org <> -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then Inc(SectSize, Sect.Size); |
|
|
356 |
Writeln('Absolute sections: ', SectSize, ' bytes'); |
|
|
357 |
|
|
|
358 |
SectSize := 0; |
|
|
359 |
for Sect in O.Sections do |
|
|
360 |
if (Sect.Org = -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then Inc(SectSize, Sect.Size); |
|
|
361 |
Writeln('Relative sections: ', SectSize, ' bytes'); |
|
|
362 |
|
|
|
363 |
WriteLn('Sections:'); |
|
|
364 |
for Sect in O.Sections do begin |
|
|
365 |
Writeln(Format(' %s with size %d: offset=%d, patches=%d, bank=%d', |
|
|
366 |
[Sect.Name, Sect.Size, Sect.Org, Sect.NumberOfPatches, Sect.Bank])); |
|
|
367 |
|
|
|
368 |
for Patch in Sect.Patches do |
|
|
369 |
Writeln(Format(' %s: %d ; %s', [Patch.SourceFile, Patch.PatchType, RPNToString(Patch.RPN, O.Symbols)])); |
|
|
370 |
end; |
|
|
371 |
end; |
|
|
372 |
|
|
|
373 |
function FindPatch(const Section: TRSection; Index: Integer; out Patch: TRPatch): Boolean; |
|
|
374 |
var |
|
|
375 |
I: Integer; |
|
|
376 |
begin |
|
|
377 |
for I := Low(Section.Patches) to High(Section.Patches) do |
|
|
378 |
if Section.Patches[I].Offset = Index then begin |
|
|
379 |
Patch := Section.Patches[I]; |
|
|
380 |
Exit(True); |
|
|
381 |
end; |
|
|
382 |
|
|
|
383 |
Result := False; |
|
|
384 |
end; |
|
|
385 |
|
|
|
386 |
var |
|
|
387 |
RObj: TRObj; |
|
|
388 |
|
|
|
389 |
Symbol: TRSymbol; |
|
|
390 |
Section: TRSection; |
|
|
391 |
Patch: TRPatch; |
|
|
392 |
|
|
|
393 |
F: Text; |
|
|
394 |
|
|
|
395 |
ValueToWrite: Word; |
|
|
396 |
RPN: TRPN; |
|
|
397 |
I: Word; |
|
|
398 |
Sct: Word; |
|
|
399 |
WritePos: Word; |
|
|
400 |
Idx: Integer; |
|
|
401 |
CODESEG: string; |
|
|
402 |
DefaultBank: Integer = 1; |
|
|
403 |
sourcename, tmp: string; |
|
|
404 |
|
|
|
405 |
old_sym, new_sym: string; |
|
|
406 |
|
|
|
407 |
verbose: boolean = false; |
|
|
408 |
|
|
|
409 |
export_all: boolean = false; |
|
|
410 |
|
|
|
411 |
begin |
|
|
412 |
if (ParamCount() < 1) then begin |
|
|
413 |
Writeln('Usage: rgb2sdas [-c<code_section>] [-v] [-e] [-r<symbol1>=<symbol2>] [-b<default_bank>] <object_name>'); |
|
|
414 |
Halt; |
|
|
415 |
end; |
|
|
416 |
|
|
|
417 |
sourcename:= ParamStr(ParamCount()); |
|
|
418 |
if not FileExists(sourcename) then Die('File not found: %s', [sourcename]); |
|
|
419 |
|
|
|
420 |
old_sym:= ''; new_sym:= ''; |
|
|
421 |
|
|
|
422 |
CODESEG:= '_CODE'; |
|
|
423 |
for I:= 1 to ParamCount() - 1 do begin |
|
|
424 |
tmp:= ParamStr(i); |
|
|
425 |
if (CompareText(tmp, '-v') = 0) then |
|
|
426 |
verbose:= true |
|
|
427 |
else if (CompareText(copy(tmp, 1, 2), '-e') = 0) then |
|
|
428 |
export_all:= true |
|
|
429 |
else if (CompareText(copy(tmp, 1, 2), '-c') = 0) then begin |
|
|
430 |
CODESEG:= copy(tmp, 3, length(tmp)); |
|
|
431 |
if length(CODESEG) = 0 then CODESEG:= '_CODE'; |
|
|
432 |
if verbose then writeln('Using CODESEG: ', CODESEG); |
|
|
433 |
end else if (CompareText(copy(tmp, 1, 2), '-b') = 0) then begin |
|
|
434 |
DefaultBank:= StrToIntDef(copy(tmp, 3, length(tmp)), DefaultBank); |
|
|
435 |
if verbose then writeln('Using DefaultBank: ', DefaultBank); |
|
|
436 |
end else if (CompareText(copy(tmp, 1, 2), '-r') = 0) then begin |
|
|
437 |
tmp:= copy(tmp, 3, length(tmp)); |
|
|
438 |
Idx:= pos('=', tmp); |
|
|
439 |
if (idx > 0) then begin |
|
|
440 |
old_sym:= copy(tmp, 1, idx - 1); |
|
|
441 |
new_sym:= copy(tmp, idx + 1, length(tmp)); |
|
|
442 |
end; |
|
|
443 |
end; |
|
|
444 |
end; |
|
|
445 |
|
|
|
446 |
RObj := ReadObjFile(sourcename); |
|
|
447 |
if verbose then PrintObjFile(RObj); |
|
|
448 |
|
|
|
449 |
Assign(F, sourcename + '.o'); |
|
|
450 |
Rewrite(F); |
|
|
451 |
try |
|
|
452 |
Idx:= 0; |
|
|
453 |
// pass 1: all imports first |
|
|
454 |
for I:= Low(RObj.Symbols) to High(RObj.Symbols) do with RObj.Symbols[I] do begin |
|
|
455 |
if ((SymType and $7f) = SYM_IMPORT) then begin |
|
|
456 |
No:= Idx; |
|
|
457 |
Inc(Idx); |
|
|
458 |
end else No:= -1; |
|
|
459 |
end; |
|
|
460 |
// pass 2: all other (export local only when forced) |
|
|
461 |
for I:= Low(RObj.Symbols) to High(RObj.Symbols) do with RObj.Symbols[I] do begin |
|
|
462 |
case (SymType and $7f) of |
|
|
463 |
SYM_LOCAL : if export_all then begin |
|
|
464 |
No:= Idx; |
|
|
465 |
Inc(Idx); |
|
|
466 |
end; |
|
|
467 |
SYM_IMPORT : ; |
|
|
468 |
SYM_EXPORT : begin |
|
|
469 |
// rename exported symbol if requested |
|
|
470 |
if (length(old_sym) > 0) and (Name = old_sym) then Name:= new_sym; |
|
|
471 |
No:= Idx; |
|
|
472 |
Inc(Idx); |
|
|
473 |
end; |
|
|
474 |
else Die('Unsupported symbol type: %d', [SymType and $7f]); |
|
|
475 |
end; |
|
|
476 |
end; |
|
|
477 |
|
|
|
478 |
// output object header |
|
|
479 |
Writeln(F, 'XL2'); |
|
|
480 |
Writeln(F, Format('H %x areas %x global symbols', [RObj.NumberOfSections, idx])); |
|
|
481 |
Writeln(F, Format('M %s', [StringReplace(ExtractFileName(sourcename), '.', '_', [rfReplaceAll])])); |
|
|
482 |
Writeln(F, 'O -mgbz80'); |
|
|
483 |
|
|
|
484 |
// output all imported symbols |
|
|
485 |
for I:= Low(RObj.Symbols) to High(RObj.Symbols) do |
|
|
486 |
with RObj.Symbols[I] do |
|
|
487 |
if (SymType = SYM_IMPORT) then |
|
|
488 |
Writeln(F, Format('S %s Ref%.4x', [StringReplace(Name, '.', '____', [rfReplaceAll]), 0])); |
|
|
489 |
|
|
|
490 |
// output all sections and other symbols |
|
|
491 |
for Section in RObj.Sections do begin |
|
|
492 |
if Section.Org = -1 then |
|
|
493 |
case Section.SectType of |
|
|
494 |
ROM0: Writeln(F, Format('A %s size %x flags 0 addr 0', [CODESEG, Section.Size])); |
|
|
495 |
ROMX: if (DefaultBank = 0) then Writeln(F, Format('A %s size %x flags 0 addr 0', [CODESEG, Section.Size])) |
|
|
496 |
else Writeln(F, Format('A _CODE_%d size %x flags 0 addr 0', [max(DefaultBank, Section.Bank), Section.Size])); |
|
|
497 |
else Writeln(F, Format('A _DATA size %x flags 0 addr 0', [Section.Size])); |
|
|
498 |
end |
|
|
499 |
else Die('absolute sections currently unsupported: %s', [Section.Name]); |
|
|
500 |
|
|
|
501 |
for Symbol in RObj.Symbols do |
|
|
502 |
if Symbol.SectionID = Section.ID then begin |
|
|
503 |
if (Symbol.SymType <> SYM_IMPORT) and (Symbol.No >= 0) then |
|
|
504 |
Writeln(F, Format('S %s Def%.4x', [StringReplace(Symbol.Name, '.', '____', [rfReplaceAll]), Symbol.Value])); |
|
|
505 |
end; |
|
|
506 |
end; |
|
|
507 |
|
|
|
508 |
// convert object itself |
|
|
509 |
for Sct := Low(RObj.Sections) to High(RObj.Sections) do begin |
|
|
510 |
Section := RObj.Sections[Sct]; |
|
|
511 |
|
|
|
512 |
if (Section.SectType <> ROMX) and (Section.SectType <> ROM0) then Continue; |
|
|
513 |
if Length(Section.Data) <= 0 then Continue; |
|
|
514 |
|
|
|
515 |
I := Low(Section.Data); |
|
|
516 |
while I <= High(Section.Data) do begin |
|
|
517 |
WritePos := I; |
|
|
518 |
if (Section.Org <> -1) then Inc(WritePos, Section.Org); |
|
|
519 |
|
|
|
520 |
if FindPatch(Section, I, Patch) then begin |
|
|
521 |
case Patch.PatchType of |
|
|
522 |
PATCH_LE_WORD : begin |
|
|
523 |
RPN := ParseRPN(Patch.RPN); |
|
|
524 |
Symbol := RObj.Symbols[RPN[0].SymbolID]; |
|
|
525 |
ValueToWrite := Symbol.Value; |
|
|
526 |
if RPN[High(RPN)].Tag = rpnPlus then |
|
|
527 |
Inc(ValueToWrite, RPN[1].IntValue); |
|
|
528 |
|
|
|
529 |
if (Symbol.SymType = SYM_IMPORT) then begin |
|
|
530 |
if (Symbol.No < 0) then Die('Trying to reference eliminated symbol'); |
|
|
531 |
Writeln(F, Format('T %.2x %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)])); |
|
|
532 |
Writeln(F, Format('R 00 00 %.2x %.2x 02 02 %.2x %.2x', [lo(Sct), hi(Sct), lo(Symbol.No), hi(Symbol.No)])); |
|
|
533 |
end else begin |
|
|
534 |
Writeln(F, Format('T %.2x %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)])); |
|
|
535 |
Writeln(F, Format('R 00 00 %.2x %.2x 00 02 %.2x %.2x', [lo(Sct), hi(Sct), lo(Symbol.SectionID), hi(Symbol.SectionID)])); |
|
|
536 |
end; |
|
|
537 |
Inc(I, 2); |
|
|
538 |
end; |
|
|
539 |
PATCH_JR : begin |
|
|
540 |
RPN := ParseRPN(Patch.RPN); |
|
|
541 |
if Length(RPN) > 1 then Die('Not handling bigger RPN on JR'); |
|
|
542 |
Symbol := RObj.Symbols[RPN[0].SymbolID]; |
|
|
543 |
Writeln(F, Format('T %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), Byte(Symbol.Value - I - 1)])); |
|
|
544 |
Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct), hi(Sct)])); |
|
|
545 |
Inc(I); |
|
|
546 |
end |
|
|
547 |
else Die('Unsupported patch type: %d', [Patch.PatchType]); |
|
|
548 |
end; |
|
|
549 |
end else begin |
|
|
550 |
Writeln(F, Format('T %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), Section.Data[I]])); |
|
|
551 |
Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct), hi(Sct)])); |
|
|
552 |
Inc(I); |
|
|
553 |
end; |
|
|
554 |
end; |
|
|
555 |
end; |
|
|
556 |
|
|
|
557 |
Writeln('rgb2sdas converting ',sourcename,' --> ',sourcename,'.o result: success!'); |
|
|
558 |
finally Close(F); end; |
|
|
559 |
end. |
|
|
560 |
|