Commit 76c4536

Nick committed on
Initial commit of rgb2gbdk program (will be integrated with the tracker)
commit 76c453602905b1e3efdf8247171b391ad56241fa parent 5d6eae8
1 changed files +465−0
Addedrgb2gbdk.pas +465−0
@@ -0,0 +1,465 @@
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