cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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.