Commit c5c7966

Nick committed on
Bring in Toxa's updated rgb2sdas
commit c5c796624843a4fe7d6be8de32f642752e14f6ff parent 6524585
3 changed files +561−466
ModifiedhUGEDriver +1−1
@@ -1 +1 @@
1 Subproject commit 3425ea80ffb4dab6320e206b5938999f2fc41b49 1 Subproject commit 73749cdf640140cad6103199b938307a5462fa44
Deletedrgb2gbdk.pas +0−465
@@ -1,465 +0,0 @@
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
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 FileName: String;
19 LineNum, SectionID, Value: LongInt;
20 end;
21
22 TRPatch = packed record
23 SourceFile: String;
24 Offset: LongInt;
25 PatchType: Byte;
26 RPNSize: LongInt;
27 RPN: array of Byte;
28 end;
29
30 TRSection = packed record
31 ID: Integer;
32 Name: String;
33 Size: LongInt;
34 SectType: Byte;
35 Org: LongInt;
36 Bank: LongInt;
37 Align: LongInt;
38
39 Data: array of Byte;
40 NumberOfPatches: LongInt;
41 Patches: array of TRPatch;
42 end;
43
44 TRObj = packed record
45 ID: array[0..3] of Char;
46 RevisionNumber: LongInt;
47 NumberOfSymbols: LongInt;
48 NumberOfSections: LongInt;
49
50 Symbols: array of TRSymbol;
51 Sections: array of TRSection;
52 end;
53
54 TRPNTag = (
55 rpnPlus,
56 rpnMinus,
57 rpnTimes,
58 rpnDiv,
59 rpnMod,
60 rpnNegate,
61 rpnOr,
62 rpnAnd,
63 rpnXor,
64 rpnComplement,
65 rpnBoolAnd,
66 rpnBoolOr,
67 rpnBoolNeg,
68 rpnEqual,
69 rpnNotEqual,
70 rpnGreater,
71 rpnLess,
72 rpnGreaterEqual,
73 rpnLessEqual,
74 rpnShl,
75 rpnShr,
76 rpnBankSymbol,
77 rpnBankSection,
78 rpnCurrentBank,
79 rpnHramCheck,
80 rpnRstCheck,
81 rpnInteger,
82 rpnSymbol);
83
84 TRPNNode = record
85 case Tag: TRPNTag of
86 rpnBankSymbol: (BankSymbol: Integer);
87 rpnBankSection: (BankSection: Integer);
88 rpnInteger: (IntValue: Integer);
89 rpnSymbol: (SymbolID: Integer);
90 end;
91 TRPN = array of TRPNNode;
92
93 const
94 WRAM0 = 0;
95 VRAM = 1;
96 ROMX = 2;
97 ROM0 = 3;
98 HRAM = 4;
99 WRAMX = 5;
100 SRAM = 6;
101 OAM = 7;
102
103 procedure Die(S: String);
104 begin
105 WriteLn(S);
106 Readln;
107 Halt
108 end;
109
110 function ReadNullTerm(S: TStream): String; // really
111 var
112 B: Byte;
113 begin
114 Result := '';
115
116 while True do begin
117 B := S.ReadByte;
118 if B = 0 then Exit;
119 Result += Chr(B)
120 end
121 end;
122
123 function ReadObjFile(S: TStream): TRObj;
124 var
125 I, J: Integer;
126 begin
127 S.Read(Result, SizeOf(TRObj) - SizeOf(Result.Symbols) - SizeOf(Result.Sections));
128 SetLength(Result.Symbols, Result.NumberOfSymbols);
129 SetLength(Result.Sections, Result.NumberOfSections);
130
131 for I := 0 to Result.NumberOfSymbols-1 do begin
132 Result.Symbols[I] := Default(TRSymbol);
133 with Result.Symbols[I] do begin
134 ID := I;
135 Name := ReadNullTerm(S);
136 S.Read(SymType, 1);
137 if (SymType and $7F) <> 1 then begin
138 FileName := ReadNullTerm(S);
139 S.Read(LineNum, SizeOf(LineNum));
140 S.Read(SectionID, SizeOf(SectionID));
141 S.Read(Value, SizeOf(Value));
142 end;
143 end;
144 end;
145
146 for I := 0 to Result.NumberOfSections-1 do begin
147 Result.Sections[I] := Default(TRSection);
148
149 with Result.Sections[I] do begin
150 ID := I;
151 Name := ReadNullTerm(S);
152 S.Read(Size, SizeOf(Size));
153 S.Read(SectType, SizeOf(SectType));
154 S.Read(Org, SizeOf(Org));
155 S.Read(Bank, SizeOf(Bank));
156 S.Read(Align, SizeOf(Align));
157 if ((SectType = ROMX) or (SectType = ROM0)) then begin
158 SetLength(Data, Size);
159 S.Read(Data[0], Size);
160 S.Read(NumberOfPatches, SizeOf(NumberOfPatches));
161 SetLength(Patches, NumberOfPatches);
162 end;
163 end;
164
165 for J := 0 to Result.Sections[I].NumberOfPatches-1 do begin
166 with Result.Sections[I].Patches[J] do begin
167 SourceFile := ReadNullTerm(S);
168 S.Read(Offset, SizeOf(Offset));
169 S.Read(PatchType, SizeOf(PatchType));
170 S.Read(RPNSize, SizeOf(RPNSize));
171 SetLength(RPN, RPNSize);
172 S.Read(RPN[0], RPNSize);
173 end;
174 end;
175 end;
176 end;
177
178 function RPNToString(const RPN: array of Byte; const Syms: array of TRSymbol): String;
179 var
180 I: Integer;
181
182 function ReadLong: LongWord;
183 begin
184 Inc(I);
185 Result := RPN[I];
186 Inc(I);
187 Result := (Result shl 8) or RPN[I];
188 Inc(I);
189 Result := (Result shl 8) or RPN[I];
190 Inc(I);
191 Result := (Result shl 8) or RPN[I];
192 Inc(I);
193 Result := SwapEndian(Result);
194 end;
195
196 begin
197 Result := '';
198
199 I := Low(RPN);
200 while I <= High(RPN) do begin
201 case RPN[I] of
202 $00: begin Result += '+ '; Inc(I); end;
203 $01: begin Result += '- '; Inc(I); end;
204 $02: begin Result += '* '; Inc(I); end;
205 $03: begin Result += '/ '; Inc(I); end;
206 $04: begin Result += '% '; Inc(I); end;
207 $05: begin Result += 'neg '; Inc(I); end;
208 $10: begin Result += '| '; Inc(I); end;
209 $11: begin Result += '& '; Inc(I); end;
210 $12: begin Result += '^ '; Inc(I); end;
211 $13: begin Result += '~ '; Inc(I); end;
212 $21: begin Result += '&& '; Inc(I); end;
213 $22: begin Result += '|| '; Inc(I); end;
214 $23: begin Result += '! '; Inc(I); end;
215 $30: begin Result += '== '; Inc(I); end;
216 $31: begin Result += '!= '; Inc(I); end;
217 $32: begin Result += '> '; Inc(I); end;
218 $33: begin Result += '< '; Inc(I); end;
219 $34: begin Result += '>= '; Inc(I); end;
220 $35: begin Result += '<= '; Inc(I); end;
221 $40: begin Result += '<< '; Inc(I); end;
222 $41: begin Result += '>> '; Inc(I); end;
223 $50: begin Result += '(bank-sym ' + IntToStr(ReadLong)+') '; end;
224 $51: begin Result += '(bank-section ' + IntToStr(ReadLong)+') '; end;
225 $52: begin Result += 'current-bank'; Inc(I); end;
226 $60: begin Result += 'hram-check'; Inc(I); end;
227 $61: begin Result += 'rst-check'; Inc(I); end;
228 $80: begin Result += '(int ' + IntToStr(ReadLong)+') '; end;
229 $81: begin Result += '(sym ' + Syms[ReadLong].Name+') '; end;
230 else Exit('INVALID!');
231 end;
232 end;
233 end;
234
235 function ParseRPN(const RPN: array of Byte): TRPN;
236 var
237 I: Integer;
238 Node: TRPNNode;
239
240 function ReadLong: LongWord;
241 begin
242 Inc(I);
243 Result := RPN[I];
244 Inc(I);
245 Result := (Result shl 8) or RPN[I];
246 Inc(I);
247 Result := (Result shl 8) or RPN[I];
248 Inc(I);
249 Result := (Result shl 8) or RPN[I];
250 Inc(I);
251 Result := SwapEndian(Result);
252 end;
253
254 function nd(Tag: TRPNTag): TRPNNode;
255 begin
256 Result.Tag := Tag;
257 end;
258
259 procedure PushRPN(Node: TRPNNode);
260 begin
261 SetLength(Result, Length(Result)+1);
262 Result[High(Result)] := Node;
263 end;
264
265 begin
266 SetLength(Result, 0);
267 I := Low(RPN);
268 while I <= High(RPN) do begin
269 //Writeln(Format('Parsing %x, len=%d', [RPN[I], Length(Result)]));
270 case RPN[I] of
271 $00: begin PushRPN(Nd(rpnPlus)); Inc(I); end;
272 $01: begin PushRPN(Nd(rpnMinus)); Inc(I); end;
273 $02: begin PushRPN(Nd(rpnTimes)); Inc(I); end;
274 $03: begin PushRPN(Nd(rpnDiv)); Inc(I); end;
275 $04: begin PushRPN(Nd(rpnMod)); Inc(I); end;
276 $05: begin PushRPN(Nd(rpnNegate)); Inc(I); end;
277 $10: begin PushRPN(Nd(rpnOr)); Inc(I); end;
278 $11: begin PushRPN(Nd(rpnAnd)); Inc(I); end;
279 $12: begin PushRPN(Nd(rpnXor)); Inc(I); end;
280 $13: begin PushRPN(Nd(rpnComplement)); Inc(I); end;
281 $21: begin PushRPN(Nd(rpnBoolAnd)); Inc(I); end;
282 $22: begin PushRPN(Nd(rpnBoolOr)); Inc(I); end;
283 $23: begin PushRPN(Nd(rpnBoolNeg)); Inc(I); end;
284 $30: begin PushRPN(Nd(rpnEqual)); Inc(I); end;
285 $31: begin PushRPN(Nd(rpnNotEqual)); Inc(I); end;
286 $32: begin PushRPN(Nd(rpnGreater)); Inc(I); end;
287 $33: begin PushRPN(Nd(rpnLess)); Inc(I); end;
288 $34: begin PushRPN(Nd(rpnGreaterEqual)); Inc(I); end;
289 $35: begin PushRPN(Nd(rpnLessEqual)); Inc(I); end;
290 $40: begin PushRPN(Nd(rpnShl)); Inc(I); end;
291 $41: begin PushRPN(Nd(rpnShr)); Inc(I); end;
292 $50: begin
293 Node.Tag := rpnBankSymbol;
294 Node.BankSymbol := ReadLong;
295 PushRPN(Node);
296 end;
297 $51: begin
298 Node.Tag := rpnBankSection;
299 Node.BankSection := ReadLong;
300 PushRPN(Node);
301 end;
302 $52: begin PushRPN(Nd(rpnCurrentBank)); Inc(I); end;
303 $60: begin PushRPN(Nd(rpnHramCheck)); Inc(I); end;
304 $61: begin PushRPN(Nd(rpnRstCheck)); Inc(I); end;
305 $80: begin
306 Node.Tag := rpnInteger;
307 Node.IntValue := ReadLong;
308 PushRPN(Node);
309 end;
310 $81: begin
311 Node.Tag := rpnSymbol;
312 Node.SymbolID := ReadLong;
313 PushRPN(Node);
314 end;
315 else die('got malformed RPN!');
316 end;
317 end;
318 end;
319
320
321 procedure PrintObjFile(O: TRObj);
322 var
323 Sym: TRSymbol;
324 Sect: TRSection;
325 Patch: TRPatch;
326 SectSize: Integer;
327 begin
328 WriteLn('-=-=- Symbols -=-=-');
329 for Sym in O.Symbols do
330 Writeln(Format('%s on %d: type=%d, section=%d, value=%d',
331 [Sym.Name, Sym.LineNum, Sym.SymType, Sym.SectionID, Sym.Value]));
332
333 Writeln;
334 Writeln;
335
336 WriteLn('-=-=- Sections -=-=-');
337 SectSize := 0;
338 for Sect in O.Sections do
339 if (Sect.Org <> -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then Inc(SectSize, Sect.Size);
340 Writeln('Absolute sections: ', SectSize, ' bytes');
341 SectSize := 0;
342 for Sect in O.Sections do
343 if (Sect.Org = -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then Inc(SectSize, Sect.Size);
344 Writeln('Relative sections: ', SectSize, ' bytes');
345 Writeln;
346
347 for Sect in O.Sections do begin
348 Writeln(Format('%s with size %d: offset=%d, patches=%d, bank=%d',
349 [Sect.Name, Sect.Size, Sect.Org, Sect.NumberOfPatches, Sect.Bank]));
350
351 for Patch in Sect.Patches do begin
352 Writeln(Format('%s: %d ; %s', [Patch.SourceFile, Patch.PatchType, RPNToString(Patch.RPN, O.Symbols)]));
353 end;
354 Writeln;
355 writeln;
356 end;
357 end;
358
359 function FindPatch(const Section: TRSection; Index: Integer; out Patch: TRPatch): Boolean;
360 var
361 I: Integer;
362 begin
363 for I := Low(Section.Patches) to High(Section.Patches) do
364 if Section.Patches[I].Offset = Index then begin
365 Patch := Section.Patches[I];
366 Exit(True);
367 end;
368
369 Result := False;
370 end;
371
372 var
373 S: TStream;
374 RObj: TRObj;
375
376 Symbol: TRSymbol;
377 Section: TRSection;
378 Patch: TRPatch;
379
380 F: Text;
381
382 ValueToWrite: Word;
383 RPN: TRPN;
384 I: Word;
385 Sct: Word;
386 WritePos: Word;
387 begin
388 S := TFileStream.Create('hUGE.obj', fmOpenRead);
389 RObj := ReadObjFile(S);
390 PrintObjFile(RObj);
391
392 Assign(F, 'hUGE_trans.o');
393 Rewrite(F);
394
395 Writeln(F, 'XL');
396 Writeln(F, Format('H %x areas %x global symbols', [RObj.NumberOfSections+1, Length(RObj.Symbols)]));
397 Writeln(F, 'A _CODE size 0 flags 0'); // Insanity
398 for Section in RObj.Sections do begin
399 if Section.Org = -1 then
400 //Writeln(F, Format('A %s size %x flags 0', [LeftStr(DelSpace(Section.Name), 25), Section.Size]))
401 Writeln(F, Format('A %s size %x flags 0', [IfThen(Section.SectType in [ROM0, ROMX], '_CODE', '_DATA'), Section.Size]))
402 else Die('absolute sections currently unsupported: ' + Section.Name);
403 //Writeln(F, Format('A %s size %x flags C', [LeftStr(DelSpace(Section.Name), 25), Section.Org+Section.Size]));
404
405 for Symbol in RObj.Symbols do
406 if Symbol.SectionID = Section.ID then begin
407 Writeln(F, Format('S %s Def%.4x', [StringReplace(Symbol.Name, '.', '____', [rfReplaceAll]), Symbol.Value]));
408 end;
409 end;
410
411 for Sct := Low(RObj.Sections) to High(RObj.Sections) do begin
412 Section := RObj.Sections[Sct];
413
414 if (Section.SectType <> ROMX) and (Section.SectType <> ROM0) then Continue;
415 if Length(Section.Data) <= 0 then Continue;
416
417 I := Low(Section.Data);
418 while I <= High(Section.Data) do begin
419 WritePos := I;
420 if Section.Org <> -1 then Inc(WritePos, Section.Org);
421 if (Section.Org <> -1) and (WritePos >= $200) then Writeln('Section ', Section.Name, ' is clobbering ', WritePos);
422
423 if FindPatch(Section, I, Patch) then begin
424 case Patch.PatchType of
425 1: begin
426 RPN := ParseRPN(Patch.RPN);
427 Symbol := RObj.Symbols[RPN[0].SymbolID];
428 ValueToWrite := Symbol.Value;
429 if RPN[High(RPN)].Tag = rpnPlus then
430 Inc(ValueToWrite, RPN[1].IntValue);
431 {if RObj.Sections[Symbol.SectionID].SectType = WRAM0 then
432 Inc(ValueToWrite, $C000);}
433
434 Writeln(F, Format('T %.2x %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)]));
435 Writeln(F, Format('R 00 00 %.2x %.2x 00 02 %.2x %.2x', [lo(Sct+1), hi(Sct+1), lo(Symbol.SectionID+1), hi(Symbol.SectionID+1)]));
436 Inc(I, 2);
437 end;
438 3: begin
439 RPN := ParseRPN(Patch.RPN);
440 if Length(RPN) > 1 then Die('Not handling bigger RPN on JR');
441 Symbol := RObj.Symbols[RPN[0].SymbolID];
442 Writeln(F, Format('T %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), Byte(Symbol.Value - I - 1)]));
443 Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct+1), hi(Sct+1)]));
444 Inc(I);
445 end
446 else begin
447 Die('Unsupported patch type: ' + IntToStr(Patch.PatchType));
448 Inc(I);
449 end;
450 end;
451 end
452 else begin
453 Writeln(F, Format('T %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), Section.Data[I]]));
454 Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct+1), hi(Sct+1)]));
455 Inc(I);
456 end;
457 end;
458 end;
459
460 Writeln('Success!');
461 Close(F);
462
463 readln;
464 end.
465
Addedrgb2sdas.pas +560−0
@@ -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