makecom.dpr (5799B)
1{$APPTYPE CONSOLE} 2{$IFDEF FPC} 3 {$MODE DELPHI} 4{$ENDIF} 5uses classes, sysutils, math; 6 7procedure ERROR(const msg: ansistring; const params: array of const); 8begin 9 writeln(format(msg, params)); 10 writeln('USAGE: makecom <image.bin> [<image.noi>] <output.com>'); 11 halt(1); 12end; 13 14procedure DecodeCommaText(const Value: ansistring; result: tStringList; adelimiter: ansichar); 15var P, P1 : PAnsiChar; 16 S : ansistring; 17begin 18 if assigned(result) then begin 19 result.BeginUpdate; 20 try 21 result.Clear; 22 P := PChar(Value); 23 while P^ in [#1..#31] do inc(P); 24 while P^ <> #0 do 25 begin 26 if P^ = '"' then 27 S := AnsiExtractQuotedStr(P, '"') 28 else 29 begin 30 P1 := P; 31 while (P^ >= ' ') and (P^ <> adelimiter) do inc(P); 32 SetString(S, P1, P - P1); 33 end; 34 result.Add(S); 35 while P^ in [#1..#31] do inc(P); 36 if P^ = adelimiter then 37 repeat 38 inc(P); 39 until not (P^ in [#1..#31]); 40 end; 41 finally 42 result.EndUpdate; 43 end; 44 end; 45end; 46 47function load_symbols(const filename: ansistring; symbols: tStringList): boolean; 48var s : textfile; 49 str : ansistring; 50 row : tStringList; 51begin 52 result:= assigned(symbols); 53 if result then begin 54 assignfile(s, filename); reset(s); 55 try 56 row := tStringList.create; 57 try 58 while not eof(s) do begin 59 readln(s, str); 60 DecodeCommaText(str, row, ' '); 61 if (row[0] = 'DEF') then begin 62 symbols.Values[row[1]] := row[2]; 63 end; 64 end; 65 result:= true; 66 finally freeandnil(row); end; 67 finally closefile(s); end; 68 end; 69end; 70 71function CopyData(banks: tList; bank: longint; image: tMemoryStream; source_ofs, dest_ofs: longint; len: longint): boolean; 72var i : longint; 73 data : tMemoryStream; 74begin 75 result:= (bank < 255); 76 if result then begin 77 if (banks.count <= bank) then 78 for i:= banks.count to bank do banks.Add(tMemoryStream.Create()); 79 data:= banks[bank]; 80 data.Seek(dest_ofs, soFromBeginning); 81 data.Write(pAnsiChar(image.Memory)[source_ofs], len); 82 end; 83end; 84procedure WriteData(banks: tList; const destname: ansistring); 85var i : longint; 86 ovr : ansistring; 87begin 88 if (banks.count > 0) then begin 89 with tMemoryStream(banks[0]) do try 90 writeln(format('writing program: %s', [destname])); 91 SaveToFile(destname); 92 finally free; end; 93 for i:= 1 to banks.count - 1 do 94 with tMemoryStream(banks[i]) do try 95 ovr:= ChangeFileExt(destname, format('.%.3d', [i])); 96 writeln(format('writing overlay: %s', [ovr])); 97 SaveToFile(ovr); 98 finally free; end; 99 end; 100end; 101 102function Hex2Int(value: ansistring): longint; 103begin 104 if (copy(value, 1, 2)) = '0x' then begin value[1]:= ' '; value[2]:= '$'; end; 105 result:= StrToIntDef(value, 0); 106end; 107 108const section_names = '_CODE,_HOME,_BASE,_CODE_0,_INITIALIZER,_LIT,_GSINIT,_GSFINAL'; 109var name_bin : ansistring; 110 name_noi : ansistring; 111 name_out : ansistring; 112 symbols : tStringList; 113 known : tStringList; 114 banks : tList; 115 source : tMemoryStream; 116 i, bank : longint; 117 name, v, l : ansistring; 118 addr, len : longint; 119begin 120 if (paramcount() = 2) then begin 121 name_bin:= paramstr(1); name_noi:= changefileext(name_bin, '.noi'); name_out:= paramstr(2); 122 end else begin 123 if (paramcount() < 3) then ERROR('ERROR: Not sufficient parameters', []); 124 name_bin:= paramstr(1); name_noi:= paramstr(2); name_out:= paramstr(3); 125 end; 126 127 if not fileexists(name_noi) then ERROR('ERROR: symbol file: "%s" not found', [name_noi]); 128 if not fileexists(name_bin) then ERROR('ERROR: binary image: "%s" not found', [name_bin]); 129 130 known:= tStringList.create; 131 symbols := tStringList.create; 132 try 133 DecodeCommaText(section_names, known, ','); 134 if load_symbols(name_noi, symbols) then begin 135 source:= tMemoryStream.Create; 136 try 137 source.LoadFromFile(name_bin); 138 banks:= tList.Create; 139 with banks do try 140 for i:= 0 to symbols.count - 1 do begin 141 name:= symbols.Names[i]; 142 v:= symbols.Values[name]; 143 if (copy(name, 1, 2) = 's_') then begin 144 name:= copy(name, 3, length(name)); 145 l:= symbols.Values[format('l_%s',[name])]; 146 if length(l) > 0 then begin 147 addr:= Hex2Int(v); 148 len:= Hex2Int(l); 149 150 if (len > 0) then begin 151 if (known.IndexOf(name) >= 0) then begin 152 CopyData(banks, 0, source, addr, math.max(0, addr - $100), len); 153 end; 154 if (copy(Name, 1, 6) = '_CODE_') then begin 155 bank:= addr shr 16; 156 CopyData(banks, bank, source, math.max(0, (addr and $ffff) - $4000) + $4000 * bank, 0, len); 157 end; 158 end; 159 end; 160 end; 161 end; 162 163 if (banks.Count > 0) then begin 164 addr:= Hex2Int(symbols.Values['___overlay_count']); 165 if (addr > $100) then pAnsiChar(tMemoryStream(banks[0]).Memory)[addr - $100]:= chr(banks.Count - 1); 166 addr:= Hex2Int(symbols.Values['___overlay_name']); 167 if (addr > $100) then begin 168 name:= format('%-8.8s', [uppercase(changefileext(extractfilename(name_out), ''))]); 169 system.move(name[1], pAnsiChar(tMemoryStream(banks[0]).Memory)[addr - $100], 8); 170 end; 171 end; 172 173 writeln('writing...'); 174 WriteData(banks, name_out); 175 writeln('done!'); 176 finally banks.free; end; 177 finally freeandnil(source); end; 178 end; 179 finally 180 freeandnil(symbols); 181 freeandnil(known); 182 end; 183 184end.