📜 ⬆️ ⬇️

Adaptation programs for the ZX Spectrum to TR-DOS with modern tools. Part 3

As we found out in the previous part , the game machine codes cannot be downloaded from a diskette directly to the destination address. We will load them to another place, and after loading we will move where necessary. In addition, we want to make a monoblock loader, when both the loader and the downloaded data are in the same BASIC file. Such a loader can only be written in machine codes. At the same time, since we have a monoblock file, the loader in machine codes will need to be placed in the comments to the loader in BASIC.


Floppy 5.25 "


Total, the following turns out:


  1. From BASIC, we transfer control to the program in machine codes.
  2. The program in machine codes transfers the loader from the BASIC area to another area that is not affected by the game machine codes, and transfers control to it.
  3. Download and unpack the boot image.
  4. We load machine game codes into a region that does not overlap the region of system variables.
  5. We transfer the machine codes to the destination address.
  6. We transfer management to the program.

Development will have to start from the middle (point 3). The fact is that in order to write a transfer program, you need to know the size of the program being moved, and in order to embed machine codes into the BASIC, you need to know the size of the transfer program.


Monoblock loader (part in machine codes)


In TR-DOS, downloading the data of a monoblock file is more like loading a headless file from a tape, when data of a known size is simply read from the current position and loaded into a specific memory area. For this in the TR-DOS subprogram is responsible at #3D13 . First, download and unzip the picture:


 LD DE, ($5CF4) ;        LD BC, $0805 ;  B  -  (9)*, ;   —   #05 ( ) LD HL, $8000 ;    32768** CALL $3D13 ;   TR-DOS CALL $8000 ;    

& ast; - see the compression of the boot image in the previous section;
& ast; & ast; - unpacker relocated, so you can download anywhere.


Similarly, we load the game machine codes:


 LD DE, ($5CF4) ;        LD BC, $2505 ;  B  - , ;   —   #05 ( ) LD HL, $6000 ;    24576 CALL $3D13 ;   TR-DOS 

At this stage, we no longer need the TR-DOS, we can transfer the machine codes to the destination address using the LDIR processor LDIR :


 LD HL, $6000 ;  (,      ) LD DE, $5B00 ;  LD BC, $2500 ;     (  data.bin) LDIR 

Well, in the end, we transfer control to the program in the same way as in the original loader - by moving the stack pointer:


 LD SP, $5D7C RET 

Now that the bootloader code is ready, you need to compile it in order to know its size, which we will need next.


 $ pasmo tmp.asm tmp.bin $ wc -c tmp.bin 44 tmp.bin 

Boot loader procedure


The bootloader is 44 bytes. Now you need to write a procedure for moving the loader from comments in BASIC (item 2 of the list at the beginning of the article). The rule of thumb is that the address where the BASIC area is located may vary depending on the peripherals connected to the computer, therefore, to determine where you need to transfer data, you need to be guided either by the system variable PROG (as well as in the original loader) or on the software counter (register PC processor).


It is impossible to access the program counter so easily - no processor instructions like LD HL, PC do not exist. I spotted the solution in Laser Compress and it looks like this (not really targeted use of the UNSTACK_Z procedure):


 LD DE, $00 ;     ,     , ;    .     ;    1 INC E ;  1  E,    ,    ;      .     1  CALL $1FC6 ;    ( ,  LD HL, PC) ADD HL, DE ;       LD DE, $F800 ;    LD BC, $002C ;  ,   (44 ) LDIR JP $F800 ;    ;      ;        

At the time of the procedure call ROM #1FC6 on the stack will be the address of the next instruction ( ADD HL, DE ). That he will be recorded as a result of a procedure call in HL . Accordingly, to determine the number to be written in the very first line, you need to compile a piece from ADD HL, DE to the end and see how long it will take:


 $ pasmo tmp.asm tmp.bin $ wc -c tmp.bin 12 tmp.bin 

