@@ -1,861 +0,0 @@ |
| 1 |
unit rgb2sdas; |
|
|
| 2 |
|
|
|
| 3 |
{ TODO: This unit needs to be refactored, really bad. } |
|
|
| 4 |
|
|
|
| 5 |
{$mode objfpc}{$H+} |
|
|
| 6 |
|
|
|
| 7 |
interface |
|
|
| 8 |
|
|
|
| 9 |
uses |
|
|
| 10 |
{$IFDEF UNIX}{$IFDEF UseCThreads} |
|
|
| 11 |
cthreads, |
|
|
| 12 |
{$ENDIF}{$ENDIF} |
|
|
| 13 |
Classes, SysUtils, strutils, Math |
|
|
| 14 |
{ you can add units after this }; |
|
|
| 15 |
|
|
|
| 16 |
type |
|
|
| 17 |
TRSymbol = packed record |
|
|
| 18 |
ID: integer; |
|
|
| 19 |
Name: string; |
|
|
| 20 |
SymType: byte; |
|
|
| 21 |
|
|
|
| 22 |
No: integer; |
|
|
| 23 |
|
|
|
| 24 |
FileName: string; |
|
|
| 25 |
LineNum, SectionID, Value: longint; |
|
|
| 26 |
end; |
|
|
| 27 |
|
|
|
| 28 |
TRPatch = packed record |
|
|
| 29 |
SourceFile: string; |
|
|
| 30 |
Offset: longint; |
|
|
| 31 |
PCSectionID: longint; |
|
|
| 32 |
PCOffset: longint; |
|
|
| 33 |
PatchType: byte; |
|
|
| 34 |
RPNSize: longint; |
|
|
| 35 |
RPN: array of byte; |
|
|
| 36 |
end; |
|
|
| 37 |
|
|
|
| 38 |
TRSection = packed record |
|
|
| 39 |
ID: integer; |
|
|
| 40 |
Name: string; |
|
|
| 41 |
Size: longint; |
|
|
| 42 |
SectType: byte; |
|
|
| 43 |
Org: longint; |
|
|
| 44 |
Bank: longint; |
|
|
| 45 |
Align: byte; |
|
|
| 46 |
Ofs: longint; |
|
|
| 47 |
|
|
|
| 48 |
Data: array of byte; |
|
|
| 49 |
NumberOfPatches: longint; |
|
|
| 50 |
Patches: array of TRPatch; |
|
|
| 51 |
end; |
|
|
| 52 |
|
|
|
| 53 |
TRObj = packed record |
|
|
| 54 |
ID: array[0..3] of AnsiChar; |
|
|
| 55 |
RevisionNumber: longint; |
|
|
| 56 |
NumberOfSymbols: longint; |
|
|
| 57 |
NumberOfSections: longint; |
|
|
| 58 |
|
|
|
| 59 |
Symbols: array of TRSymbol; |
|
|
| 60 |
Sections: array of TRSection; |
|
|
| 61 |
end; |
|
|
| 62 |
|
|
|
| 63 |
TRPNTag = ( |
|
|
| 64 |
rpnPlus, |
|
|
| 65 |
rpnMinus, |
|
|
| 66 |
rpnTimes, |
|
|
| 67 |
rpnDiv, |
|
|
| 68 |
rpnMod, |
|
|
| 69 |
rpnNegate, |
|
|
| 70 |
rpnOr, |
|
|
| 71 |
rpnAnd, |
|
|
| 72 |
rpnXor, |
|
|
| 73 |
rpnComplement, |
|
|
| 74 |
rpnBoolAnd, |
|
|
| 75 |
rpnBoolOr, |
|
|
| 76 |
rpnBoolNeg, |
|
|
| 77 |
rpnEqual, |
|
|
| 78 |
rpnNotEqual, |
|
|
| 79 |
rpnGreater, |
|
|
| 80 |
rpnLess, |
|
|
| 81 |
rpnGreaterEqual, |
|
|
| 82 |
rpnLessEqual, |
|
|
| 83 |
rpnShl, |
|
|
| 84 |
rpnShr, |
|
|
| 85 |
rpnBankSymbol, |
|
|
| 86 |
rpnBankSection, |
|
|
| 87 |
rpnCurrentBank, |
|
|
| 88 |
rpnHramCheck, |
|
|
| 89 |
rpnRstCheck, |
|
|
| 90 |
rpnInteger, |
|
|
| 91 |
rpnSymbol); |
|
|
| 92 |
|
|
|
| 93 |
TRPNNode = record |
|
|
| 94 |
case Tag: TRPNTag of |
|
|
| 95 |
rpnBankSymbol: (BankSymbol: integer); |
|
|
| 96 |
rpnBankSection: (BankSection: integer); |
|
|
| 97 |
rpnInteger: (IntValue: integer); |
|
|
| 98 |
rpnSymbol: (SymbolID: integer); |
|
|
| 99 |
end; |
|
|
| 100 |
TRPN = array of TRPNNode; |
|
|
| 101 |
|
|
|
| 102 |
type |
|
|
| 103 |
TObjFileStream = class(TFileStream) |
|
|
| 104 |
function ReadNullTerm: string; virtual; |
|
|
| 105 |
end; |
|
|
| 106 |
|
|
|
| 107 |
EObjectConversionException = class(Exception); |
|
|
| 108 |
|
|
|
| 109 |
procedure ConvertRGB2SDAS(SourceName, DestName: string); |
|
|
| 110 |
|
|
|
| 111 |
implementation |
|
|
| 112 |
|
|
|
| 113 |
function TObjFileStream.ReadNullTerm: string; |
|
|
| 114 |
var |
|
|
| 115 |
B: byte; |
|
|
| 116 |
begin |
|
|
| 117 |
Result := ''; |
|
|
| 118 |
while True do |
|
|
| 119 |
begin |
|
|
| 120 |
B := ReadByte; |
|
|
| 121 |
if B = 0 then |
|
|
| 122 |
Exit; |
|
|
| 123 |
Result += Chr(B); |
|
|
| 124 |
end; |
|
|
| 125 |
end; |
|
|
| 126 |
|
|
|
| 127 |
const |
|
|
| 128 |
WRAM0 = 0; |
|
|
| 129 |
VRAM = 1; |
|
|
| 130 |
ROMX = 2; |
|
|
| 131 |
ROM0 = 3; |
|
|
| 132 |
HRAM = 4; |
|
|
| 133 |
WRAMX = 5; |
|
|
| 134 |
SRAM = 6; |
|
|
| 135 |
OAM = 7; |
|
|
| 136 |
|
|
|
| 137 |
const |
|
|
| 138 |
SYM_LOCAL = 0; |
|
|
| 139 |
SYM_IMPORT = 1; |
|
|
| 140 |
SYM_EXPORT = 2; |
|
|
| 141 |
|
|
|
| 142 |
const |
|
|
| 143 |
PATCH_BYTE = 0; |
|
|
| 144 |
PATCH_LE_WORD = 1; |
|
|
| 145 |
PATCH_LE_LONG = 2; |
|
|
| 146 |
PATCH_JR = 3; |
|
|
| 147 |
|
|
|
| 148 |
procedure Die(const S: string); overload; |
|
|
| 149 |
begin |
|
|
| 150 |
raise EObjectConversionException.Create(S); |
|
|
| 151 |
end; |
|
|
| 152 |
|
|
|
| 153 |
procedure Die(const fmt: string; const params: array of const); overload; |
|
|
| 154 |
begin |
|
|
| 155 |
Die(format(fmt, params)); |
|
|
| 156 |
end; |
|
|
| 157 |
|
|
|
| 158 |
function ReadObjFile(const afilename: string): TRObj; |
|
|
| 159 |
const |
|
|
| 160 |
Sign: array[0..3] of AnsiChar = 'RGB9'; |
|
|
| 161 |
var |
|
|
| 162 |
I, J: integer; |
|
|
| 163 |
begin |
|
|
| 164 |
with TObjFileStream.Create(afilename, fmOpenRead) do |
|
|
| 165 |
try |
|
|
| 166 |
Read(Result, SizeOf(TRObj) - SizeOf(Result.Symbols) - SizeOf(Result.Sections)); |
|
|
| 167 |
if not (CompareMem(@Result.ID, @Sign, sizeof(Result.ID)) and |
|
|
| 168 |
(Result.RevisionNumber = 5)) then |
|
|
| 169 |
Die('Unsupported object file version!'); |
|
|
| 170 |
SetLength(Result.Symbols, Result.NumberOfSymbols); |
|
|
| 171 |
SetLength(Result.Sections, Result.NumberOfSections); |
|
|
| 172 |
|
|
|
| 173 |
for I := 0 to Result.NumberOfSymbols - 1 do |
|
|
| 174 |
begin |
|
|
| 175 |
Result.Symbols[I] := Default(TRSymbol); |
|
|
| 176 |
with Result.Symbols[I] do |
|
|
| 177 |
begin |
|
|
| 178 |
ID := I; |
|
|
| 179 |
Name := ReadNullTerm; |
|
|
| 180 |
Read(SymType, 1); |
|
|
| 181 |
if ((SymType and $7F) <> SYM_IMPORT) then |
|
|
| 182 |
begin |
|
|
| 183 |
FileName := ReadNullTerm; |
|
|
| 184 |
Read(LineNum, SizeOf(LineNum)); |
|
|
| 185 |
Read(SectionID, SizeOf(SectionID)); |
|
|
| 186 |
Read(Value, SizeOf(Value)); |
|
|
| 187 |
end; |
|
|
| 188 |
end; |
|
|
| 189 |
end; |
|
|
| 190 |
|
|
|
| 191 |
for I := 0 to Result.NumberOfSections - 1 do |
|
|
| 192 |
begin |
|
|
| 193 |
Result.Sections[I] := Default(TRSection); |
|
|
| 194 |
with Result.Sections[I] do |
|
|
| 195 |
begin |
|
|
| 196 |
ID := I; |
|
|
| 197 |
Name := ReadNullTerm; |
|
|
| 198 |
Read(Size, SizeOf(Size)); |
|
|
| 199 |
Read(SectType, SizeOf(SectType)); |
|
|
| 200 |
Read(Org, SizeOf(Org)); |
|
|
| 201 |
Read(Bank, SizeOf(Bank)); |
|
|
| 202 |
Read(Align, SizeOf(Align)); |
|
|
| 203 |
Read(Ofs, SizeOf(Ofs)); |
|
|
| 204 |
if ((SectType = ROMX) or (SectType = ROM0)) then |
|
|
| 205 |
begin |
|
|
| 206 |
SetLength(Data, Size); |
|
|
| 207 |
Read(Data[0], Size); |
|
|
| 208 |
Read(NumberOfPatches, SizeOf(NumberOfPatches)); |
|
|
| 209 |
SetLength(Patches, NumberOfPatches); |
|
|
| 210 |
end; |
|
|
| 211 |
end; |
|
|
| 212 |
|
|
|
| 213 |
for J := 0 to Result.Sections[I].NumberOfPatches - 1 do |
|
|
| 214 |
begin |
|
|
| 215 |
with Result.Sections[I].Patches[J] do |
|
|
| 216 |
begin |
|
|
| 217 |
SourceFile := ReadNullTerm; |
|
|
| 218 |
Read(Offset, SizeOf(Offset)); |
|
|
| 219 |
Read(PCSectionID, SizeOf(PCSectionID)); |
|
|
| 220 |
Read(PCOffset, SizeOf(PCOffset)); |
|
|
| 221 |
Read(PatchType, SizeOf(PatchType)); |
|
|
| 222 |
Read(RPNSize, SizeOf(RPNSize)); |
|
|
| 223 |
SetLength(RPN, RPNSize); |
|
|
| 224 |
Read(RPN[0], RPNSize); |
|
|
| 225 |
end; |
|
|
| 226 |
end; |
|
|
| 227 |
end; |
|
|
| 228 |
finally |
|
|
| 229 |
Free; |
|
|
| 230 |
end; |
|
|
| 231 |
end; |
|
|
| 232 |
|
|
|
| 233 |
function RPNToString(const RPN: array of byte; const Syms: array of TRSymbol): string; |
|
|
| 234 |
var |
|
|
| 235 |
I: integer; |
|
|
| 236 |
|
|
|
| 237 |
function ReadLong: longword; |
|
|
| 238 |
begin |
|
|
| 239 |
Inc(I); |
|
|
| 240 |
Result := RPN[I]; |
|
|
| 241 |
Inc(I); |
|
|
| 242 |
Result := (Result shl 8) or RPN[I]; |
|
|
| 243 |
Inc(I); |
|
|
| 244 |
Result := (Result shl 8) or RPN[I]; |
|
|
| 245 |
Inc(I); |
|
|
| 246 |
Result := (Result shl 8) or RPN[I]; |
|
|
| 247 |
Inc(I); |
|
|
| 248 |
Result := SwapEndian(Result); |
|
|
| 249 |
end; |
|
|
| 250 |
|
|
|
| 251 |
begin |
|
|
| 252 |
Result := ''; |
|
|
| 253 |
|
|
|
| 254 |
I := Low(RPN); |
|
|
| 255 |
while I <= High(RPN) do |
|
|
| 256 |
begin |
|
|
| 257 |
case RPN[I] of |
|
|
| 258 |
$00: |
|
|
| 259 |
begin |
|
|
| 260 |
Result += '+ '; |
|
|
| 261 |
Inc(I); |
|
|
| 262 |
end; |
|
|
| 263 |
$01: |
|
|
| 264 |
begin |
|
|
| 265 |
Result += '- '; |
|
|
| 266 |
Inc(I); |
|
|
| 267 |
end; |
|
|
| 268 |
$02: |
|
|
| 269 |
begin |
|
|
| 270 |
Result += '* '; |
|
|
| 271 |
Inc(I); |
|
|
| 272 |
end; |
|
|
| 273 |
$03: |
|
|
| 274 |
begin |
|
|
| 275 |
Result += '/ '; |
|
|
| 276 |
Inc(I); |
|
|
| 277 |
end; |
|
|
| 278 |
$04: |
|
|
| 279 |
begin |
|
|
| 280 |
Result += '% '; |
|
|
| 281 |
Inc(I); |
|
|
| 282 |
end; |
|
|
| 283 |
$05: |
|
|
| 284 |
begin |
|
|
| 285 |
Result += 'neg '; |
|
|
| 286 |
Inc(I); |
|
|
| 287 |
end; |
|
|
| 288 |
$10: |
|
|
| 289 |
begin |
|
|
| 290 |
Result += '| '; |
|
|
| 291 |
Inc(I); |
|
|
| 292 |
end; |
|
|
| 293 |
$11: |
|
|
| 294 |
begin |
|
|
| 295 |
Result += '& '; |
|
|
| 296 |
Inc(I); |
|
|
| 297 |
end; |
|
|
| 298 |
$12: |
|
|
| 299 |
begin |
|
|
| 300 |
Result += '^ '; |
|
|
| 301 |
Inc(I); |
|
|
| 302 |
end; |
|
|
| 303 |
$13: |
|
|
| 304 |
begin |
|
|
| 305 |
Result += '~ '; |
|
|
| 306 |
Inc(I); |
|
|
| 307 |
end; |
|
|
| 308 |
$21: |
|
|
| 309 |
begin |
|
|
| 310 |
Result += '&& '; |
|
|
| 311 |
Inc(I); |
|
|
| 312 |
end; |
|
|
| 313 |
$22: |
|
|
| 314 |
begin |
|
|
| 315 |
Result += '|| '; |
|
|
| 316 |
Inc(I); |
|
|
| 317 |
end; |
|
|
| 318 |
$23: |
|
|
| 319 |
begin |
|
|
| 320 |
Result += '! '; |
|
|
| 321 |
Inc(I); |
|
|
| 322 |
end; |
|
|
| 323 |
$30: |
|
|
| 324 |
begin |
|
|
| 325 |
Result += '== '; |
|
|
| 326 |
Inc(I); |
|
|
| 327 |
end; |
|
|
| 328 |
$31: |
|
|
| 329 |
begin |
|
|
| 330 |
Result += '!= '; |
|
|
| 331 |
Inc(I); |
|
|
| 332 |
end; |
|
|
| 333 |
$32: |
|
|
| 334 |
begin |
|
|
| 335 |
Result += '> '; |
|
|
| 336 |
Inc(I); |
|
|
| 337 |
end; |
|
|
| 338 |
$33: |
|
|
| 339 |
begin |
|
|
| 340 |
Result += '< '; |
|
|
| 341 |
Inc(I); |
|
|
| 342 |
end; |
|
|
| 343 |
$34: |
|
|
| 344 |
begin |
|
|
| 345 |
Result += '>= '; |
|
|
| 346 |
Inc(I); |
|
|
| 347 |
end; |
|
|
| 348 |
$35: |
|
|
| 349 |
begin |
|
|
| 350 |
Result += '<= '; |
|
|
| 351 |
Inc(I); |
|
|
| 352 |
end; |
|
|
| 353 |
$40: |
|
|
| 354 |
begin |
|
|
| 355 |
Result += '<< '; |
|
|
| 356 |
Inc(I); |
|
|
| 357 |
end; |
|
|
| 358 |
$41: |
|
|
| 359 |
begin |
|
|
| 360 |
Result += '>> '; |
|
|
| 361 |
Inc(I); |
|
|
| 362 |
end; |
|
|
| 363 |
$50: |
|
|
| 364 |
begin |
|
|
| 365 |
Result += '(bank-sym ' + IntToStr(ReadLong) + ') '; |
|
|
| 366 |
end; |
|
|
| 367 |
$51: |
|
|
| 368 |
begin |
|
|
| 369 |
Result += '(bank-section ' + IntToStr(ReadLong) + ') '; |
|
|
| 370 |
end; |
|
|
| 371 |
$52: |
|
|
| 372 |
begin |
|
|
| 373 |
Result += 'current-bank'; |
|
|
| 374 |
Inc(I); |
|
|
| 375 |
end; |
|
|
| 376 |
$60: |
|
|
| 377 |
begin |
|
|
| 378 |
Result += 'hram-check'; |
|
|
| 379 |
Inc(I); |
|
|
| 380 |
end; |
|
|
| 381 |
$61: |
|
|
| 382 |
begin |
|
|
| 383 |
Result += 'rst-check'; |
|
|
| 384 |
Inc(I); |
|
|
| 385 |
end; |
|
|
| 386 |
$80: |
|
|
| 387 |
begin |
|
|
| 388 |
Result += '(int ' + IntToStr(ReadLong) + ') '; |
|
|
| 389 |
end; |
|
|
| 390 |
$81: |
|
|
| 391 |
begin |
|
|
| 392 |
Result += '(sym ' + Syms[ReadLong].Name + ') '; |
|
|
| 393 |
end; |
|
|
| 394 |
else |
|
|
| 395 |
Exit('INVALID!'); |
|
|
| 396 |
end; |
|
|
| 397 |
end; |
|
|
| 398 |
end; |
|
|
| 399 |
|
|
|
| 400 |
function ParseRPN(const RPN: array of byte): TRPN; |
|
|
| 401 |
var |
|
|
| 402 |
I: integer; |
|
|
| 403 |
Node: TRPNNode; |
|
|
| 404 |
|
|
|
| 405 |
function ReadLong: longword; |
|
|
| 406 |
begin |
|
|
| 407 |
Inc(I); |
|
|
| 408 |
Result := RPN[I]; |
|
|
| 409 |
Inc(I); |
|
|
| 410 |
Result := (Result shl 8) or RPN[I]; |
|
|
| 411 |
Inc(I); |
|
|
| 412 |
Result := (Result shl 8) or RPN[I]; |
|
|
| 413 |
Inc(I); |
|
|
| 414 |
Result := (Result shl 8) or RPN[I]; |
|
|
| 415 |
Inc(I); |
|
|
| 416 |
Result := SwapEndian(Result); |
|
|
| 417 |
end; |
|
|
| 418 |
|
|
|
| 419 |
function nd(Tag: TRPNTag): TRPNNode; |
|
|
| 420 |
begin |
|
|
| 421 |
Result.Tag := Tag; |
|
|
| 422 |
end; |
|
|
| 423 |
|
|
|
| 424 |
procedure PushRPN(Node: TRPNNode); |
|
|
| 425 |
begin |
|
|
| 426 |
SetLength(Result, Length(Result) + 1); |
|
|
| 427 |
Result[High(Result)] := Node; |
|
|
| 428 |
end; |
|
|
| 429 |
|
|
|
| 430 |
begin |
|
|
| 431 |
SetLength(Result, 0); |
|
|
| 432 |
I := Low(RPN); |
|
|
| 433 |
while I <= High(RPN) do |
|
|
| 434 |
begin |
|
|
| 435 |
//Writeln(Format('Parsing %x, len=%d', [RPN[I], Length(Result)])); |
|
|
| 436 |
case RPN[I] of |
|
|
| 437 |
$00: |
|
|
| 438 |
begin |
|
|
| 439 |
PushRPN(Nd(rpnPlus)); |
|
|
| 440 |
Inc(I); |
|
|
| 441 |
end; |
|
|
| 442 |
$01: |
|
|
| 443 |
begin |
|
|
| 444 |
PushRPN(Nd(rpnMinus)); |
|
|
| 445 |
Inc(I); |
|
|
| 446 |
end; |
|
|
| 447 |
$02: |
|
|
| 448 |
begin |
|
|
| 449 |
PushRPN(Nd(rpnTimes)); |
|
|
| 450 |
Inc(I); |
|
|
| 451 |
end; |
|
|
| 452 |
$03: |
|
|
| 453 |
begin |
|
|
| 454 |
PushRPN(Nd(rpnDiv)); |
|
|
| 455 |
Inc(I); |
|
|
| 456 |
end; |
|
|
| 457 |
$04: |
|
|
| 458 |
begin |
|
|
| 459 |
PushRPN(Nd(rpnMod)); |
|
|
| 460 |
Inc(I); |
|
|
| 461 |
end; |
|
|
| 462 |
$05: |
|
|
| 463 |
begin |
|
|
| 464 |
PushRPN(Nd(rpnNegate)); |
|
|
| 465 |
Inc(I); |
|
|
| 466 |
end; |
|
|
| 467 |
$10: |
|
|
| 468 |
begin |
|
|
| 469 |
PushRPN(Nd(rpnOr)); |
|
|
| 470 |
Inc(I); |
|
|
| 471 |
end; |
|
|
| 472 |
$11: |
|
|
| 473 |
begin |
|
|
| 474 |
PushRPN(Nd(rpnAnd)); |
|
|
| 475 |
Inc(I); |
|
|
| 476 |
end; |
|
|
| 477 |
$12: |
|
|
| 478 |
begin |
|
|
| 479 |
PushRPN(Nd(rpnXor)); |
|
|
| 480 |
Inc(I); |
|
|
| 481 |
end; |
|
|
| 482 |
$13: |
|
|
| 483 |
begin |
|
|
| 484 |
PushRPN(Nd(rpnComplement)); |
|
|
| 485 |
Inc(I); |
|
|
| 486 |
end; |
|
|
| 487 |
$21: |
|
|
| 488 |
begin |
|
|
| 489 |
PushRPN(Nd(rpnBoolAnd)); |
|
|
| 490 |
Inc(I); |
|
|
| 491 |
end; |
|
|
| 492 |
$22: |
|
|
| 493 |
begin |
|
|
| 494 |
PushRPN(Nd(rpnBoolOr)); |
|
|
| 495 |
Inc(I); |
|
|
| 496 |
end; |
|
|
| 497 |
$23: |
|
|
| 498 |
begin |
|
|
| 499 |
PushRPN(Nd(rpnBoolNeg)); |
|
|
| 500 |
Inc(I); |
|
|
| 501 |
end; |
|
|
| 502 |
$30: |
|
|
| 503 |
begin |
|
|
| 504 |
PushRPN(Nd(rpnEqual)); |
|
|
| 505 |
Inc(I); |
|
|
| 506 |
end; |
|
|
| 507 |
$31: |
|
|
| 508 |
begin |
|
|
| 509 |
PushRPN(Nd(rpnNotEqual)); |
|
|
| 510 |
Inc(I); |
|
|
| 511 |
end; |
|
|
| 512 |
$32: |
|
|
| 513 |
begin |
|
|
| 514 |
PushRPN(Nd(rpnGreater)); |
|
|
| 515 |
Inc(I); |
|
|
| 516 |
end; |
|
|
| 517 |
$33: |
|
|
| 518 |
begin |
|
|
| 519 |
PushRPN(Nd(rpnLess)); |
|
|
| 520 |
Inc(I); |
|
|
| 521 |
end; |
|
|
| 522 |
$34: |
|
|
| 523 |
begin |
|
|
| 524 |
PushRPN(Nd(rpnGreaterEqual)); |
|
|
| 525 |
Inc(I); |
|
|
| 526 |
end; |
|
|
| 527 |
$35: |
|
|
| 528 |
begin |
|
|
| 529 |
PushRPN(Nd(rpnLessEqual)); |
|
|
| 530 |
Inc(I); |
|
|
| 531 |
end; |
|
|
| 532 |
$40: |
|
|
| 533 |
begin |
|
|
| 534 |
PushRPN(Nd(rpnShl)); |
|
|
| 535 |
Inc(I); |
|
|
| 536 |
end; |
|
|
| 537 |
$41: |
|
|
| 538 |
begin |
|
|
| 539 |
PushRPN(Nd(rpnShr)); |
|
|
| 540 |
Inc(I); |
|
|
| 541 |
end; |
|
|
| 542 |
$50: |
|
|
| 543 |
begin |
|
|
| 544 |
Node.Tag := rpnBankSymbol; |
|
|
| 545 |
Node.BankSymbol := ReadLong; |
|
|
| 546 |
PushRPN(Node); |
|
|
| 547 |
end; |
|
|
| 548 |
$51: |
|
|
| 549 |
begin |
|
|
| 550 |
Node.Tag := rpnBankSection; |
|
|
| 551 |
Node.BankSection := ReadLong; |
|
|
| 552 |
PushRPN(Node); |
|
|
| 553 |
end; |
|
|
| 554 |
$52: |
|
|
| 555 |
begin |
|
|
| 556 |
PushRPN(Nd(rpnCurrentBank)); |
|
|
| 557 |
Inc(I); |
|
|
| 558 |
end; |
|
|
| 559 |
$60: |
|
|
| 560 |
begin |
|
|
| 561 |
PushRPN(Nd(rpnHramCheck)); |
|
|
| 562 |
Inc(I); |
|
|
| 563 |
end; |
|
|
| 564 |
$61: |
|
|
| 565 |
begin |
|
|
| 566 |
PushRPN(Nd(rpnRstCheck)); |
|
|
| 567 |
Inc(I); |
|
|
| 568 |
end; |
|
|
| 569 |
$80: |
|
|
| 570 |
begin |
|
|
| 571 |
Node.Tag := rpnInteger; |
|
|
| 572 |
Node.IntValue := ReadLong; |
|
|
| 573 |
PushRPN(Node); |
|
|
| 574 |
end; |
|
|
| 575 |
$81: |
|
|
| 576 |
begin |
|
|
| 577 |
Node.Tag := rpnSymbol; |
|
|
| 578 |
Node.SymbolID := ReadLong; |
|
|
| 579 |
PushRPN(Node); |
|
|
| 580 |
end; |
|
|
| 581 |
else |
|
|
| 582 |
Die('Got malformed RPN!'); |
|
|
| 583 |
end; |
|
|
| 584 |
end; |
|
|
| 585 |
end; |
|
|
| 586 |
|
|
|
| 587 |
|
|
|
| 588 |
procedure PrintObjFile(O: TRObj); |
|
|
| 589 |
var |
|
|
| 590 |
Sym: TRSymbol; |
|
|
| 591 |
Sect: TRSection; |
|
|
| 592 |
Patch: TRPatch; |
|
|
| 593 |
SectSize: integer; |
|
|
| 594 |
begin |
|
|
| 595 |
WriteLn('Symbols:'); |
|
|
| 596 |
for Sym in O.Symbols do |
|
|
| 597 |
Writeln(Format(' %s on %d: type=%d, section=%d, value=%d', |
|
|
| 598 |
[Sym.Name, Sym.LineNum, Sym.SymType, Sym.SectionID, Sym.Value])); |
|
|
| 599 |
|
|
|
| 600 |
SectSize := 0; |
|
|
| 601 |
for Sect in O.Sections do |
|
|
| 602 |
if (Sect.Org <> -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then |
|
|
| 603 |
Inc(SectSize, Sect.Size); |
|
|
| 604 |
Writeln('Absolute sections: ', SectSize, ' bytes'); |
|
|
| 605 |
|
|
|
| 606 |
SectSize := 0; |
|
|
| 607 |
for Sect in O.Sections do |
|
|
| 608 |
if (Sect.Org = -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then |
|
|
| 609 |
Inc(SectSize, Sect.Size); |
|
|
| 610 |
Writeln('Relative sections: ', SectSize, ' bytes'); |
|
|
| 611 |
|
|
|
| 612 |
WriteLn('Sections:'); |
|
|
| 613 |
for Sect in O.Sections do |
|
|
| 614 |
begin |
|
|
| 615 |
Writeln(Format(' %s with size %d: offset=%d, patches=%d, bank=%d', |
|
|
| 616 |
[Sect.Name, Sect.Size, Sect.Org, Sect.NumberOfPatches, Sect.Bank])); |
|
|
| 617 |
|
|
|
| 618 |
for Patch in Sect.Patches do |
|
|
| 619 |
Writeln(Format(' %s: %d ; %s', [Patch.SourceFile, Patch.PatchType, |
|
|
| 620 |
RPNToString(Patch.RPN, O.Symbols)])); |
|
|
| 621 |
end; |
|
|
| 622 |
end; |
|
|
| 623 |
|
|
|
| 624 |
function FindPatch(const Section: TRSection; Index: integer; |
|
|
| 625 |
out Patch: TRPatch): boolean; |
|
|
| 626 |
var |
|
|
| 627 |
I: integer; |
|
|
| 628 |
begin |
|
|
| 629 |
for I := Low(Section.Patches) to High(Section.Patches) do |
|
|
| 630 |
if Section.Patches[I].Offset = Index then |
|
|
| 631 |
begin |
|
|
| 632 |
Patch := Section.Patches[I]; |
|
|
| 633 |
Exit(True); |
|
|
| 634 |
end; |
|
|
| 635 |
|
|
|
| 636 |
Result := False; |
|
|
| 637 |
end; |
|
|
| 638 |
|
|
|
| 639 |
procedure ConvertRGB2SDAS(SourceName, DestName: String); |
|
|
| 640 |
var |
|
|
| 641 |
RObj: TRObj; |
|
|
| 642 |
|
|
|
| 643 |
Symbol: TRSymbol; |
|
|
| 644 |
Section: TRSection; |
|
|
| 645 |
Patch: TRPatch; |
|
|
| 646 |
|
|
|
| 647 |
F: Text; |
|
|
| 648 |
|
|
|
| 649 |
ValueToWrite: word; |
|
|
| 650 |
RPN: TRPN; |
|
|
| 651 |
I: word; |
|
|
| 652 |
Sct: word; |
|
|
| 653 |
WritePos: word; |
|
|
| 654 |
Idx: integer; |
|
|
| 655 |
CODESEG: string; |
|
|
| 656 |
DefaultBank: integer = 1; |
|
|
| 657 |
tmp: string; |
|
|
| 658 |
|
|
|
| 659 |
old_sym, new_sym: string; |
|
|
| 660 |
|
|
|
| 661 |
verbose: boolean = False; |
|
|
| 662 |
|
|
|
| 663 |
export_all: boolean = False; |
|
|
| 664 |
begin |
|
|
| 665 |
if not FileExists(sourcename) then |
|
|
| 666 |
Die('File not found: %s', [sourcename]); |
|
|
| 667 |
|
|
|
| 668 |
old_sym := ''; |
|
|
| 669 |
new_sym := ''; |
|
|
| 670 |
|
|
|
| 671 |
CODESEG := '_CODE'; |
|
|
| 672 |
{for I:= 1 to ParamCount() - 1 do begin |
|
|
| 673 |
tmp:= ParamStr(i); |
|
|
| 674 |
if (CompareText(tmp, '-v') = 0) then |
|
|
| 675 |
verbose:= true |
|
|
| 676 |
else if (CompareText(copy(tmp, 1, 2), '-e') = 0) then |
|
|
| 677 |
export_all:= true |
|
|
| 678 |
else if (CompareText(copy(tmp, 1, 2), '-c') = 0) then begin |
|
|
| 679 |
CODESEG:= copy(tmp, 3, length(tmp)); |
|
|
| 680 |
if length(CODESEG) = 0 then CODESEG:= '_CODE'; |
|
|
| 681 |
if verbose then writeln('Using CODESEG: ', CODESEG); |
|
|
| 682 |
end else if (CompareText(copy(tmp, 1, 2), '-b') = 0) then begin |
|
|
| 683 |
DefaultBank:= StrToIntDef(copy(tmp, 3, length(tmp)), DefaultBank); |
|
|
| 684 |
if verbose then writeln('Using DefaultBank: ', DefaultBank); |
|
|
| 685 |
end else if (CompareText(copy(tmp, 1, 2), '-r') = 0) then begin |
|
|
| 686 |
tmp:= copy(tmp, 3, length(tmp)); |
|
|
| 687 |
Idx:= pos('=', tmp); |
|
|
| 688 |
if (idx > 0) then begin |
|
|
| 689 |
old_sym:= copy(tmp, 1, idx - 1); |
|
|
| 690 |
new_sym:= copy(tmp, idx + 1, length(tmp)); |
|
|
| 691 |
end; |
|
|
| 692 |
end; |
|
|
| 693 |
end;} |
|
|
| 694 |
|
|
|
| 695 |
RObj := ReadObjFile(sourcename); |
|
|
| 696 |
if verbose then |
|
|
| 697 |
PrintObjFile(RObj); |
|
|
| 698 |
|
|
|
| 699 |
Assign(F, DestName); |
|
|
| 700 |
Rewrite(F); |
|
|
| 701 |
try |
|
|
| 702 |
Idx := 0; |
|
|
| 703 |
// pass 1: all imports first |
|
|
| 704 |
for I := Low(RObj.Symbols) to High(RObj.Symbols) do |
|
|
| 705 |
with RObj.Symbols[I] do |
|
|
| 706 |
begin |
|
|
| 707 |
if ((SymType and $7f) = SYM_IMPORT) then |
|
|
| 708 |
begin |
|
|
| 709 |
No := Idx; |
|
|
| 710 |
Inc(Idx); |
|
|
| 711 |
end |
|
|
| 712 |
else |
|
|
| 713 |
No := -1; |
|
|
| 714 |
end; |
|
|
| 715 |
// pass 2: all other (export local only when forced) |
|
|
| 716 |
for I := Low(RObj.Symbols) to High(RObj.Symbols) do |
|
|
| 717 |
with RObj.Symbols[I] do |
|
|
| 718 |
begin |
|
|
| 719 |
case (SymType and $7f) of |
|
|
| 720 |
SYM_LOCAL: if export_all then |
|
|
| 721 |
begin |
|
|
| 722 |
No := Idx; |
|
|
| 723 |
Inc(Idx); |
|
|
| 724 |
end; |
|
|
| 725 |
SYM_IMPORT: ; |
|
|
| 726 |
SYM_EXPORT: |
|
|
| 727 |
begin |
|
|
| 728 |
// rename exported symbol if requested |
|
|
| 729 |
if (length(old_sym) > 0) and (Name = old_sym) then |
|
|
| 730 |
Name := new_sym; |
|
|
| 731 |
No := Idx; |
|
|
| 732 |
Inc(Idx); |
|
|
| 733 |
end; |
|
|
| 734 |
else |
|
|
| 735 |
Die('Unsupported symbol type: %d', [SymType and $7f]); |
|
|
| 736 |
end; |
|
|
| 737 |
end; |
|
|
| 738 |
|
|
|
| 739 |
// output object header |
|
|
| 740 |
Writeln(F, 'XL2'); |
|
|
| 741 |
Writeln(F, Format('H %x areas %x global symbols', [RObj.NumberOfSections, idx])); |
|
|
| 742 |
Writeln(F, Format('M %s', [StringReplace(ExtractFileName(sourcename), |
|
|
| 743 |
'.', '_', [rfReplaceAll])])); |
|
|
| 744 |
Writeln(F, 'O -mgbz80'); |
|
|
| 745 |
|
|
|
| 746 |
// output all imported symbols |
|
|
| 747 |
for I := Low(RObj.Symbols) to High(RObj.Symbols) do |
|
|
| 748 |
with RObj.Symbols[I] do |
|
|
| 749 |
if (SymType = SYM_IMPORT) then |
|
|
| 750 |
Writeln(F, Format('S %s Ref%.4x', |
|
|
| 751 |
[StringReplace(Name, '.', '____', [rfReplaceAll]), 0])); |
|
|
| 752 |
|
|
|
| 753 |
// output all sections and other symbols |
|
|
| 754 |
for Section in RObj.Sections do |
|
|
| 755 |
begin |
|
|
| 756 |
if Section.Org = -1 then |
|
|
| 757 |
case Section.SectType of |
|
|
| 758 |
ROM0: Writeln(F, Format('A %s size %x flags 0 addr 0', |
|
|
| 759 |
[CODESEG, Section.Size])); |
|
|
| 760 |
ROMX: if (DefaultBank = 0) then |
|
|
| 761 |
Writeln(F, Format('A %s size %x flags 0 addr 0', [CODESEG, Section.Size])) |
|
|
| 762 |
else |
|
|
| 763 |
Writeln(F, Format('A _CODE_%d size %x flags 0 addr 0', |
|
|
| 764 |
[max(DefaultBank, Section.Bank), Section.Size])); |
|
|
| 765 |
else |
|
|
| 766 |
Writeln(F, Format('A _DATA size %x flags 0 addr 0', [Section.Size])); |
|
|
| 767 |
end |
|
|
| 768 |
else |
|
|
| 769 |
Die('absolute sections currently unsupported: %s', [Section.Name]); |
|
|
| 770 |
|
|
|
| 771 |
for Symbol in RObj.Symbols do |
|
|
| 772 |
if Symbol.SectionID = Section.ID then |
|
|
| 773 |
begin |
|
|
| 774 |
if (Symbol.SymType <> SYM_IMPORT) and (Symbol.No >= 0) then |
|
|
| 775 |
Writeln(F, Format('S %s Def%.4x', |
|
|
| 776 |
[StringReplace(Symbol.Name, '.', '____', [rfReplaceAll]), Symbol.Value])); |
|
|
| 777 |
end; |
|
|
| 778 |
end; |
|
|
| 779 |
|
|
|
| 780 |
// convert object itself |
|
|
| 781 |
for Sct := Low(RObj.Sections) to High(RObj.Sections) do |
|
|
| 782 |
begin |
|
|
| 783 |
Section := RObj.Sections[Sct]; |
|
|
| 784 |
|
|
|
| 785 |
if (Section.SectType <> ROMX) and (Section.SectType <> ROM0) then |
|
|
| 786 |
Continue; |
|
|
| 787 |
if Length(Section.Data) <= 0 then |
|
|
| 788 |
Continue; |
|
|
| 789 |
|
|
|
| 790 |
I := Low(Section.Data); |
|
|
| 791 |
while I <= High(Section.Data) do |
|
|
| 792 |
begin |
|
|
| 793 |
WritePos := I; |
|
|
| 794 |
if (Section.Org <> -1) then |
|
|
| 795 |
Inc(WritePos, Section.Org); |
|
|
| 796 |
|
|
|
| 797 |
if FindPatch(Section, I, Patch) then |
|
|
| 798 |
begin |
|
|
| 799 |
case Patch.PatchType of |
|
|
| 800 |
PATCH_LE_WORD: |
|
|
| 801 |
begin |
|
|
| 802 |
RPN := ParseRPN(Patch.RPN); |
|
|
| 803 |
Symbol := RObj.Symbols[RPN[0].SymbolID]; |
|
|
| 804 |
ValueToWrite := Symbol.Value; |
|
|
| 805 |
if RPN[High(RPN)].Tag = rpnPlus then |
|
|
| 806 |
Inc(ValueToWrite, RPN[1].IntValue); |
|
|
| 807 |
|
|
|
| 808 |
if (Symbol.SymType = SYM_IMPORT) then |
|
|
| 809 |
begin |
|
|
| 810 |
if (Symbol.No < 0) then |
|
|
| 811 |
Die('Trying to reference eliminated symbol'); |
|
|
| 812 |
Writeln(F, Format('T %.2x %.2x %.2x %.2x', |
|
|
| 813 |
[lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)])); |
|
|
| 814 |
Writeln(F, |
|
|
| 815 |
Format('R 00 00 %.2x %.2x 02 02 %.2x %.2x', [lo(Sct), hi(Sct), |
|
|
| 816 |
lo(Symbol.No), hi(Symbol.No)])); |
|
|
| 817 |
end |
|
|
| 818 |
else |
|
|
| 819 |
begin |
|
|
| 820 |
Writeln(F, Format('T %.2x %.2x %.2x %.2x', |
|
|
| 821 |
[lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)])); |
|
|
| 822 |
Writeln(F, |
|
|
| 823 |
Format('R 00 00 %.2x %.2x 00 02 %.2x %.2x', [lo(Sct), hi(Sct), |
|
|
| 824 |
lo(Symbol.SectionID), hi(Symbol.SectionID)])); |
|
|
| 825 |
end; |
|
|
| 826 |
Inc(I, 2); |
|
|
| 827 |
end; |
|
|
| 828 |
PATCH_JR: |
|
|
| 829 |
begin |
|
|
| 830 |
RPN := ParseRPN(Patch.RPN); |
|
|
| 831 |
if Length(RPN) > 1 then |
|
|
| 832 |
Die('Not handling bigger RPN on JR'); |
|
|
| 833 |
Symbol := RObj.Symbols[RPN[0].SymbolID]; |
|
|
| 834 |
Writeln(F, Format('T %.2x %.2x %.2x', |
|
|
| 835 |
[lo(WritePos), hi(WritePos), byte(Symbol.Value - I - 1)])); |
|
|
| 836 |
Writeln(F, Format('R 00 00 %.2x %.2x', |
|
|
| 837 |
[lo(Sct), hi(Sct)])); |
|
|
| 838 |
Inc(I); |
|
|
| 839 |
end |
|
|
| 840 |
else |
|
|
| 841 |
Die('Unsupported patch type: %d', [Patch.PatchType]); |
|
|
| 842 |
end; |
|
|
| 843 |
end |
|
|
| 844 |
else |
|
|
| 845 |
begin |
|
|
| 846 |
Writeln(F, Format('T %.2x %.2x %.2x', |
|
|
| 847 |
[lo(WritePos), hi(WritePos), Section.Data[I]])); |
|
|
| 848 |
Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct), hi(Sct)])); |
|
|
| 849 |
Inc(I); |
|
|
| 850 |
end; |
|
|
| 851 |
end; |
|
|
| 852 |
end; |
|
|
| 853 |
|
|
|
| 854 |
//Writeln('rgb2sdas converting ',sourcename,' --> ',sourcename,'.o result: success!'); |
|
|
| 855 |
finally |
|
|
| 856 |
Close(F); |
|
|
| 857 |
end; |
|
|
| 858 |
end; |
|
|
| 859 |
|
|
|
| 860 |
begin |
|
|
| 861 |
end. |
|
|