Improved compression of Z80 assembly language programs

ZXNet echo conference «code.zx»

From Ivan Roshin To All 19 April 2003

Hello, All! ═══════════════════ bestpack.t ══════════════════ (c) Ivan Roshchin, Moscow Fido: 2:5020/689.53 ZXNet: 500:95/462.53 E-mail: bestview@mtu-net.ru WWW: http://www.ivr.da.ru Improved compression of Z80 assembly language programs ═════════════════════ ══════════════════════ "Radiomir. Your computer" 4/2003. Last edit date: 12/27/2002. Most commonly used for compressing assembly programs HRUST packer of Dmitry Pyankov, as I found out as a result experiments, compresses even two or three identical ones standing next to each other byte. Here I want to talk about how it can be used to improve program compression. Improving compression will save the disk space occupied by the program, and if the program is written so that its individual parts are stored in memory in a packed form and unpacked if necessary, this will help save money place in memory. So, what is the essence of the method? This technique is often used optimization when the variable is placed directly in loading command, thereby reducing the size of the program and the execution time is reduced (for more details, see you can read in [1]). For example, instead of this: VAR DS 1 ......... LD A,(VAR) can be written like this (it will be 2 bytes shorter and 6 clock cycles faster): LD A,0 VAR EQU $-1If the original value of a variable is not used in program, then it makes sense to make this value such that after compilation, the result was a sequence of identical bytes, which can be compressed by the packer. That is, a byte the operand must be equal to the previous byte. In this case previous byte - operation code "LD A,n", equal to #3E, Therefore, we write like this: LD A,#3E VAR EQU $-1 As a result, after compilation, the corresponding section program will be two identical bytes #3E. This method can be used for other commands in which the original operand value is not used. Let for example, in the program there is a command CALL 0, where instead of 0 in front By executing this command, some address is written. Exactly like that However, to increase the compression ratio, we make the operand equal not 0, but a number consisting of bytes equal to the previous byte (code operations CALL nn), resulting in CALL #CDCD. If in a program using assembler directives DB, DW, DS variables or memory areas are defined, initial whose value is not used, then to improve their compression It also makes sense to fill with the value of the previous byte. Let For example, the program contains the following fragment: JP label1 DS 20 The JP instruction in machine code is represented by three bytes;the last of them is the most significant byte of the operand, that is, label1/256. Accordingly, in the program we write: JP label1 DS 20,label1/256 So what do we have? When using the described method to improve compression, the programmer has to remember opcodes (either refer to the directory each time, or type the command in debugger and see what code you get). Moreover, so as not to get confused, for each team in which a substitution is made operand, you will have to write a comment explaining that the specified in the command the value is needed only for better compression and not used when running the program. It is clear that this is very inconvenient. So I suggest implement support for this method of improving compression at the level compiler. You can use the following recording form: if in instead of the operand value, put the symbol "", then the compiler will fill the byte(s) of the operand with the value of the previous one byte of memory. Thus, the entry "LD A," would be equivalent to "LD A,#3E", "CALL" - equivalent to "CALL #CDCD", "JR" - "JR #18", and so on. The commands "DB", "DW", "DS n," will respectively mean that 1, 2, n bytes of memory are filled the value of the previous byte. In this case, the programmer will not need to remember command codes and comment on such sections of the program; without any comments it will be clear that such a command is used to increasing the degree of program compression.But there are no such compilers yet, and the operands will have to be replaced manually. For convenience, I will provide information about what you need replace the operand for some assembler instructions. LD A, = LD A,#3E LD IX, = LD IX,#2121 LD B, = LD B,#06 LD IY, = LD IY,#2121 LD C, = LD C,#0E LD SP, = LD SP,#3131 LD D, = LD D,#16 LD (HL), = LD (HL),#36 LD E, = LD E,#1E ADD A, = ADD A,#C6 LD H, = LD H,#26 ADC A, = ADC A,#CE LD L, = LD L,#2E SUB = SUB #D6 LD XH, = LD XH,#26 SBC A, = SBC A,#DE LD XL, = LD XL,#2E AND = AND #E6 LD YH, = LD YH,#26 OR = OR #F6 LD YL, = LD YL,#2E XOR = XOR #EE LD BC, = LD BC,#0101 JP = JP #C3C3 LD DE, = LD DE,#1111 JR = JR #18 LD HL, = LD HL,#2121 CALL = CALL #CDCD By the way, the compiler can act in more complex ways thus, without necessarily replacing the byte(s) of the operand with the value of the previous byte. Let the program have the following sequence of commands: LD HL,#1234 CALL subr1 LD HL,\n CALL subr1 In this case, it would be more profitable to make the third operand commands are not #2121, but #1234 - then after compilation we will get twoconsecutive identical groups of 6 bytes, which will shrink more efficiently. So, the compiler can track similar situations and decide what values the bytes will take operand in ""-commands. Another option for the logic of the compiler is not to accept decide on what values to fill the bytes with operands in ""-instructions, and shift this task directly to the packer. In this case, the compiler generates two output file: in one - the compiled program, and in friend indicates which bytes this program can accept arbitrary values. The packer parses both files and selects the values of these bytes so that the size of the program after packaging was minimal. But such a packer still needs to be written! Or if it's seems more convenient, you can write a separate program, which would take the two files described above and produce one file with set byte values, which is then fed to packer's entrance. But to ensure the best compression, this the program must know exactly how packaging is carried out. By the way, in [2] I wrote about a method for increasing the compression of music modules, based on automatic detection of module bytes, whose initial values are not used during playback (which means they can be anything). By filling these bytes value of the previous byte and an increase in degree was achievedcompression. So, there you can perform the replacement in the same way without simply to the value of the previous byte, and so that the compression is the best. Literature ────────── 1. I. Roshchin. "Optimization using the example of intro 'Start'". "Radiomir. Your computer" 7-10/2001. 2. I. Roshchin. "Increasing the compression ratio of music modules." "Radiomir. Your computer" 7/2002. ════════════════════════════════ ════════════════════════════════ My other articles on improving assembler: 1. "Several proposals for improving the assembler." "ZX-Review" 7-10/1997. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.