There are some tape copiers, such as LERM that claim to be able to copy tapes which contain software that takes the full 48kbyte of RAM.

However, this seems impossible on a Spectrum, when the whole 48kb is read from a single file on disk.

How do they work?

  • The Key was my preferred copier. No one seems to have mentioned that one. – Greenonline Nov 25 '19 at 22:43

These programs usually had a mono-color background with very little text. By setting the color of the screen as "black ink on black paper" or "white ink on white paper", it is possible to relocate the whole software in video RAM and hide it from view.

These programs were tiny asm utilities (they used 1 or 2 kilobytes or RAM) which copied themselves to videoram and used the rest of RAM as a buffer to copy the software they read from tape. Usually they discarded or corrupted the tiny bit of video memory they could not copy.

So, technically, they were not copying the whole 48k, but they did allow you to make a copy of a 48kbyte file, by discarding the video data.

See for example Two Speed Copy:

Screenshot - Two Speed Copy

| improve this answer | |
  • Yes, I wrote a "hacker" toolkit for the ZX Spectrum that people (including me) used to disassemble games to discover pokes. It was able to relocate itself anywhere in memory, including within the 6k video memory. Self-relocating code was meant to be impossible in Z80A, but as with all these things, it was easy when you knew how. – Steve Jones Jan 27 '18 at 20:21

There are multiple techniques used by tape copy programs to be able to copy large blocks of data. By large we mean close to the whole RAM capacity (48 KiB) or even more!

Using maximum of the available RAM

ZX Spectrum 48K (and ZX Spectrum+) has 48 KiB (49152 B) of RAM from which 6 KiB (monochrome pixels) + 768 B (colour attributes) are being used for video RAM. A simple copier which uses the video RAM just for ordinary displaying will have about 41 KiB (~42000 B) of space for copying.

A program can use not only portions of memory used by the BASIC interpreter but also the video RAM. For example Tape-File Copy created in 1986 by Arnošt Večerka lets you select which portion of video RAM will be used for storing the data being copied this program allows capacity up to 44288 B. In the screenshot below the upper part showing the remaining capacity hides the pixels containing data by using the same colour for background and foreground. The lower part uses both the pixel and colour attribute part for visibly storing the data.

Tape-File Copy

Limiting the program functions (special mode)

BS Copy 48F/2 written in 1990 by Slavomír Lábsky is a little bit "Spartan". It provides only load, save and clear functions, also it shows information only in a single line of the screen (hard to find on the screenshot below :) but it has incredible 48082 B of available RAM.

BS Copy 48F/2

There are also programs which go further. For example in special mode they can copy only a single block and they show no information on the screen but they occupy just a tiny space in RAM. One of them is Iso Copy 1 which in Max. copy mode provides 49122 available bytes.

Compressing the data in RAM

The mentioned program BS Copy in addition to large free RAM compresses the loaded data in RAM. It uses just a simple compression of repeated bytes but in many cases this could save a lot of memory and in effect you can copy blocks larger than the physical RAM.

I am not sure what LERM Tape Utility exactly does in the "B" mode which is said to be able to copy blocks larger than 48 KiB. But it seems that it either compresses the data or it somehow skips unimportant parts of the data.

Memory paging on ZX Spectrum models with additional RAM

It is worth to mention that there are copiers which are able to use extended RAM in models like ZX Spectrum 128 or home-made extensions like ZX Spectrum 80k. Though the memory space is not continuous in these computers the load and save routines inside the copiers can switch the memory pages during operation and copy extremely large blocks.

| improve this answer | |
  • I am very happy you mentioned compression-on-the-fly (every case that I know of used some kind of RLE); your answer should have been the one accepted as "best". – introspec Feb 15 '18 at 15:36
  • 1
    Regarding memory paging: On a +2A / +3, it was also possible to page the memory to a 64K RAM configuration, which would have allowed processing of large tape blocks in contiguous memory. I used this technique in a hand-rolled tape-to-TAP converter. – john_e May 1 at 11:31

Assuming a program consisting of a unique big block of 49152 bytes (the whole RAM space). A routine that may be used for a copier to copy this block would sit at the top memory, say at address 64000 along with the stack. Prior to that, the copier asks the user to start loading the big block, just to get the flag byte (which may be different than 255). This first load is very short, as the flag byte is the first byte present after the sync pulse.

Then, the copier sets the computer to load a block starting at address 9472, with a length of 49152 bytes and a flag as got in the first stage. That is: the block starts loading into ROM. Obviously, the first 6912 bytes won't be actually copied, but this is just the screen, which may or may not be needed to run the program. The rest of the program is therefore loaded from address 16384 to 58623, making a total length of 42240 bytes. The screen will surely show garbage during the load process.

The copier is still safe beginning at address 64000. It will craft a header block of type 3 (Bytes), a file name, start address of 23296 and length according to the number of bytes actually copied (worst case it's 42240 bytes). It will save the header, then the block just loaded beginning from 16384.

To recover the original screen content (which might have code hidden in it, or used by the initialization routines to check for integrity as a copy countermeasure), the copier would ask the user to load the big block for a second time, but this time the loader would load only 6912 bytes to address 16384, discarding the rest of the big block. The copier then, would make another header for the screen file, saving it.

At the end we end up with two blocks: the first one is a big block of 42240 bytes that will start at 23296, and the second one, smaller, containing the screen, that will start at 16384 with the standard length for a screen of 6912 bytes.

Using a copier or by other means, the user would swap the blocks in tape so the screen block comes first, then the big block. A BASIC loader for the whole program would be something like:

10 POKE 23729,111: LOAD ""SCREEN$: LOAD ""CODE

The POKE command modifies the address of the output routine for the "S" channel to point to an address in ROM in where a RET instruction is stored. The effect of this is to silent any text output to the screen, which would corrupt the screen loaded when the second block loads its header and prints the "Bytes: ...." text.

This loader assumes that the stack pointer doesn't get changed from its default value at boot, which will be case for some programs. Others may need the user to get access to the original loader to see what number the CLEAR statement has.

A example routine that performs the copy of the big block is now presented. It is from the spanish magazine "Microhobby" and belongs to a series of articles collectively called "The Bible of the Hacker". The routine is featured in the XIV issue.

As presented here, the routine is meant to be used from plain BASIC. It uses the DEF FN method so one can run the routine with an argument, in this case, the flag needed for the big block. So, to use the routine you would set up a small BASIC program as this:

10 DEF FN A(N) = USR 64000

So, assuming the flag is 255, you would start the routine by typing:


Scanned code listing

Link to the scanned article (spanish): http://microhobby.speccy.cz/mhf/088/MH088_21.jpg

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.