Commit 39f3f2c

Nick committed on
WIP adding export formats/work towards release
commit 39f3f2c9a539c262f3e4bf5981619883b3ffc48f parent 300fc9e
5 changed files +757−356
Modifiedcodegen.pas +46−35
@@ -7,19 +7,19 @@ interface
7 uses 7 uses
8 Classes, SysUtils, Math, Instruments, Song, Utils, 8 Classes, SysUtils, Math, Instruments, Song, Utils,
9 HugeDatatypes, Constants, Dialogs, strutils, FileUtil, LazFileUtils, 9 HugeDatatypes, Constants, Dialogs, strutils, FileUtil, LazFileUtils,
10 lclintf, process; 10 lclintf, process, rgb2sdas;
11 11
12 type 12 type
13 TExportMode = (emNormal, emPreview, emGBS, emRGBDSObj, emGBDKObj, emGBDKC); 13 TExportMode = (emNormal, emPreview, emGBS, emRGBDSObj, emGBDKObj);
14 14
15 function RenderPreviewRom(Song: TSong): boolean; 15 function RenderPreviewRom(Song: TSong): boolean;
16 function RenderSongToFile(Song: TSong; Filename: string; 16 function RenderSongToFile(Song: TSong; Filename: string;
17 Mode: TExportMode = emNormal): boolean; 17 Mode: TExportMode = emNormal; DescriptorName: String = 'song_descriptor'): boolean;
18 procedure RenderSongToGBDKC(Song: TSong; Filename: string); 18 procedure RenderSongToGBDKC(Song: TSong; DescriptorName: String; Filename: string);
19 19
20 implementation 20 implementation
21 21
22 procedure RenderSongToGBDKC(Song: TSong; Filename: string); 22 procedure RenderSongToGBDKC(Song: TSong; DescriptorName: String; Filename: string);
23 var 23 var
24 OrderMatrix: TOrderMatrix; 24 OrderMatrix: TOrderMatrix;
25 OutSL: TStringList; 25 OutSL: TStringList;
@@ -35,10 +35,9 @@ var
35 SL.Delimiter := ','; 35 SL.Delimiter := ',';
36 36
37 if Cell.Note = NO_NOTE then 37 if Cell.Note = NO_NOTE then
38 SL.Add('90') 38 SL.Add('___')
39 //SL.Add('___') 39 else
40 else SL.Add(IntToStr(Cell.Note)); 40 SL.Add(NoteToCMap.KeyData[Cell.Note]);
41 //SL.Add(NoteToDriverMap.KeyData[Cell.Note]);
42 41
43 if InRange(Cell.Instrument, 0, 15) then 42 if InRange(Cell.Instrument, 0, 15) then
44 SL.Add(IntToStr(Cell.Instrument)) 43 SL.Add(IntToStr(Cell.Instrument))
@@ -117,9 +116,10 @@ var
117 var 116 var
118 I: integer; 117 I: integer;
119 begin 118 begin
120 Result := 'static const unsigned char ' + Name + '[] = {'; 119 Result := 'static const unsigned char ' + Name + '[] = {'+LineEnding;
121 for I := Low(Bank) to High(Bank) do 120 for I := Low(Bank) to High(Bank) do begin
122 Result += RenderGBDKInstrument(Bank[I]) + ','; 121 Result += RenderGBDKInstrument(Bank[I]) + ','+LineEnding;
122 end;
123 Result += '};'; 123 Result += '};';
124 end; 124 end;
125 125
@@ -127,9 +127,10 @@ var
127 var 127 var
128 I, J: integer; 128 I, J: integer;
129 begin 129 begin
130 Result := 'static const unsigned char waves[] = {'; 130 Result := 'static const unsigned char waves[] = {'+LineEnding;
131 for I := Low(Waves) to High(Waves) do 131 for I := Low(Waves) to High(Waves) do
132 begin 132 begin
133 Result += ' ';
133 J := Low(Waves[I]); 134 J := Low(Waves[I]);
134 while J < High(Waves[I]) do 135 while J < High(Waves[I]) do
135 begin 136 begin
@@ -146,12 +147,6 @@ begin
146 OutSL.Add('#include "hUGEDriver.h"'); 147 OutSL.Add('#include "hUGEDriver.h"');
147 OutSL.Add('#include <stddef.h>'); 148 OutSL.Add('#include <stddef.h>');
148 OutSL.Add(''); 149 OutSL.Add('');
149 OutSL.Add('#ifndef SONG_VAR_NAME');
150 OutSL.Add('#define SONG_VAR_NAME song');
151 OutSL.Add('#endif');
152 OutSL.Add('');
153 OutSL.Add('#define DN(A, B, C) (A),((B << 4) | (C >> 8)),(C & 0xF)');
154 OutSL.Add('');
155 150
156 OrderMatrix := Song.OrderMatrix; 151 OrderMatrix := Song.OrderMatrix;
157 OrderCnt := MaxIntValue([High(OrderMatrix[0]), High(OrderMatrix[1]), 152 OrderCnt := MaxIntValue([High(OrderMatrix[0]), High(OrderMatrix[1]),
@@ -182,9 +177,9 @@ begin
182 OutSL.Add(''); 177 OutSL.Add('');
183 178
184 OutSL.Add(Format( 179 OutSL.Add(Format(
185 'const hUGESong_t SONG_VAR_NAME = {%d, &order_cnt, order1, order2, order3,'+ 180 'const hUGESong_t %s = {%d, &order_cnt, order1, order2, order3,'+
186 'order4, duty_instruments, wave_instruments, noise_instruments, NULL, waves};', 181 'order4, duty_instruments, wave_instruments, noise_instruments, NULL, waves};',
187 [Song.TicksPerRow])); 182 [DescriptorName, Song.TicksPerRow]));
188 183
189 AssignFile(F, Filename); 184 AssignFile(F, Filename);
190 Rewrite(F); 185 Rewrite(F);
@@ -401,14 +396,16 @@ begin
401 Result := RenderSongToFile(Song, 'preview.gb', emPreview); 396 Result := RenderSongToFile(Song, 'preview.gb', emPreview);
402 end; 397 end;
403 398
404 function RenderSongToFile(Song: TSong; Filename: string; 399 function RenderSongToFile(Song: TSong; Filename: String;
405 Mode: TExportMode = emNormal): boolean; 400 Mode: TExportMode = emNormal; DescriptorName: String = 'song_descriptor'): boolean;
401 { TODO: Refactor this whole monstrosity. }
406 var 402 var
407 OutFile: Text; 403 OutFile: Text;
408 I: integer; 404 I: integer;
409 Proc: TProcess; 405 Proc: TProcess;
410 OutSL: TStringList; 406 OutSL: TStringList;
411 FilePath: string; 407 FilePath: string;
408 RenameSucceeded: Boolean;
412 409
413 procedure WriteHTT(F: string; S: string); 410 procedure WriteHTT(F: string; S: string);
414 begin 411 begin
@@ -499,8 +496,6 @@ begin
499 poNoConsole]; 496 poNoConsole];
500 497
501 // Assemble 498 // Assemble
502
503 // TODO: this is fugly, wish there was a ternary operator in this language...
504 if Mode = emPreview then 499 if Mode = emPreview then
505 begin 500 begin
506 if Assemble(Filename + '_driver.obj', 'driver.z80', ['PREVIEW_MODE']) <> 0 then 501 if Assemble(Filename + '_driver.obj', 'driver.z80', ['PREVIEW_MODE']) <> 0 then
@@ -512,17 +507,17 @@ begin
512 goto AssemblyError; 507 goto AssemblyError;
513 end; 508 end;
514 509
515 if Assemble(Filename + '_song.obj', 'song.z80', []) <> 0 then 510 if Assemble(Filename + '_song.obj', 'song.z80', ['SONG_DESCRIPTOR=_'+DescriptorName]) <> 0 then
516 goto AssemblyError; 511 goto AssemblyError;
517 512
518 if Mode = emGBS then 513 if Mode = emGBS then
519 begin 514 begin
520 if Assemble(Filename + '_gbs.obj', 'gbs.z80', []) <> 0 then 515 if Assemble(Filename + '_gbs.obj', 'gbs.z80', ['SONG_DESCRIPTOR=_'+DescriptorName]) <> 0 then
521 goto AssemblyError; 516 goto AssemblyError;
522 end 517 end
523 else 518 else
524 begin 519 begin
525 if Assemble(Filename + '_player.obj', 'player.z80', []) <> 0 then 520 if Assemble(Filename + '_player.obj', 'player.z80', ['SONG_DESCRIPTOR=_'+DescriptorName]) <> 0 then
526 goto AssemblyError; 521 goto AssemblyError;
527 end; 522 end;
528 523
@@ -556,7 +551,17 @@ begin
556 if FileExists(FilePath) then 551 if FileExists(FilePath) then
557 DeleteFile(FilePath); 552 DeleteFile(FilePath);
558 553
559 if not RenameFile(Filename + IfThen(Mode = emGBS, '.gbs', '.gb'), FilePath) then 554 case Mode of
555 emGBS: RenameSucceeded := RenameFile(Filename + '.gbs', FilePath);
556 emRGBDSObj: RenameSucceeded := RenameFile(Filename + '_song.obj', FilePath);
557 emGBDKObj: begin
558 RenameSucceeded := RenameFile(Filename + '_song.obj', FilePath);
559 ConvertRGB2SDAS(FilePath);
560 end
561 else RenameSucceeded := RenameFile(Filename + '.gb', FilePath);
562 end;
563
564 if not RenameSucceeded then
560 begin 565 begin
561 MessageDlg('Error!', 566 MessageDlg('Error!',
562 'Couldn''t create file at ' + FilePath + 567 'Couldn''t create file at ' + FilePath +
@@ -568,12 +573,18 @@ begin
568 goto Cleanup; 573 goto Cleanup;
569 end; 574 end;
570 {$ifdef DEVELOPMENT} 575 {$ifdef DEVELOPMENT}
571 RenameFile(Filename + '.obj', FilePath + '.obj'); 576 RenameFile(Filename + '_driver.obj', FilePath + '_driver.obj');
572 RenameFile(Filename + '.sym', FilePath + '.sym'); 577 RenameFile(Filename + '_song.obj', FilePath + '_driver.obj');
573 RenameFile(Filename + '.map', FilePath + '.map'); 578 RenameFile(Filename + '_player.obj', FilePath + '_driver.obj');
579 RenameFile(Filename + '_gbs.obj', FilePath + '_gbs.obj');
580 RenameFile(Filename + '.sym', FilePath + '.sym');
581 RenameFile(Filename + '.map', FilePath + '.map');
574 {$endif} 582 {$endif}
575 {$ifdef PRODUCTION} 583 {$ifdef PRODUCTION}
576 DeleteFile(Filename + '.obj'); 584 DeleteFile(Filename + '_driver.obj');
585 DeleteFile(Filename + '_song.obj');
586 DeleteFile(Filename + '_player.obj');
587 DeleteFile(Filename + '_gbs.obj');
577 DeleteFile(Filename + '.sym'); 588 DeleteFile(Filename + '.sym');
578 DeleteFile(Filename + '.map'); 589 DeleteFile(Filename + '.map');
579 {$endif} 590 {$endif}
@@ -609,11 +620,11 @@ begin
609 620
610 {$ifdef PRODUCTION} 621 {$ifdef PRODUCTION}
611 OpenURL('https://github.com/SuperDisk/hUGETracker/issues'); 622 OpenURL('https://github.com/SuperDisk/hUGETracker/issues');
612 {$endif} 623 {$endif}
613 end; 624 end;
614 625
615 Cleanup: 626 Cleanup:
616 Proc.Free; 627 Proc.Free;
617 OutSL.Free; 628 OutSL.Free;
618 Chdir('..'); 629 Chdir('..');
619 end; 630 end;
Modifiedconstants.pas +77−2
@@ -141,8 +141,7 @@ const
141 NO_NOTE = 90; 141 NO_NOTE = 90;
142 142
143 var 143 var
144 NoteMap: TNoteMap; 144 NoteMap, NoteToDriverMap, NoteToCMap: TNoteMap;
145 NoteToDriverMap: TNoteMap;
146 NotesToFreqs: TNoteToFreqMap; 145 NotesToFreqs: TNoteToFreqMap;
147 NoteToCodeMap: TNoteToCodeMap; 146 NoteToCodeMap: TNoteToCodeMap;
148 147
@@ -161,6 +160,7 @@ end;
161 begin 160 begin
162 NoteMap := TNoteMap.Create; 161 NoteMap := TNoteMap.Create;
163 NoteToDriverMap := TNoteMap.Create; 162 NoteToDriverMap := TNoteMap.Create;
163 NoteToCMap := TNoteMap.Create;
164 164
165 NotesToFreqs := TNoteToFreqMap.Create; 165 NotesToFreqs := TNoteToFreqMap.Create;
166 NoteToCodeMap := TNoteToCodeMap.Create; 166 NoteToCodeMap := TNoteToCodeMap.Create;
@@ -465,4 +465,79 @@ begin
465 NoteToDriverMap.add(B_8, 'B_8'); 465 NoteToDriverMap.add(B_8, 'B_8');
466 {%EndRegion} 466 {%EndRegion}
467 467
468 {%Region Notes -> C constants}
469 NoteToCMap.add(C_3, 'C_3');
470 NoteToCMap.add(Cs3, 'Cs3');
471 NoteToCMap.add(D_3, 'D_3');
472 NoteToCMap.add(Ds3, 'Ds3');
473 NoteToCMap.add(E_3, 'E_3');
474 NoteToCMap.add(F_3, 'F_3');
475 NoteToCMap.add(Fs3, 'Fs3');
476 NoteToCMap.add(G_3, 'G_3');
477 NoteToCMap.add(Gs3, 'Gs3');
478 NoteToCMap.add(A_3, 'A_3');
479 NoteToCMap.add(As3, 'As3');
480 NoteToCMap.add(B_3, 'B_3');
481 NoteToCMap.add(C_4, 'C_4');
482 NoteToCMap.add(Cs4, 'Cs4');
483 NoteToCMap.add(D_4, 'D_4');
484 NoteToCMap.add(Ds4, 'Ds4');
485 NoteToCMap.add(E_4, 'E_4');
486 NoteToCMap.add(F_4, 'F_4');
487 NoteToCMap.add(Fs4, 'Fs4');
488 NoteToCMap.add(G_4, 'G_4');
489 NoteToCMap.add(Gs4, 'Gs4');
490 NoteToCMap.add(A_4, 'A_4');
491 NoteToCMap.add(As4, 'As4');
492 NoteToCMap.add(B_4, 'B_4');
493 NoteToCMap.add(C_5, 'C_5');
494 NoteToCMap.add(Cs5, 'Cs5');
495 NoteToCMap.add(D_5, 'D_5');
496 NoteToCMap.add(Ds5, 'Ds5');
497 NoteToCMap.add(E_5, 'E_5');
498 NoteToCMap.add(F_5, 'F_5');
499 NoteToCMap.add(Fs5, 'Fs5');
500 NoteToCMap.add(G_5, 'G_5');
501 NoteToCMap.add(Gs5, 'Gs5');
502 NoteToCMap.add(A_5, 'A_5');
503 NoteToCMap.add(As5, 'As5');
504 NoteToCMap.add(B_5, 'B_5');
505 NoteToCMap.add(C_6, 'C_6');
506 NoteToCMap.add(Cs6, 'Cs6');
507 NoteToCMap.add(D_6, 'D_6');
508 NoteToCMap.add(Ds6, 'Ds6');
509 NoteToCMap.add(E_6, 'E_6');
510 NoteToCMap.add(F_6, 'F_6');
511 NoteToCMap.add(Fs6, 'Fs6');
512 NoteToCMap.add(G_6, 'G_6');
513 NoteToCMap.add(Gs6, 'Gs6');
514 NoteToCMap.add(A_6, 'A_6');
515 NoteToCMap.add(As6, 'As6');
516 NoteToCMap.add(B_6, 'B_6');
517 NoteToCMap.add(C_7, 'C_7');
518 NoteToCMap.add(Cs7, 'Cs7');
519 NoteToCMap.add(D_7, 'D_7');
520 NoteToCMap.add(Ds7, 'Ds7');
521 NoteToCMap.add(E_7, 'E_7');
522 NoteToCMap.add(F_7, 'F_7');
523 NoteToCMap.add(Fs7, 'Fs7');
524 NoteToCMap.add(G_7, 'G_7');
525 NoteToCMap.add(Gs7, 'Gs7');
526 NoteToCMap.add(A_7, 'A_7');
527 NoteToCMap.add(As7, 'As7');
528 NoteToCMap.add(B_7, 'B_7');
529 NoteToCMap.add(C_8, 'C_8');
530 NoteToCMap.add(Cs8, 'Cs8');
531 NoteToCMap.add(D_8, 'D_8');
532 NoteToCMap.add(Ds8, 'Ds8');
533 NoteToCMap.add(E_8, 'E_8');
534 NoteToCMap.add(F_8, 'F_8');
535 NoteToCMap.add(Fs8, 'Fs8');
536 NoteToCMap.add(G_8, 'G_8');
537 NoteToCMap.add(Gs8, 'Gs8');
538 NoteToCMap.add(A_8, 'A_8');
539 NoteToCMap.add(As8, 'As8');
540 NoteToCMap.add(B_8, 'B_8');
541 {%EndRegion}
542
468 end. 543 end.
Modifiedrgb2sdas.pas +598−298
@@ -1,56 +1,58 @@
1 program rgb2sdas; 1 unit rgb2sdas;
2 2
3 {$mode objfpc}{$H+} 3 {$mode objfpc}{$H+}
4 4
5 interface
6
5 uses 7 uses
6 {$IFDEF UNIX}{$IFDEF UseCThreads} 8 {$IFDEF UNIX}{$IFDEF UseCThreads}
7 cthreads, 9 cthreads,
8 {$ENDIF}{$ENDIF} 10 {$ENDIF}{$ENDIF}
9 Classes, SysUtils, strutils, math 11 Classes, SysUtils, strutils, Math
10 { you can add units after this }; 12 { you can add units after this };
11 13
12 type 14 type
13 TRSymbol = packed record 15 TRSymbol = packed record
14 ID: Integer; 16 ID: integer;
15 Name: String; 17 Name: string;
16 SymType: Byte; 18 SymType: byte;
17 19
18 No: Integer; 20 No: integer;
19 21
20 FileName: String; 22 FileName: string;
21 LineNum, SectionID, Value: LongInt; 23 LineNum, SectionID, Value: longint;
22 end; 24 end;
23 25
24 TRPatch = packed record 26 TRPatch = packed record
25 SourceFile: String; 27 SourceFile: string;
26 Offset: LongInt; 28 Offset: longint;
27 PCSectionID: LongInt; 29 PCSectionID: longint;
28 PCOffset: LongInt; 30 PCOffset: longint;
29 PatchType: Byte; 31 PatchType: byte;
30 RPNSize: LongInt; 32 RPNSize: longint;
31 RPN: array of Byte; 33 RPN: array of byte;
32 end; 34 end;
33 35
34 TRSection = packed record 36 TRSection = packed record
35 ID: Integer; 37 ID: integer;
36 Name: String; 38 Name: string;
37 Size: LongInt; 39 Size: longint;
38 SectType: Byte; 40 SectType: byte;
39 Org: LongInt; 41 Org: longint;
40 Bank: LongInt; 42 Bank: longint;
41 Align: Byte; 43 Align: byte;
42 Ofs: LongInt; 44 Ofs: longint;
43 45
44 Data: array of Byte; 46 Data: array of byte;
45 NumberOfPatches: LongInt; 47 NumberOfPatches: longint;
46 Patches: array of TRPatch; 48 Patches: array of TRPatch;
47 end; 49 end;
48 50
49 TRObj = packed record 51 TRObj = packed record
50 ID: array[0..3] of AnsiChar; 52 ID: array[0..3] of AnsiChar;
51 RevisionNumber: LongInt; 53 RevisionNumber: longint;
52 NumberOfSymbols: LongInt; 54 NumberOfSymbols: longint;
53 NumberOfSections: LongInt; 55 NumberOfSections: longint;
54 56
55 Symbols: array of TRSymbol; 57 Symbols: array of TRSymbol;
56 Sections: array of TRSection; 58 Sections: array of TRSection;
@@ -87,28 +89,37 @@ type
87 rpnSymbol); 89 rpnSymbol);
88 90
89 TRPNNode = record 91 TRPNNode = record
90 case Tag: TRPNTag of 92 case Tag: TRPNTag of
91 rpnBankSymbol: (BankSymbol: Integer); 93 rpnBankSymbol: (BankSymbol: integer);
92 rpnBankSection: (BankSection: Integer); 94 rpnBankSection: (BankSection: integer);
93 rpnInteger: (IntValue: Integer); 95 rpnInteger: (IntValue: integer);
94 rpnSymbol: (SymbolID: Integer); 96 rpnSymbol: (SymbolID: integer);
95 end; 97 end;
96 TRPN = array of TRPNNode; 98 TRPN = array of TRPNNode;
97 99
98 type 100 type
99 TObjFileStream = class(TFileStream) 101 TObjFileStream = class(TFileStream)
100 function ReadNullTerm: string; virtual; 102 function ReadNullTerm: string; virtual;
101 end; 103 end;
102 104
105 EObjectConversionException = class(Exception);
106
107 procedure ConvertRGB2SDAS(Filename: string);
108
109 implementation
110
103 function TObjFileStream.ReadNullTerm: string; 111 function TObjFileStream.ReadNullTerm: string;
104 var B: Byte; 112 var
113 B: byte;
105 begin 114 begin
106 Result := ''; 115 Result := '';
107 while True do begin 116 while True do
117 begin
108 B := ReadByte; 118 B := ReadByte;
109 if B = 0 then Exit; 119 if B = 0 then
120 Exit;
110 Result += Chr(B); 121 Result += Chr(B);
111 end 122 end;
112 end; 123 end;
113 124
114 const 125 const
@@ -121,87 +132,107 @@ const
121 SRAM = 6; 132 SRAM = 6;
122 OAM = 7; 133 OAM = 7;
123 134
124 const 135 const
125 SYM_LOCAL = 0; 136 SYM_LOCAL = 0;
126 SYM_IMPORT = 1; 137 SYM_IMPORT = 1;
127 SYM_EXPORT = 2; 138 SYM_EXPORT = 2;
128 139
129 const 140 const
130 PATCH_BYTE = 0; 141 PATCH_BYTE = 0;
131 PATCH_LE_WORD = 1; 142 PATCH_LE_WORD = 1;
132 PATCH_LE_LONG = 2; 143 PATCH_LE_LONG = 2;
133 PATCH_JR = 3; 144 PATCH_JR = 3;
134 145
135 procedure Die(const S: String); overload; 146 procedure Die(const S: string); overload;
136 begin WriteLn('ERROR:', S); Halt; end; 147 begin
137 procedure Die(const fmt: String; const params: array of const); overload; 148 raise EObjectConversionException.Create(S);
138 begin Die(format(fmt, params)); end; 149 end;
150
151 procedure Die(const fmt: string; const params: array of const); overload;
152 begin
153 Die(format(fmt, params));
154 end;
139 155
140 function ReadObjFile(const afilename: string): TRObj; 156 function ReadObjFile(const afilename: string): TRObj;
141 const Sign : array[0..3] of AnsiChar = 'RGB9'; 157 const
142 var I, J: Integer; 158 Sign: array[0..3] of AnsiChar = 'RGB9';
159 var
160 I, J: integer;
143 begin 161 begin
144 with TObjFileStream.Create(afilename, fmOpenRead) do try 162 with TObjFileStream.Create(afilename, fmOpenRead) do
145 Read(Result, SizeOf(TRObj) - SizeOf(Result.Symbols) - SizeOf(Result.Sections)); 163 try
146 if not (CompareMem(@Result.ID, @Sign, sizeof(Result.ID)) and (Result.RevisionNumber = 5)) then Die('Unsupported object file version!'); 164 Read(Result, SizeOf(TRObj) - SizeOf(Result.Symbols) - SizeOf(Result.Sections));
147 SetLength(Result.Symbols, Result.NumberOfSymbols); 165 if not (CompareMem(@Result.ID, @Sign, sizeof(Result.ID)) and
148 SetLength(Result.Sections, Result.NumberOfSections); 166 (Result.RevisionNumber = 5)) then
149 167 Die('Unsupported object file version!');
150 for I := 0 to Result.NumberOfSymbols-1 do begin 168 SetLength(Result.Symbols, Result.NumberOfSymbols);
151 Result.Symbols[I] := Default(TRSymbol); 169 SetLength(Result.Sections, Result.NumberOfSections);
152 with Result.Symbols[I] do begin 170
153 ID := I; 171 for I := 0 to Result.NumberOfSymbols - 1 do
154 Name := ReadNullTerm; 172 begin
155 Read(SymType, 1); 173 Result.Symbols[I] := Default(TRSymbol);
156 if ((SymType and $7F) <> SYM_IMPORT) then begin 174 with Result.Symbols[I] do
157 FileName := ReadNullTerm; 175 begin
158 Read(LineNum, SizeOf(LineNum)); 176 ID := I;
159 Read(SectionID, SizeOf(SectionID)); 177 Name := ReadNullTerm;
160 Read(Value, SizeOf(Value)); 178 Read(SymType, 1);
179 if ((SymType and $7F) <> SYM_IMPORT) then
180 begin
181 FileName := ReadNullTerm;
182 Read(LineNum, SizeOf(LineNum));
183 Read(SectionID, SizeOf(SectionID));
184 Read(Value, SizeOf(Value));
185 end;
161 end; 186 end;
162 end; 187 end;
163 end;
164 188
165 for I := 0 to Result.NumberOfSections-1 do begin 189 for I := 0 to Result.NumberOfSections - 1 do
166 Result.Sections[I] := Default(TRSection); 190 begin
167 with Result.Sections[I] do begin 191 Result.Sections[I] := Default(TRSection);
168 ID := I; 192 with Result.Sections[I] do
169 Name := ReadNullTerm; 193 begin
170 Read(Size, SizeOf(Size)); 194 ID := I;
171 Read(SectType, SizeOf(SectType)); 195 Name := ReadNullTerm;
172 Read(Org, SizeOf(Org)); 196 Read(Size, SizeOf(Size));
173 Read(Bank, SizeOf(Bank)); 197 Read(SectType, SizeOf(SectType));
174 Read(Align, SizeOf(Align)); 198 Read(Org, SizeOf(Org));
175 Read(Ofs, SizeOf(Ofs)); 199 Read(Bank, SizeOf(Bank));
176 if ((SectType = ROMX) or (SectType = ROM0)) then begin 200 Read(Align, SizeOf(Align));
177 SetLength(Data, Size); 201 Read(Ofs, SizeOf(Ofs));
178 Read(Data[0], Size); 202 if ((SectType = ROMX) or (SectType = ROM0)) then
179 Read(NumberOfPatches, SizeOf(NumberOfPatches)); 203 begin
180 SetLength(Patches, NumberOfPatches); 204 SetLength(Data, Size);
205 Read(Data[0], Size);
206 Read(NumberOfPatches, SizeOf(NumberOfPatches));
207 SetLength(Patches, NumberOfPatches);
208 end;
181 end; 209 end;
182 end;
183 210
184 for J := 0 to Result.Sections[I].NumberOfPatches-1 do begin 211 for J := 0 to Result.Sections[I].NumberOfPatches - 1 do
185 with Result.Sections[I].Patches[J] do begin 212 begin
186 SourceFile := ReadNullTerm; 213 with Result.Sections[I].Patches[J] do
187 Read(Offset, SizeOf(Offset)); 214 begin
188 Read(PCSectionID, SizeOf(PCSectionID)); 215 SourceFile := ReadNullTerm;
189 Read(PCOffset, SizeOf(PCOffset)); 216 Read(Offset, SizeOf(Offset));
190 Read(PatchType, SizeOf(PatchType)); 217 Read(PCSectionID, SizeOf(PCSectionID));
191 Read(RPNSize, SizeOf(RPNSize)); 218 Read(PCOffset, SizeOf(PCOffset));
192 SetLength(RPN, RPNSize); 219 Read(PatchType, SizeOf(PatchType));
193 Read(RPN[0], RPNSize); 220 Read(RPNSize, SizeOf(RPNSize));
221 SetLength(RPN, RPNSize);
222 Read(RPN[0], RPNSize);
223 end;
194 end; 224 end;
195 end; 225 end;
226 finally
227 Free;
196 end; 228 end;
197 finally free; end;
198 end; 229 end;
199 230
200 function RPNToString(const RPN: array of Byte; const Syms: array of TRSymbol): String; 231 function RPNToString(const RPN: array of byte; const Syms: array of TRSymbol): string;
201 var 232 var
202 I: Integer; 233 I: integer;
203 234
204 function ReadLong: LongWord; 235 function ReadLong: longword;
205 begin 236 begin
206 Inc(I); 237 Inc(I);
207 Result := RPN[I]; 238 Result := RPN[I];
@@ -219,47 +250,157 @@ begin
219 Result := ''; 250 Result := '';
220 251
221 I := Low(RPN); 252 I := Low(RPN);
222 while I <= High(RPN) do begin 253 while I <= High(RPN) do
254 begin
223 case RPN[I] of 255 case RPN[I] of
224 $00: begin Result += '+ '; Inc(I); end; 256 $00:
225 $01: begin Result += '- '; Inc(I); end; 257 begin
226 $02: begin Result += '* '; Inc(I); end; 258 Result += '+ ';
227 $03: begin Result += '/ '; Inc(I); end; 259 Inc(I);
228 $04: begin Result += '% '; Inc(I); end; 260 end;
229 $05: begin Result += 'neg '; Inc(I); end; 261 $01:
230 $10: begin Result += '| '; Inc(I); end; 262 begin
231 $11: begin Result += '& '; Inc(I); end; 263 Result += '- ';
232 $12: begin Result += '^ '; Inc(I); end; 264 Inc(I);
233 $13: begin Result += '~ '; Inc(I); end; 265 end;
234 $21: begin Result += '&& '; Inc(I); end; 266 $02:
235 $22: begin Result += '|| '; Inc(I); end; 267 begin
236 $23: begin Result += '! '; Inc(I); end; 268 Result += '* ';
237 $30: begin Result += '== '; Inc(I); end; 269 Inc(I);
238 $31: begin Result += '!= '; Inc(I); end; 270 end;
239 $32: begin Result += '> '; Inc(I); end; 271 $03:
240 $33: begin Result += '< '; Inc(I); end; 272 begin
241 $34: begin Result += '>= '; Inc(I); end; 273 Result += '/ ';
242 $35: begin Result += '<= '; Inc(I); end; 274 Inc(I);
243 $40: begin Result += '<< '; Inc(I); end; 275 end;
244 $41: begin Result += '>> '; Inc(I); end; 276 $04:
245 $50: begin Result += '(bank-sym ' + IntToStr(ReadLong)+') '; end; 277 begin
246 $51: begin Result += '(bank-section ' + IntToStr(ReadLong)+') '; end; 278 Result += '% ';
247 $52: begin Result += 'current-bank'; Inc(I); end; 279 Inc(I);
248 $60: begin Result += 'hram-check'; Inc(I); end; 280 end;
249 $61: begin Result += 'rst-check'; Inc(I); end; 281 $05:
250 $80: begin Result += '(int ' + IntToStr(ReadLong)+') '; end; 282 begin
251 $81: begin Result += '(sym ' + Syms[ReadLong].Name+') '; end; 283 Result += 'neg ';
252 else Exit('INVALID!'); 284 Inc(I);
285 end;
286 $10:
287 begin
288 Result += '| ';
289 Inc(I);
290 end;
291 $11:
292 begin
293 Result += '& ';
294 Inc(I);
295 end;
296 $12:
297 begin
298 Result += '^ ';
299 Inc(I);
300 end;
301 $13:
302 begin
303 Result += '~ ';
304 Inc(I);
305 end;
306 $21:
307 begin
308 Result += '&& ';
309 Inc(I);
310 end;
311 $22:
312 begin
313 Result += '|| ';
314 Inc(I);
315 end;
316 $23:
317 begin
318 Result += '! ';
319 Inc(I);
320 end;
321 $30:
322 begin
323 Result += '== ';
324 Inc(I);
325 end;
326 $31:
327 begin
328 Result += '!= ';
329 Inc(I);
330 end;
331 $32:
332 begin
333 Result += '> ';
334 Inc(I);
335 end;
336 $33:
337 begin
338 Result += '< ';
339 Inc(I);
340 end;
341 $34:
342 begin
343 Result += '>= ';
344 Inc(I);
345 end;
346 $35:
347 begin
348 Result += '<= ';
349 Inc(I);
350 end;
351 $40:
352 begin
353 Result += '<< ';
354 Inc(I);
355 end;
356 $41:
357 begin
358 Result += '>> ';
359 Inc(I);
360 end;
361 $50:
362 begin
363 Result += '(bank-sym ' + IntToStr(ReadLong) + ') ';
364 end;
365 $51:
366 begin
367 Result += '(bank-section ' + IntToStr(ReadLong) + ') ';
368 end;
369 $52:
370 begin
371 Result += 'current-bank';
372 Inc(I);
373 end;
374 $60:
375 begin
376 Result += 'hram-check';
377 Inc(I);
378 end;
379 $61:
380 begin
381 Result += 'rst-check';
382 Inc(I);
383 end;
384 $80:
385 begin
386 Result += '(int ' + IntToStr(ReadLong) + ') ';
387 end;
388 $81:
389 begin
390 Result += '(sym ' + Syms[ReadLong].Name + ') ';
391 end;
392 else
393 Exit('INVALID!');
253 end; 394 end;
254 end; 395 end;
255 end; 396 end;
256 397
257 function ParseRPN(const RPN: array of Byte): TRPN; 398 function ParseRPN(const RPN: array of byte): TRPN;
258 var 399 var
259 I: Integer; 400 I: integer;
260 Node: TRPNNode; 401 Node: TRPNNode;
261 402
262 function ReadLong: LongWord; 403 function ReadLong: longword;
263 begin 404 begin
264 Inc(I); 405 Inc(I);
265 Result := RPN[I]; 406 Result := RPN[I];
@@ -274,65 +415,169 @@ var
274 end; 415 end;
275 416
276 function nd(Tag: TRPNTag): TRPNNode; 417 function nd(Tag: TRPNTag): TRPNNode;
277 begin Result.Tag := Tag; end; 418 begin
419 Result.Tag := Tag;
420 end;
278 421
279 procedure PushRPN(Node: TRPNNode); 422 procedure PushRPN(Node: TRPNNode);
280 begin 423 begin
281 SetLength(Result, Length(Result)+1); 424 SetLength(Result, Length(Result) + 1);
282 Result[High(Result)] := Node; 425 Result[High(Result)] := Node;
283 end; 426 end;
284 427
285 begin 428 begin
286 SetLength(Result, 0); 429 SetLength(Result, 0);
287 I := Low(RPN); 430 I := Low(RPN);
288 while I <= High(RPN) do begin 431 while I <= High(RPN) do
432 begin
289 //Writeln(Format('Parsing %x, len=%d', [RPN[I], Length(Result)])); 433 //Writeln(Format('Parsing %x, len=%d', [RPN[I], Length(Result)]));
290 case RPN[I] of 434 case RPN[I] of
291 $00: begin PushRPN(Nd(rpnPlus)); Inc(I); end; 435 $00:
292 $01: begin PushRPN(Nd(rpnMinus)); Inc(I); end; 436 begin
293 $02: begin PushRPN(Nd(rpnTimes)); Inc(I); end; 437 PushRPN(Nd(rpnPlus));
294 $03: begin PushRPN(Nd(rpnDiv)); Inc(I); end; 438 Inc(I);
295 $04: begin PushRPN(Nd(rpnMod)); Inc(I); end; 439 end;
296 $05: begin PushRPN(Nd(rpnNegate)); Inc(I); end; 440 $01:
297 $10: begin PushRPN(Nd(rpnOr)); Inc(I); end; 441 begin
298 $11: begin PushRPN(Nd(rpnAnd)); Inc(I); end; 442 PushRPN(Nd(rpnMinus));
299 $12: begin PushRPN(Nd(rpnXor)); Inc(I); end; 443 Inc(I);
300 $13: begin PushRPN(Nd(rpnComplement)); Inc(I); end; 444 end;
301 $21: begin PushRPN(Nd(rpnBoolAnd)); Inc(I); end; 445 $02:
302 $22: begin PushRPN(Nd(rpnBoolOr)); Inc(I); end; 446 begin
303 $23: begin PushRPN(Nd(rpnBoolNeg)); Inc(I); end; 447 PushRPN(Nd(rpnTimes));
304 $30: begin PushRPN(Nd(rpnEqual)); Inc(I); end; 448 Inc(I);
305 $31: begin PushRPN(Nd(rpnNotEqual)); Inc(I); end; 449 end;
306 $32: begin PushRPN(Nd(rpnGreater)); Inc(I); end; 450 $03:
307 $33: begin PushRPN(Nd(rpnLess)); Inc(I); end; 451 begin
308 $34: begin PushRPN(Nd(rpnGreaterEqual)); Inc(I); end; 452 PushRPN(Nd(rpnDiv));
309 $35: begin PushRPN(Nd(rpnLessEqual)); Inc(I); end; 453 Inc(I);
310 $40: begin PushRPN(Nd(rpnShl)); Inc(I); end; 454 end;
311 $41: begin PushRPN(Nd(rpnShr)); Inc(I); end; 455 $04:
312 $50: begin 456 begin
313 Node.Tag := rpnBankSymbol; 457 PushRPN(Nd(rpnMod));
314 Node.BankSymbol := ReadLong; 458 Inc(I);
315 PushRPN(Node); 459 end;
316 end; 460 $05:
317 $51: begin 461 begin
318 Node.Tag := rpnBankSection; 462 PushRPN(Nd(rpnNegate));
319 Node.BankSection := ReadLong; 463 Inc(I);
320 PushRPN(Node); 464 end;
321 end; 465 $10:
322 $52: begin PushRPN(Nd(rpnCurrentBank)); Inc(I); end; 466 begin
323 $60: begin PushRPN(Nd(rpnHramCheck)); Inc(I); end; 467 PushRPN(Nd(rpnOr));
324 $61: begin PushRPN(Nd(rpnRstCheck)); Inc(I); end; 468 Inc(I);
325 $80: begin 469 end;
326 Node.Tag := rpnInteger; 470 $11:
327 Node.IntValue := ReadLong; 471 begin
328 PushRPN(Node); 472 PushRPN(Nd(rpnAnd));
329 end; 473 Inc(I);
330 $81: begin 474 end;
331 Node.Tag := rpnSymbol; 475 $12:
332 Node.SymbolID := ReadLong; 476 begin
333 PushRPN(Node); 477 PushRPN(Nd(rpnXor));
334 end; 478 Inc(I);
335 else Die('Got malformed RPN!'); 479 end;
480 $13:
481 begin
482 PushRPN(Nd(rpnComplement));
483 Inc(I);
484 end;
485 $21:
486 begin
487 PushRPN(Nd(rpnBoolAnd));
488 Inc(I);
489 end;
490 $22:
491 begin
492 PushRPN(Nd(rpnBoolOr));
493 Inc(I);
494 end;
495 $23:
496 begin
497 PushRPN(Nd(rpnBoolNeg));
498 Inc(I);
499 end;
500 $30:
501 begin
502 PushRPN(Nd(rpnEqual));
503 Inc(I);
504 end;
505 $31:
506 begin
507 PushRPN(Nd(rpnNotEqual));
508 Inc(I);
509 end;
510 $32:
511 begin
512 PushRPN(Nd(rpnGreater));
513 Inc(I);
514 end;
515 $33:
516 begin
517 PushRPN(Nd(rpnLess));
518 Inc(I);
519 end;
520 $34:
521 begin
522 PushRPN(Nd(rpnGreaterEqual));
523 Inc(I);
524 end;
525 $35:
526 begin
527 PushRPN(Nd(rpnLessEqual));
528 Inc(I);
529 end;
530 $40:
531 begin
532 PushRPN(Nd(rpnShl));
533 Inc(I);
534 end;
535 $41:
536 begin
537 PushRPN(Nd(rpnShr));
538 Inc(I);
539 end;
540 $50:
541 begin
542 Node.Tag := rpnBankSymbol;
543 Node.BankSymbol := ReadLong;
544 PushRPN(Node);
545 end;
546 $51:
547 begin
548 Node.Tag := rpnBankSection;
549 Node.BankSection := ReadLong;
550 PushRPN(Node);
551 end;
552 $52:
553 begin
554 PushRPN(Nd(rpnCurrentBank));
555 Inc(I);
556 end;
557 $60:
558 begin
559 PushRPN(Nd(rpnHramCheck));
560 Inc(I);
561 end;
562 $61:
563 begin
564 PushRPN(Nd(rpnRstCheck));
565 Inc(I);
566 end;
567 $80:
568 begin
569 Node.Tag := rpnInteger;
570 Node.IntValue := ReadLong;
571 PushRPN(Node);
572 end;
573 $81:
574 begin
575 Node.Tag := rpnSymbol;
576 Node.SymbolID := ReadLong;
577 PushRPN(Node);
578 end;
579 else
580 Die('Got malformed RPN!');
336 end; 581 end;
337 end; 582 end;
338 end; 583 end;
@@ -343,39 +588,45 @@ var
343 Sym: TRSymbol; 588 Sym: TRSymbol;
344 Sect: TRSection; 589 Sect: TRSection;
345 Patch: TRPatch; 590 Patch: TRPatch;
346 SectSize: Integer; 591 SectSize: integer;
347 begin 592 begin
348 WriteLn('Symbols:'); 593 WriteLn('Symbols:');
349 for Sym in O.Symbols do 594 for Sym in O.Symbols do
350 Writeln(Format(' %s on %d: type=%d, section=%d, value=%d', 595 Writeln(Format(' %s on %d: type=%d, section=%d, value=%d',
351 [Sym.Name, Sym.LineNum, Sym.SymType, Sym.SectionID, Sym.Value])); 596 [Sym.Name, Sym.LineNum, Sym.SymType, Sym.SectionID, Sym.Value]));
352 597
353 SectSize := 0; 598 SectSize := 0;
354 for Sect in O.Sections do 599 for Sect in O.Sections do
355 if (Sect.Org <> -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then Inc(SectSize, Sect.Size); 600 if (Sect.Org <> -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then
601 Inc(SectSize, Sect.Size);
356 Writeln('Absolute sections: ', SectSize, ' bytes'); 602 Writeln('Absolute sections: ', SectSize, ' bytes');
357 603
358 SectSize := 0; 604 SectSize := 0;
359 for Sect in O.Sections do 605 for Sect in O.Sections do
360 if (Sect.Org = -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then Inc(SectSize, Sect.Size); 606 if (Sect.Org = -1) and ((Sect.SectType = ROM0) or (Sect.SectType = ROMX)) then
607 Inc(SectSize, Sect.Size);
361 Writeln('Relative sections: ', SectSize, ' bytes'); 608 Writeln('Relative sections: ', SectSize, ' bytes');
362 609
363 WriteLn('Sections:'); 610 WriteLn('Sections:');
364 for Sect in O.Sections do begin 611 for Sect in O.Sections do
612 begin
365 Writeln(Format(' %s with size %d: offset=%d, patches=%d, bank=%d', 613 Writeln(Format(' %s with size %d: offset=%d, patches=%d, bank=%d',
366 [Sect.Name, Sect.Size, Sect.Org, Sect.NumberOfPatches, Sect.Bank])); 614 [Sect.Name, Sect.Size, Sect.Org, Sect.NumberOfPatches, Sect.Bank]));
367 615
368 for Patch in Sect.Patches do 616 for Patch in Sect.Patches do
369 Writeln(Format(' %s: %d ; %s', [Patch.SourceFile, Patch.PatchType, RPNToString(Patch.RPN, O.Symbols)])); 617 Writeln(Format(' %s: %d ; %s', [Patch.SourceFile, Patch.PatchType,
618 RPNToString(Patch.RPN, O.Symbols)]));
370 end; 619 end;
371 end; 620 end;
372 621
373 function FindPatch(const Section: TRSection; Index: Integer; out Patch: TRPatch): Boolean; 622 function FindPatch(const Section: TRSection; Index: integer;
623 out Patch: TRPatch): boolean;
374 var 624 var
375 I: Integer; 625 I: integer;
376 begin 626 begin
377 for I := Low(Section.Patches) to High(Section.Patches) do 627 for I := Low(Section.Patches) to High(Section.Patches) do
378 if Section.Patches[I].Offset = Index then begin 628 if Section.Patches[I].Offset = Index then
629 begin
379 Patch := Section.Patches[I]; 630 Patch := Section.Patches[I];
380 Exit(True); 631 Exit(True);
381 end; 632 end;
@@ -383,6 +634,7 @@ begin
383 Result := False; 634 Result := False;
384 end; 635 end;
385 636
637 procedure ConvertRGB2SDAS(Filename: string);
386 var 638 var
387 RObj: TRObj; 639 RObj: TRObj;
388 640
@@ -392,38 +644,34 @@ var
392 644
393 F: Text; 645 F: Text;
394 646
395 ValueToWrite: Word; 647 ValueToWrite: word;
396 RPN: TRPN; 648 RPN: TRPN;
397 I: Word; 649 I: word;
398 Sct: Word; 650 Sct: word;
399 WritePos: Word; 651 WritePos: word;
400 Idx: Integer; 652 Idx: integer;
401 CODESEG: string; 653 CODESEG: string;
402 DefaultBank: Integer = 1; 654 DefaultBank: integer = 1;
403 sourcename, tmp: string; 655 sourcename, tmp: string;
404 656
405 old_sym, new_sym: string; 657 old_sym, new_sym: string;
406
407 verbose: boolean = false;
408
409 export_all: boolean = false;
410 658
659 verbose: boolean = False;
660
661 export_all: boolean = False;
411 begin 662 begin
412 if (ParamCount() < 1) then begin 663 sourcename := Filename;
413 Writeln('Usage: rgb2sdas [-c<code_section>] [-v] [-e] [-r<symbol1>=<symbol2>] [-b<default_bank>] <object_name>'); 664 if not FileExists(sourcename) then
414 Halt; 665 Die('File not found: %s', [sourcename]);
415 end; 666
416 667 old_sym := '';
417 sourcename:= ParamStr(ParamCount()); 668 new_sym := '';
418 if not FileExists(sourcename) then Die('File not found: %s', [sourcename]); 669
419 670 CODESEG := '_CODE';
420 old_sym:= ''; new_sym:= ''; 671 {for I:= 1 to ParamCount() - 1 do begin
421
422 CODESEG:= '_CODE';
423 for I:= 1 to ParamCount() - 1 do begin
424 tmp:= ParamStr(i); 672 tmp:= ParamStr(i);
425 if (CompareText(tmp, '-v') = 0) then 673 if (CompareText(tmp, '-v') = 0) then
426 verbose:= true 674 verbose:= true
427 else if (CompareText(copy(tmp, 1, 2), '-e') = 0) then 675 else if (CompareText(copy(tmp, 1, 2), '-e') = 0) then
428 export_all:= true 676 export_all:= true
429 else if (CompareText(copy(tmp, 1, 2), '-c') = 0) then begin 677 else if (CompareText(copy(tmp, 1, 2), '-c') = 0) then begin
@@ -440,121 +688,173 @@ begin
440 old_sym:= copy(tmp, 1, idx - 1); 688 old_sym:= copy(tmp, 1, idx - 1);
441 new_sym:= copy(tmp, idx + 1, length(tmp)); 689 new_sym:= copy(tmp, idx + 1, length(tmp));
442 end; 690 end;
443 end; 691 end;
444 end; 692 end;}
445 693
446 RObj := ReadObjFile(sourcename); 694 RObj := ReadObjFile(sourcename);
447 if verbose then PrintObjFile(RObj); 695 if verbose then
696 PrintObjFile(RObj);
448 697
449 Assign(F, sourcename + '.o'); 698 Assign(F, sourcename + '.o');
450 Rewrite(F); 699 Rewrite(F);
451 try 700 try
452 Idx:= 0; 701 Idx := 0;
453 // pass 1: all imports first 702 // pass 1: all imports first
454 for I:= Low(RObj.Symbols) to High(RObj.Symbols) do with RObj.Symbols[I] do begin 703 for I := Low(RObj.Symbols) to High(RObj.Symbols) do
455 if ((SymType and $7f) = SYM_IMPORT) then begin 704 with RObj.Symbols[I] do
456 No:= Idx; 705 begin
457 Inc(Idx); 706 if ((SymType and $7f) = SYM_IMPORT) then
458 end else No:= -1; 707 begin
459 end; 708 No := Idx;
709 Inc(Idx);
710 end
711 else
712 No := -1;
713 end;
460 // pass 2: all other (export local only when forced) 714 // 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 715 for I := Low(RObj.Symbols) to High(RObj.Symbols) do
462 case (SymType and $7f) of 716 with RObj.Symbols[I] do
463 SYM_LOCAL : if export_all then begin 717 begin
464 No:= Idx; 718 case (SymType and $7f) of
465 Inc(Idx); 719 SYM_LOCAL: if export_all then
466 end; 720 begin
467 SYM_IMPORT : ; 721 No := Idx;
468 SYM_EXPORT : begin 722 Inc(Idx);
469 // rename exported symbol if requested 723 end;
470 if (length(old_sym) > 0) and (Name = old_sym) then Name:= new_sym; 724 SYM_IMPORT: ;
471 No:= Idx; 725 SYM_EXPORT:
472 Inc(Idx); 726 begin
473 end; 727 // rename exported symbol if requested
474 else Die('Unsupported symbol type: %d', [SymType and $7f]); 728 if (length(old_sym) > 0) and (Name = old_sym) then
475 end; 729 Name := new_sym;
476 end; 730 No := Idx;
731 Inc(Idx);
732 end;
733 else
734 Die('Unsupported symbol type: %d', [SymType and $7f]);
735 end;
736 end;
477 737
478 // output object header 738 // output object header
479 Writeln(F, 'XL2'); 739 Writeln(F, 'XL2');
480 Writeln(F, Format('H %x areas %x global symbols', [RObj.NumberOfSections, idx])); 740 Writeln(F, Format('H %x areas %x global symbols', [RObj.NumberOfSections, idx]));
481 Writeln(F, Format('M %s', [StringReplace(ExtractFileName(sourcename), '.', '_', [rfReplaceAll])])); 741 Writeln(F, Format('M %s', [StringReplace(ExtractFileName(sourcename),
742 '.', '_', [rfReplaceAll])]));
482 Writeln(F, 'O -mgbz80'); 743 Writeln(F, 'O -mgbz80');
483 744
484 // output all imported symbols 745 // output all imported symbols
485 for I:= Low(RObj.Symbols) to High(RObj.Symbols) do 746 for I := Low(RObj.Symbols) to High(RObj.Symbols) do
486 with RObj.Symbols[I] do 747 with RObj.Symbols[I] do
487 if (SymType = SYM_IMPORT) then 748 if (SymType = SYM_IMPORT) then
488 Writeln(F, Format('S %s Ref%.4x', [StringReplace(Name, '.', '____', [rfReplaceAll]), 0])); 749 Writeln(F, Format('S %s Ref%.4x',
489 750 [StringReplace(Name, '.', '____', [rfReplaceAll]), 0]));
751
490 // output all sections and other symbols 752 // output all sections and other symbols
491 for Section in RObj.Sections do begin 753 for Section in RObj.Sections do
754 begin
492 if Section.Org = -1 then 755 if Section.Org = -1 then
493 case Section.SectType of 756 case Section.SectType of
494 ROM0: Writeln(F, Format('A %s size %x flags 0 addr 0', [CODESEG, Section.Size])); 757 ROM0: Writeln(F, Format('A %s size %x flags 0 addr 0',
495 ROMX: if (DefaultBank = 0) then Writeln(F, Format('A %s size %x flags 0 addr 0', [CODESEG, Section.Size])) 758 [CODESEG, Section.Size]));
496 else Writeln(F, Format('A _CODE_%d size %x flags 0 addr 0', [max(DefaultBank, Section.Bank), Section.Size])); 759 ROMX: if (DefaultBank = 0) then
497 else Writeln(F, Format('A _DATA size %x flags 0 addr 0', [Section.Size])); 760 Writeln(F, Format('A %s size %x flags 0 addr 0', [CODESEG, Section.Size]))
498 end 761 else
499 else Die('absolute sections currently unsupported: %s', [Section.Name]); 762 Writeln(F, Format('A _CODE_%d size %x flags 0 addr 0',
763 [max(DefaultBank, Section.Bank), Section.Size]));
764 else
765 Writeln(F, Format('A _DATA size %x flags 0 addr 0', [Section.Size]));
766 end
767 else
768 Die('absolute sections currently unsupported: %s', [Section.Name]);
500 769
501 for Symbol in RObj.Symbols do 770 for Symbol in RObj.Symbols do
502 if Symbol.SectionID = Section.ID then begin 771 if Symbol.SectionID = Section.ID then
503 if (Symbol.SymType <> SYM_IMPORT) and (Symbol.No >= 0) then 772 begin
504 Writeln(F, Format('S %s Def%.4x', [StringReplace(Symbol.Name, '.', '____', [rfReplaceAll]), Symbol.Value])); 773 if (Symbol.SymType <> SYM_IMPORT) and (Symbol.No >= 0) then
774 Writeln(F, Format('S %s Def%.4x',
775 [StringReplace(Symbol.Name, '.', '____', [rfReplaceAll]), Symbol.Value]));
505 end; 776 end;
506 end; 777 end;
507 778
508 // convert object itself 779 // convert object itself
509 for Sct := Low(RObj.Sections) to High(RObj.Sections) do begin 780 for Sct := Low(RObj.Sections) to High(RObj.Sections) do
781 begin
510 Section := RObj.Sections[Sct]; 782 Section := RObj.Sections[Sct];
511 783
512 if (Section.SectType <> ROMX) and (Section.SectType <> ROM0) then Continue; 784 if (Section.SectType <> ROMX) and (Section.SectType <> ROM0) then
513 if Length(Section.Data) <= 0 then Continue; 785 Continue;
786 if Length(Section.Data) <= 0 then
787 Continue;
514 788
515 I := Low(Section.Data); 789 I := Low(Section.Data);
516 while I <= High(Section.Data) do begin 790 while I <= High(Section.Data) do
791 begin
517 WritePos := I; 792 WritePos := I;
518 if (Section.Org <> -1) then Inc(WritePos, Section.Org); 793 if (Section.Org <> -1) then
794 Inc(WritePos, Section.Org);
519 795
520 if FindPatch(Section, I, Patch) then begin 796 if FindPatch(Section, I, Patch) then
797 begin
521 case Patch.PatchType of 798 case Patch.PatchType of
522 PATCH_LE_WORD : begin 799 PATCH_LE_WORD:
523 RPN := ParseRPN(Patch.RPN); 800 begin
524 Symbol := RObj.Symbols[RPN[0].SymbolID]; 801 RPN := ParseRPN(Patch.RPN);
525 ValueToWrite := Symbol.Value; 802 Symbol := RObj.Symbols[RPN[0].SymbolID];
526 if RPN[High(RPN)].Tag = rpnPlus then 803 ValueToWrite := Symbol.Value;
527 Inc(ValueToWrite, RPN[1].IntValue); 804 if RPN[High(RPN)].Tag = rpnPlus then
528 805 Inc(ValueToWrite, RPN[1].IntValue);
529 if (Symbol.SymType = SYM_IMPORT) then begin 806
530 if (Symbol.No < 0) then Die('Trying to reference eliminated symbol'); 807 if (Symbol.SymType = SYM_IMPORT) then
531 Writeln(F, Format('T %.2x %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)])); 808 begin
532 Writeln(F, Format('R 00 00 %.2x %.2x 02 02 %.2x %.2x', [lo(Sct), hi(Sct), lo(Symbol.No), hi(Symbol.No)])); 809 if (Symbol.No < 0) then
533 end else begin 810 Die('Trying to reference eliminated symbol');
534 Writeln(F, Format('T %.2x %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)])); 811 Writeln(F, Format('T %.2x %.2x %.2x %.2x',
535 Writeln(F, Format('R 00 00 %.2x %.2x 00 02 %.2x %.2x', [lo(Sct), hi(Sct), lo(Symbol.SectionID), hi(Symbol.SectionID)])); 812 [lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)]));
536 end; 813 Writeln(F,
537 Inc(I, 2); 814 Format('R 00 00 %.2x %.2x 02 02 %.2x %.2x', [lo(Sct), hi(Sct),
538 end; 815 lo(Symbol.No), hi(Symbol.No)]));
539 PATCH_JR : begin 816 end
540 RPN := ParseRPN(Patch.RPN); 817 else
541 if Length(RPN) > 1 then Die('Not handling bigger RPN on JR'); 818 begin
542 Symbol := RObj.Symbols[RPN[0].SymbolID]; 819 Writeln(F, Format('T %.2x %.2x %.2x %.2x',
543 Writeln(F, Format('T %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), Byte(Symbol.Value - I - 1)])); 820 [lo(WritePos), hi(WritePos), lo(ValueToWrite), hi(ValueToWrite)]));
544 Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct), hi(Sct)])); 821 Writeln(F,
545 Inc(I); 822 Format('R 00 00 %.2x %.2x 00 02 %.2x %.2x', [lo(Sct), hi(Sct),
546 end 823 lo(Symbol.SectionID), hi(Symbol.SectionID)]));
547 else Die('Unsupported patch type: %d', [Patch.PatchType]); 824 end;
825 Inc(I, 2);
826 end;
827 PATCH_JR:
828 begin
829 RPN := ParseRPN(Patch.RPN);
830 if Length(RPN) > 1 then
831 Die('Not handling bigger RPN on JR');
832 Symbol := RObj.Symbols[RPN[0].SymbolID];
833 Writeln(F, Format('T %.2x %.2x %.2x',
834 [lo(WritePos), hi(WritePos), byte(Symbol.Value - I - 1)]));
835 Writeln(F, Format('R 00 00 %.2x %.2x',
836 [lo(Sct), hi(Sct)]));
837 Inc(I);
838 end
839 else
840 Die('Unsupported patch type: %d', [Patch.PatchType]);
548 end; 841 end;
549 end else begin 842 end
550 Writeln(F, Format('T %.2x %.2x %.2x', [lo(WritePos), hi(WritePos), Section.Data[I]])); 843 else
844 begin
845 Writeln(F, Format('T %.2x %.2x %.2x',
846 [lo(WritePos), hi(WritePos), Section.Data[I]]));
551 Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct), hi(Sct)])); 847 Writeln(F, Format('R 00 00 %.2x %.2x', [lo(Sct), hi(Sct)]));
552 Inc(I); 848 Inc(I);
553 end; 849 end;
554 end; 850 end;
555 end; 851 end;
556 852
557 Writeln('rgb2sdas converting ',sourcename,' --> ',sourcename,'.o result: success!'); 853 //Writeln('rgb2sdas converting ',sourcename,' --> ',sourcename,'.o result: success!');
558 finally Close(F); end; 854 finally
559 end. 855 Close(F);
856 end;
857 end;
560 858
859 begin
860 end.
Modifiedtracker.lfm +30−20
@@ -211,11 +211,12 @@ object frmTracker: TfrmTracker
211 Height = 614 211 Height = 614
212 Top = 31 212 Top = 31
213 Width = 838 213 Width = 838
214 HorzScrollBar.Increment = 5 214 HorzScrollBar.Increment = 3
215 HorzScrollBar.Page = 56 215 HorzScrollBar.Page = 32
216 HorzScrollBar.Smooth = True 216 HorzScrollBar.Smooth = True
217 HorzScrollBar.Tracking = True 217 HorzScrollBar.Tracking = True
218 VertScrollBar.Page = 88 218 VertScrollBar.Increment = 5
219 VertScrollBar.Page = 50
219 VertScrollBar.Smooth = True 220 VertScrollBar.Smooth = True
220 VertScrollBar.Tracking = True 221 VertScrollBar.Tracking = True
221 Align = alClient 222 Align = alClient
@@ -1723,7 +1724,7 @@ object frmTracker: TfrmTracker
1723 ParentShowHint = False 1724 ParentShowHint = False
1724 end 1725 end
1725 object PanicToolButton: TToolButton 1726 object PanicToolButton: TToolButton
1726 Left = 551 1727 Left = 557
1727 Hint = 'Stops all sound output' 1728 Hint = 'Stops all sound output'
1728 Top = 0 1729 Top = 0
1729 AutoSize = True 1730 AutoSize = True
@@ -1734,17 +1735,17 @@ object frmTracker: TfrmTracker
1734 ShowHint = True 1735 ShowHint = True
1735 end 1736 end
1736 object ToolButton2: TToolButton 1737 object ToolButton2: TToolButton
1737 Left = 145 1738 Left = 147
1738 Top = 0 1739 Top = 0
1739 Action = PlayCursorAction 1740 Action = PlayCursorAction
1740 end 1741 end
1741 object ToolButton4: TToolButton 1742 object ToolButton4: TToolButton
1742 Left = 219 1743 Left = 221
1743 Top = 0 1744 Top = 0
1744 Action = StopAction 1745 Action = StopAction
1745 end 1746 end
1746 object ExportGBButton: TToolButton 1747 object ExportGBButton: TToolButton
1747 Left = 287 1748 Left = 291
1748 Hint = 'Export the song as a standalone ROM' 1749 Hint = 'Export the song as a standalone ROM'
1749 Top = 0 1750 Top = 0
1750 AutoSize = True 1751 AutoSize = True
@@ -1760,21 +1761,21 @@ object frmTracker: TfrmTracker
1760 Style = tbsDivider 1761 Style = tbsDivider
1761 end 1762 end
1762 object ToolButton6: TToolButton 1763 object ToolButton6: TToolButton
1763 Left = 284 1764 Left = 286
1764 Height = 22 1765 Height = 22
1765 Top = 0 1766 Top = 0
1766 Caption = 'ToolButton6' 1767 Caption = 'ToolButton6'
1767 Style = tbsDivider 1768 Style = tbsDivider
1768 end 1769 end
1769 object ToolButton7: TToolButton 1770 object ToolButton7: TToolButton
1770 Left = 1088 1771 Left = 1097
1771 Height = 22 1772 Height = 22
1772 Top = 0 1773 Top = 0
1773 Caption = 'ToolButton7' 1774 Caption = 'ToolButton7'
1774 Style = tbsSeparator 1775 Style = tbsSeparator
1775 end 1776 end
1776 object OctaveSpinEdit: TSpinEdit 1777 object OctaveSpinEdit: TSpinEdit
1777 Left = 654 1778 Left = 663
1778 Height = 23 1779 Height = 23
1779 Hint = 'The octave offset for entering new notes' 1780 Hint = 'The octave offset for entering new notes'
1780 Top = 0 1781 Top = 0
@@ -1785,14 +1786,14 @@ object frmTracker: TfrmTracker
1785 TabOrder = 0 1786 TabOrder = 0
1786 end 1787 end
1787 object ToolButton9: TToolButton 1788 object ToolButton9: TToolButton
1788 Left = 606 1789 Left = 612
1789 Height = 22 1790 Height = 22
1790 Top = 0 1791 Top = 0
1791 Caption = 'ToolButton9' 1792 Caption = 'ToolButton9'
1792 Style = tbsSeparator 1793 Style = tbsSeparator
1793 end 1794 end
1794 object Label22: TLabel 1795 object Label22: TLabel
1795 Left = 611 1796 Left = 620
1796 Height = 22 1797 Height = 22
1797 Top = 0 1798 Top = 0
1798 Width = 43 1799 Width = 43
@@ -1803,7 +1804,7 @@ object frmTracker: TfrmTracker
1803 ParentFont = False 1804 ParentFont = False
1804 end 1805 end
1805 object Label23: TLabel 1806 object Label23: TLabel
1806 Left = 719 1807 Left = 728
1807 Height = 22 1808 Height = 22
1808 Top = 0 1809 Top = 0
1809 Width = 70 1810 Width = 70
@@ -1814,7 +1815,7 @@ object frmTracker: TfrmTracker
1814 ParentFont = False 1815 ParentFont = False
1815 end 1816 end
1816 object InstrumentComboBox: TComboBox 1817 object InstrumentComboBox: TComboBox
1817 Left = 789 1818 Left = 798
1818 Height = 23 1819 Height = 23
1819 Hint = 'The selected instrument for new notes' 1820 Hint = 'The selected instrument for new notes'
1820 Top = 0 1821 Top = 0
@@ -1832,7 +1833,7 @@ object frmTracker: TfrmTracker
1832 Text = '(no instrument)' 1833 Text = '(no instrument)'
1833 end 1834 end
1834 object Label24: TLabel 1835 object Label24: TLabel
1835 Left = 1003 1836 Left = 1012
1836 Height = 22 1837 Height = 22
1837 Top = 0 1838 Top = 0
1838 Width = 35 1839 Width = 35
@@ -1843,7 +1844,7 @@ object frmTracker: TfrmTracker
1843 ParentFont = False 1844 ParentFont = False
1844 end 1845 end
1845 object StepSpinEdit: TSpinEdit 1846 object StepSpinEdit: TSpinEdit
1846 Left = 1038 1847 Left = 1047
1847 Height = 23 1848 Height = 23
1848 Hint = 'How many rows to step down after entering a new note' 1849 Hint = 'How many rows to step down after entering a new note'
1849 Top = 0 1850 Top = 0
@@ -1854,12 +1855,12 @@ object frmTracker: TfrmTracker
1854 TabOrder = 2 1855 TabOrder = 2
1855 end 1856 end
1856 object ToolButton3: TToolButton 1857 object ToolButton3: TToolButton
1857 Left = 82 1858 Left = 84
1858 Top = 0 1859 Top = 0
1859 Action = PlayStartAction 1860 Action = PlayStartAction
1860 end 1861 end
1861 object ExportGBSButton: TToolButton 1862 object ExportGBSButton: TToolButton
1862 Left = 368 1863 Left = 372
1863 Hint = 'Export the song as a GBS soundtrack' 1864 Hint = 'Export the song as a GBS soundtrack'
1864 Top = 0 1865 Top = 0
1865 Caption = 'Export .GBS' 1866 Caption = 'Export .GBS'
@@ -1867,14 +1868,14 @@ object frmTracker: TfrmTracker
1867 OnClick = ExportGBSButtonClick 1868 OnClick = ExportGBSButtonClick
1868 end 1869 end
1869 object ToolButton5: TToolButton 1870 object ToolButton5: TToolButton
1870 Left = 548 1871 Left = 552
1871 Height = 22 1872 Height = 22
1872 Top = 0 1873 Top = 0
1873 Caption = 'ToolButton5' 1874 Caption = 'ToolButton5'
1874 Style = tbsDivider 1875 Style = tbsDivider
1875 end 1876 end
1876 object ToolButton10: TToolButton 1877 object ToolButton10: TToolButton
1877 Left = 455 1878 Left = 459
1878 Hint = 'Export the song as WAV or MP3' 1879 Hint = 'Export the song as WAV or MP3'
1879 Top = 0 1880 Top = 0
1880 Caption = 'Render Song' 1881 Caption = 'Render Song'
@@ -1890,6 +1891,7 @@ object frmTracker: TfrmTracker
1890 Caption = 'File' 1891 Caption = 'File'
1891 object MenuItem33: TMenuItem 1892 object MenuItem33: TMenuItem
1892 Caption = 'New' 1893 Caption = 'New'
1894 Hint = 'Create a new song'
1893 OnClick = MenuItem33Click 1895 OnClick = MenuItem33Click
1894 end 1896 end
1895 object MenuItem12: TMenuItem 1897 object MenuItem12: TMenuItem
@@ -1914,22 +1916,30 @@ object frmTracker: TfrmTracker
1914 end 1916 end
1915 object MenuItem54: TMenuItem 1917 object MenuItem54: TMenuItem
1916 Caption = 'Export .GB ROM ...' 1918 Caption = 'Export .GB ROM ...'
1919 Hint = 'Export the song as a standalone ROM'
1917 OnClick = ExportGBButtonClick 1920 OnClick = ExportGBButtonClick
1918 end 1921 end
1919 object MenuItem44: TMenuItem 1922 object MenuItem44: TMenuItem
1920 Caption = 'Export .GBS soundtrack ...' 1923 Caption = 'Export .GBS soundtrack ...'
1924 Hint = 'Export the song as a GBS soundtrack'
1921 OnClick = ExportGBSButtonClick 1925 OnClick = ExportGBSButtonClick
1922 end 1926 end
1927 object MenuItem40: TMenuItem
1928 Caption = '-'
1929 end
1923 object ExportRGBDSMenuItem: TMenuItem 1930 object ExportRGBDSMenuItem: TMenuItem
1924 Caption = 'Export RGBDS .obj ...' 1931 Caption = 'Export RGBDS .obj ...'
1932 Hint = 'Export an object suitable for an RGBDS-based project'
1925 OnClick = ExportRGBDSMenuItemClick 1933 OnClick = ExportRGBDSMenuItemClick
1926 end 1934 end
1927 object ExportGBDKMenuItem: TMenuItem 1935 object ExportGBDKMenuItem: TMenuItem
1928 Caption = 'Export GBDK .o ...' 1936 Caption = 'Export GBDK .o ...'
1937 Hint = 'Export an object suitable for a GBDK-based project'
1929 OnClick = ExportGBDKMenuItemClick 1938 OnClick = ExportGBDKMenuItemClick
1930 end 1939 end
1931 object ExportCMenuItem: TMenuItem 1940 object ExportCMenuItem: TMenuItem
1932 Caption = 'Export GBDK .c ...' 1941 Caption = 'Export GBDK .c ...'
1942 Hint = 'Export a C source file suitable for a GBDK-based project'
1933 OnClick = ExportCMenuItemClick 1943 OnClick = ExportCMenuItemClick
1934 end 1944 end
1935 object MenuItem43: TMenuItem 1945 object MenuItem43: TMenuItem
Modifiedtracker.pas +6−1
@@ -32,6 +32,7 @@ type
32 ExportCMenuItem: TMenuItem; 32 ExportCMenuItem: TMenuItem;
33 ExportGBDKMenuItem: TMenuItem; 33 ExportGBDKMenuItem: TMenuItem;
34 ExportRGBDSMenuItem: TMenuItem; 34 ExportRGBDSMenuItem: TMenuItem;
35 MenuItem40: TMenuItem;
35 MenuItem43: TMenuItem; 36 MenuItem43: TMenuItem;
36 MenuItem44: TMenuItem; 37 MenuItem44: TMenuItem;
37 MenuItem54: TMenuItem; 38 MenuItem54: TMenuItem;
@@ -1865,7 +1866,11 @@ end;
1865 procedure TfrmTracker.ExportCMenuItemClick(Sender: TObject); 1866 procedure TfrmTracker.ExportCMenuItemClick(Sender: TObject);
1866 begin 1867 begin
1867 if GBDKCSaveDialog.Execute then begin 1868 if GBDKCSaveDialog.Execute then begin
1868 RenderSongToGBDKC(Song, GBDKCSaveDialog.FileName); 1869 RenderSongToGBDKC(
1870 Song,
1871 InputBox('Song descriptor', 'Enter the song descriptor (must be a valid C symbol):', 'song_descriptor'),
1872 GBDKCSaveDialog.FileName
1873 );
1869 end; 1874 end;
1870 end; 1875 end;
1871 1876