It turned out 12 bytes. Accordingly, we write 11 ( #0B ) in the first line.


Next, we compose the move procedure with the loader (see the finished file ), which it will move and re-compile. It should be 56 bytes.


Here it should be noted that after I wrote this piece, I figured out that instead of calculating the length of the program being moved, you could use labels and let the assembler figure it out for himself. But for historical justice, let's leave everything as it is.


Monoblock loader (part in BASIC)


Now that we know the size of the bootloader in machine codes, we can write the bootloader in BASIC and collect everything into a monoblock file.


Machine codes in the BASIC file embedded or in the comments, or at the end of the file. The second usually makes it difficult to study the file and is more suitable for protection, so we will use the first option. A variant with a comment is as follows:


  1 REM @#$%... 10 RANDOMIZE USR (PEEK 23635+256*PEEK 23636+5) 

23635 ( #5C53 ) is the address of the system variable PROG , which we mentioned earlier. 5 is the offset of the first comment character relative to PROG (2 bytes occupy the line number, 2 bytes is the length of the line and 1 byte is the REM operator). If you want to add any more comments before the machine codes, such as your name, phone number or postal address, the value 5 will need to be corrected.


If we didn’t use any additional utilities to create the bootloader, we would have to enter arbitrary characters in RL no less than the length of the program in machine codes that we want to put in place of the comment (in our case 56 bytes) after REM . After that, it would be possible to load the program there through LOAD "" CODE PEEK 23635+256*PEEK 23636+5 and save the file.


However, the bas2tap utility can greatly facilitate the process, since it can compile a basic file and embed binary data in it if each byte is represented as a hexadecimal number in curly brackets. To do this, run the compiled boot loader through hexdump :


  $ hexdump -ve '1/1 "{%02x}"' loader.bin {11}{0b}{00}{1c}{cd}{c6}{1f}{19}{11}... 

The hexdump output hexdump inserted into the place of the comment in the first line after REM and we compile the loader on BASIC ( -sboot is the file name on the tape, -a10 is the line number of the autostart):


 $ bas2tap -sboot -a10 boot.bas boot.tap 

hobeta convert the bootloader from tap format to hobeta via intermediate format 0 :


 $ tapto0 -f boot.tap $ 0tohob boot.000 

Creating a monoblock file


By this moment we already have all the necessary files for creating an image of a floppy disk. You can create an image and copy all the necessary files into it:


 createtrd Pac-Man.trd hobeta2trd boot.\$$B Pac-Man.trd hobeta2trd screen.\$$C Pac-Man.trd hobeta2trd data.\$$C Pac-Man.trd 

The resulting floppy image should already work. You can run it in the emulator and check, but that's not all. Since we are loading the subsequent files not by name, but based on the position of the head of the drive, the download will work only if the files are on the diskette strictly one after another. This needs to be fixed.


The principle is as follows: TR-DOS stores redundant information about file size:


  1. Size in sectors - used to place files on a floppy disk and copy.
  2. Size in bytes - used to load content.

Typically, these sizes correspond to each other (256 bytes per sector), but this is not necessary. We will take advantage of this. If you change the size of the boot file in sectors to a value equal to the total size of all the files that we want to load, but not change the size in bytes, TR-DOS will copy all the data as one large file, but only the BASIC will be loaded at boot time -part.


On a real Spectrum or in an emulator, the zero track can be edited with programs like Disk Doctor, for example, Hex Disk Editor :


Hex Disk Editor


But it can be made simpler: a trd image is nothing more than a byte copy of all data on a diskette, so it can be edited in any hex editor:


 $ hexdump -C Pac-Man.trd | head -4 00000000 62 6f 6f 74 20 20 20 20 42 d0 00 d0 00 01 00 01 |boot B.......| 00000010 73 63 72 65 65 6e 20 20 43 40 9c 14 07 08 01 01 |screen C@......| 00000020 64 61 74 61 20 20 20 20 43 00 5b 00 25 25 09 01 |data C.[.%%..| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 

As you can see, at the very beginning of the diskette (on the zero track) there is a file allocation table, in which information about each file takes 16 bytes. The size in sectors is stored in a byte with offset #0D (third column to the right). The size of our files is #01 , #08 and #25 sectors, for a total of #2E . We write this value in the corresponding byte, and remove the remaining headers, because they are no longer needed:


 $ hexdump -C Pac-Man.trd | head -4 00000000 62 6f 6f 74 20 20 20 20 42 d0 00 d0 00 2E 00 01 |boot B.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 

Now we have a complete floppy image with a monoblock file. It must be properly loaded and completely copied from a floppy to a floppy. It remains only to reduce the size of the image. Since a trd image is a byte copy, it always takes 640KB. In practice, in most cases, it is more convenient to use the scl format, which looks more like hobeta stores the file data itself:


 $ trd2scl Pac-Man.trd Pac-Man.scl 

Now for sure. The adaptation process from beginning to end can be found in the project githab repository.


Instruments:


  1. Pasmo - cross assembler for Z80.
  2. bas2tap - cross-compiler of the Spectrum dialect of BASIC.
  3. trd2scl - converter trd-images to scl.

Related Links:


  1. “Adaptation of programs to the TR-DOS system” by Nikolay Rodionov.
  2. "TR-DOS Functions" from the magazine Info Guide â„–1.
  3. “The structure of the TR-DOS diskette” from the book “TR-DOS for professionals and amateurs” .
  4. Handbook of system variables and procedures ROM Spectrum .

')

Source: https://habr.com/ru/post/458782/


All Articles