tzxwriter.pas 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. { IHX (Intel Hex format) to TZX (ZX Spectrum tape file format) convertor tool.
  2. This file contains the TZX writer code.
  3. Copyright (C) 2020 Nikolay Nikolov <[email protected]>
  4. This source is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free
  6. Software Foundation; either version 2 of the License, or (at your option)
  7. any later version.
  8. This code is distributed in the hope that it will be useful, but WITHOUT ANY
  9. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  11. details.
  12. A copy of the GNU General Public License is available on the World Wide Web
  13. at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
  14. to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
  15. Boston, MA 02110-1335, USA.
  16. }
  17. unit tzxwriter;
  18. {$mode objfpc}{$H+}
  19. interface
  20. uses
  21. Classes, SysUtils;
  22. type
  23. { TTZXWriter }
  24. TTZXWriter = class
  25. private
  26. FOutStream: TStream;
  27. public
  28. constructor Create(OutStream : TStream);
  29. procedure AppendStandardSpeedDataBlock(const Buffer; Count: Word);
  30. procedure AppendHeader(FileType: Byte; const FileName: string; DataBlockLength, Parameter1, Parameter2: Word);
  31. procedure AppendDataBlock(const Buffer; Count: Word);
  32. procedure AppendProgramFile(const FileName: string; AutostartLine, VarAreaOffset: Word; const Buffer; Count: Word);
  33. procedure AppendCodeFile(const FileName: string; StartAddress: Word; const Buffer; Count: Word);
  34. end;
  35. implementation
  36. { TTZXWriter }
  37. constructor TTZXWriter.Create(OutStream: TStream);
  38. const
  39. Header: string = 'ZXTape!'#$1A#1#20;
  40. begin
  41. FOutStream := OutStream;
  42. FOutStream.Seek(0, soFromBeginning);
  43. FOutStream.Write(Header[1], Length(Header));
  44. end;
  45. procedure TTZXWriter.AppendStandardSpeedDataBlock(const Buffer; Count: Word);
  46. const
  47. PauseMilliseconds = 1000;
  48. begin
  49. FOutStream.WriteByte($10);
  50. FOutStream.WriteByte(Byte(PauseMilliseconds));
  51. FOutStream.WriteByte(Byte(PauseMilliseconds shr 8));
  52. FOutStream.WriteByte(Byte(Count));
  53. FOutStream.WriteByte(Byte(Count shr 8));
  54. FOutStream.Write(Buffer, Count);
  55. end;
  56. procedure TTZXWriter.AppendHeader(FileType: Byte; const FileName: string;
  57. DataBlockLength, Parameter1, Parameter2: Word);
  58. var
  59. HeaderBlock: array [0..18] of Byte;
  60. I: Integer;
  61. Checksum: Byte;
  62. begin
  63. HeaderBlock[0] := 0; { header }
  64. HeaderBlock[1] := FileType;
  65. { file name }
  66. for I := 1 to 10 do
  67. if I <= Length(FileName) then
  68. HeaderBlock[I + 1] := Ord(FileName[I])
  69. else
  70. HeaderBlock[I + 1] := Ord(' ');
  71. HeaderBlock[12] := Byte(DataBlockLength);
  72. HeaderBlock[13] := Byte(DataBlockLength shr 8);
  73. HeaderBlock[14] := Byte(Parameter1);
  74. HeaderBlock[15] := Byte(Parameter1 shr 8);
  75. HeaderBlock[16] := Byte(Parameter2);
  76. HeaderBlock[17] := Byte(Parameter2 shr 8);
  77. Checksum := 0;
  78. for I := 0 to 17 do
  79. Checksum := Checksum xor HeaderBlock[I];
  80. HeaderBlock[18] := Checksum;
  81. AppendStandardSpeedDataBlock(HeaderBlock, SizeOf(HeaderBlock));
  82. end;
  83. procedure TTZXWriter.AppendDataBlock(const Buffer; Count: Word);
  84. var
  85. I: Integer;
  86. Checksum: Byte;
  87. DataBlock: array of Byte;
  88. begin
  89. SetLength(DataBlock, Count + 2);
  90. Move(Buffer, DataBlock[1], Count);
  91. DataBlock[0] := $FF; { data }
  92. Checksum := 0;
  93. for I := 0 to High(DataBlock) - 1 do
  94. Checksum := Checksum xor DataBlock[I];
  95. DataBlock[High(DataBlock)] := Checksum;
  96. AppendStandardSpeedDataBlock(DataBlock[0], Length(DataBlock));
  97. end;
  98. procedure TTZXWriter.AppendProgramFile(const FileName: string; AutostartLine,
  99. VarAreaOffset: Word; const Buffer; Count: Word);
  100. begin
  101. AppendHeader(0, FileName, Count, AutostartLine, VarAreaOffset);
  102. AppendDataBlock(Buffer, Count);
  103. end;
  104. procedure TTZXWriter.AppendCodeFile(const FileName: string; StartAddress: Word;
  105. const Buffer; Count: Word);
  106. begin
  107. AppendHeader(3, FileName, Count, StartAddress, 32768);
  108. AppendDataBlock(Buffer, Count);
  109. end;
  110. end.