Passing parameters when calling assembly procedures...

ZXNet echo conference «code.zx»

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.1 ══════════════════ (c) Ivan Roshchin, Moscow Fido: 2:5020/689.53 ZXNet: 500:95/462.53 E-mail: asder_ffc@softhome.net WWW: http://www.ivr.da.ru Passing parameters ═══════════════════ when calling assembly procedures from a BASIC program ════════════════════════════ ════════════════════════════ ("Radiomir. Your computer" 10/2001) Introduction ──────── After a BASIC program is written, often it turns out that it works prohibitively slowly. Yes several ways to solve this problem. You can completely rewrite the program in assembler, achieving maximum performance - but this will have to cost a lot of time and effort. You can use the BASIC compiler - this will not require any significant effort, but the program will not be as fast as one written in assembly language, besides There may also be problems with insufficient memory during compilation or when trying to run a compiled program. It is possible finally, rewrite in assembler only those sections of the program on which most of the time is spent. At the same time performance will be only slightly lower compared to full rewriting the program in assembler, and the amount of work will be much less. It is this method of optimization in a number ofcases turns out to be the most preferable. When using assembly procedures, the question arises passing parameters. In standard BASIC there are means for this very modest: it is only stipulated that the called procedure can return one value in register pair BC, representing which is an integer in the range 0-65535. Let's say, when executing the command .... 1000 LET A = USR 40000 .... the assembler procedure located at the address will be called 40000, after which variable A will be assigned the value register pair BC. You can select a specific area for transferring parameters memory, write values there before calling the procedure passed variables using the POKE operator, and then call - read return values using operator PEEK. Let, say, you need to pass the scaling procedure coordinates located at address 40004, variables X and Y (integers, in the range 0-65535) through memory area 40000-40003 (with Address 40000 contains the value X, in the format minor byte/high byte; with 40002 - Y value, in the same format). The procedure will change these values in a certain way, leaving the result is in the same memory cells; after that you need to read returned values and assign them to variables X1 and Y1. ..... 1000 POKE 40000,X-INT(X/256)*256: POKE 40001,INT(X/256)1010 POKE 40002,Y-INT(Y/256)*256: POKE 40003,INT(Y/256) 1020 RANDOMIZE USR 40004 1030 LET X1=PEEK(40000)+PEEK(40001)*256 1040 LET Y1=PEEK(40002)+PEEK(40003)*256 ..... As we can see, with this method of passing parameters The volume of the BASIC program increases, time is wasted on transmission values (sometimes quite significant - for example, when transmitting arrays), you have to remember which address is which the variable is located, and, finally, it simply may not be enough memory. A more promising way seems to be when an assembler program directly works with variables BASIC. Let's consider this method in more detail. BASIC Variables ────────────────── Let's first consider what variables there are in BASIC, where and in what format they are stored. BASIC program variables are located in the memory area the beginning of which is addressed to the VARS system variable, located at #5C4B=23627. Variables are strictly different after each other, and after the last of them there is byte #80 - a sign end of the variable area. Although variable names are allowed in both uppercase and lowercase Latin letters, as well as spaces and numbers (a number cannot be the first character), in the storage area for variable names are converted to lowercase letters and spaces are not stored (so Thus, for the interpreter the variables Size X and sizex are one and the samethe same), the "$" sign for symbolic variables is also not stored. Below are the different types of variables and the format: their storage (format data given in [1], frankly speaking, do not differ in completeness and accuracy, so a lot had to be study through practical experiments). ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.2 ══════════════════ Numeric variable with a single letter name - name (1 byte) - value (5 bytes) Numeric variable with a multi-character name - name (the code of the first character is increased by #40, the last - by #80) - value (5 bytes) for-next loop variable - name (1 byte), symbol code increased by #80 - value (5 bytes) - limit (5 bytes) - increment (5 bytes) - number of the line in which the corresponding FOR operator (2 bytes) - the number of the operator next after FOR in this line (1 byte) (Note: a variable with a single letter name defined initially as usual, later, if it is used in as a for-next loop variable, changes its format storage.) Numeric array - name (1 byte), symbol code increased by #20 - array length in bytes (2 bytes) - number of dimensions (1 byte) - first dimension (2 bytes) ........................... - last dimension (2 bytes) - elements (5 bytes each), stored in the following order: first the last index increases, then the penultimate one and so on, for example (1,1), (1,2), (1,3), (2,1), (2,2), ... Character variable - name (1 byte), character code reduced by #20 - number of characters (2 bytes) - contents Character array - name (1 byte), symbol code increased by #60- array length in bytes (2 bytes) - number of dimensions (1 byte) - first dimension (2 bytes) ........................... - last dimension (2 bytes) - elements (1 byte each); the storage procedure is the same as for numeric arrays. As we can see, by the value of the first byte of the variable name You can immediately determine its type: ╔══════════════════════════╤═══ ═══════════════════════════════╗ ║ Value range │ Variable type ║ ║ first byte │ ║ ╠══════════════════════════╪═══ ═══════════════════════════════╣ ║ #41-#5A │ symbolic ║ ╟──────────────────────────┼─── ───────────────────────────────╢ ║ #61-#7A │ number (name - one letter) ║ ╟──────────────────────────┼─── ───────────────────────────────╢ ║ #81-#9A │ numeric array ║ ╟──────────────────────────┼─── ───────────────────────────────╢ ║ #A1-#BA │ number (name - several characters) ║ ╟──────────────────────────┼─── ───────────────────────────────╢ ║ #C1-#DA │ character array ║ ╟──────────────────────────┼─── ───────────────────────────────╢ ║ #E1-#FA │ loop variable ║ ╚══════════════════════════╧═══ ═══════════════════════════════╝Table 1 I will provide some information about the five-byte representation form numbers used to store variables. Integers in range 0..65535 are represented as follows: ┌─────┬─────┬─────────────────── ───┬─────────────────────┬─────┐ │ 0 │ 0 │ low byte of a number │ high byte of a number │ 0 │ │ │ │ │ │ │ └─────┴─────┴─────────────────── ───┴─────────────────────┴─────┘ And integers in the range -65535..-1 - like this: ┌─────┬─────┬─────────────────── ───┬─────────────────────┬─────┐ │ 0 │ #FF │ low byte of the number │ high byte of the number │ 0 │ │ │ │(the number is represented in two's complement)│ │ └─────┴─────┴─────────────────── ───┴─────────────────────┴─────┘ Real numbers are stored in a more complex form. Information You can learn about the format of their storage, for example, from [3]. I do not present them here, since working with such numbers is difficult. assembly language is necessary only in very rare cases. It is often possible to transform the problem being solved so that it works only with integers, which makes calculations much faster. Let's try now, armed with the knowledge we have gained, "decrypt" the contents of the real variable area, dump which is shown in Fig. 1. ┌───────────────────────┐ │pic_1.scr ││ │ │ │ │ │ │ │ │ │ │ │ └───────────────────────┘ Fig. 1 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.3 ══════════════════ The first byte of the variable area is #98. He belongs range #81-#9A, therefore the first variable is numeric array. As we remember, for a numeric array the name character code is stored increased by #20. Let's define the name: #98-#20=#78, this is the code character "x". The next two bytes contain the length of the array (not counting the name byte and the two bytes of the length itself). After reading it (#23=35) and moving forward the appropriate number of bytes, we We can immediately move on to the next variable. But for now, do this Let's not, but consider the structure of the array. In the next byte 2 is stored, which means the array is two-dimensional. According to the first dimension it size is 2, according to the second - 3 (and in total, it means 6 elements). Next are the elements themselves. X(1,1)=4, X(1,2)=0, subsequent elements are also zero. The first byte of the next variable is #C1, therefore it is a character array named A$... Well and so on; I hope with you can figure out the rest of this variable area on your own. Procedure for determining the address of a variable ─────────────────────────────────────── To determine the location of a BASIC variable it is convenient use the procedure below. Here are its inputs and output parameters. Input: DE points to variable name converted toin accordance with its type (i.e. the name must be in exactly this form as it is stored in the variable area), ending byte 0. Output: if the variable is found, the Z flag is cleared, HL points in the variable area to the first byte after the name found variable, DE points to the next byte after 0 (which means if you store the names of the sought variables one after another, then, first loading the address of the first name into DE and then calling the procedure sequentially, we will sequentially get the addresses of these variables). If the variable is not found - the Z flag is set, DE remains unchanged. The procedure, when running, changes the contents of register A. VARS EQU #5C4B FIND_VAR LD HL,(VARS) PUSH BC FIND_M0 PUSH DE PUSH HL ;Comparing the name of the current variable with the name of the desired one: FIND_M1 LD A,(DE) INC DE AND A JR Z,FIND_YES ;names match CP(HL) INC HL JR Z,FIND_M1 ;The names do not match - we skip the current variable: POP HL POP DE LD A,(HL) INC HL CP #80 ;Have you reached the end of the variable area? JR Z,FIND_NO ;If yes, exit, flag Z is set. CP#60 JR C,SKIP_M ;skip the character variable CP#80 FIND_M4 LD BC,5JR C,SKIP_BC ;skip the numeric variable ;with a name of one letter CP#A0 JR C,SKIP_M ;skip the numeric array CP#C0 JR NC,FIND_M3 ;Skip a numeric variable with a name of several characters: FIND_M2 LD A,(HL) INC HL R.L.A. JR NC,FIND_M2 JR FIND_M4 FIND_M3 CP #E0 LD C,18 ;B=0! JR NC,SKIP_BC ;skip the loop variable ;Skipping a character variable or array: SKIP_M LD C,(HL) INC HL LD B,(HL) INC HL SKIP_BC ADD HL,BC JR FIND_M0 FIND_YES POP BC ;remove two now unnecessary numbers from the stack POP B.C. INC A ;A will become equal to 1, flag Z will be reset FIND_NO POP BC RET ;output The BASIC interpreter performs a similar search every time accessing any variable - here is one of the reasons low speed of BASIC programs. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.4 ══════════════════ Optimization example ────────────────── Let's try to optimize for performance some a simple BASIC program - for example, the one below. 10 LET N=0: INPUT A$ 20 IF A$="" THEN GO TO 60 30 FOR I=1 TO LEN (A$) 40 IF A$(I)="X" THEN LET N=N+1 50 NEXT I 60 PRINT N This program prompts the user for a string and counts how many times the "X" character appears in it. Critical in terms of performance, the area is obviously a loop in lines 30-50. Let's rewrite it in assembler. Let it be placed Let's say from address 40000. ORG 40000 LD DE,NAME_A ;look for variable A$ CALL FIND_VAR ;Now HL points to a 2-byte value defining ;length of string A$. LD E,(HL) INC HL LD D,(HL) INC HL ;DE is the length of the string, HL indicates the first character of the string. LD BC,0 ;character counter "X" M1 LD A,(HL) CP "X" JR NZ,M2 INC B.C. M2 INC HL DEC DE LD A,D OR E JR NZ,M1 ;BC - number of "X" characters in the line. LD DE,NAME_N ;looking for variable N CALL FIND_VAR ;Now HL points to the value of the variable N. Place it there ;contents of BC, represented in 5-byte form:LD(HL),0 INC HL LD(HL),0 INC HL LD(HL),C INC HL LD(HL),B INC HL LD(HL),0 RET ;output NAME_A DB "a"-#20 ;variable name A$ DB 0 NAME_N DB "n" ;variable name N DB 0 The result of the compilation will be written to the file "file1". After that All that remains is to rewrite the original program: 5 CLEAR 39999: RANDOMIZE USR 15619: REM: LOAD "file1" CODE 10 LET N=0: INPUT A$ 20 IF A$="" THEN GO TO 60 30 RANDOMIZE USR 40000 60 PRINT N Let me remind you of the conditions that the called one must satisfy. BASIC assembly procedure. - maskable interrupts when running your procedure can prohibited, but must be allowed before exiting. Please note that when interrupts are disabled, the value does not increase system timer - this may be important if you use it, say, to calculate execution time programs. - the value of the register pair HL' when exiting the procedure should be the same as at entry - equal to #2758. So what if in the procedure you used HL' for some of your purposes, before exiting, do not forget to enter the commands LD HL, #2758: EXX. - the value of register pair IY should not change whenenabled interrupts, since it is used by the system interrupt handling procedure. So if you need use IY, disable interrupts first, and before resolution, do not forget to restore the contents of IY (there should be number #5C3A). ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.5 ══════════════════ Some useful tips ────────────────────────── It is better to convert the values of numeric variables to post-processing from a 5-byte form into a single or double-byte, depending on the range: this way they can be faster to process. If you need to work with arrays, and in there is enough free space in memory, it is worth copying them to addresses divisible by 256: this will speed up access to elements such an array (read more about how to quickly work with arrays, you can read in [4]). Creating New Variables ───────────────────────── It may be that in the rewritten program fragment a value is assigned to a previously unused variable. In this case, there is no information about it in the area variables, and therefore we need to add it there. For this must be allocated at the end of the variable area (between the end last variable and byte #80) memory area required length and enter the name and value of the new variable into it. Memory area is allocated using the procedure MAKE_ROOM, located in ROM at address #1655. When she calls the HL register pair must contain the address from which you need to allocate space, and in BC - the length of the allocated area. The address of the allocated memory area is easy to determine iftake into account that directly behind the variable area there is area of editable program lines, the beginning address of which stored in the E_LINE system variable. Therefore, for to obtain the desired address, just take the value E_LINE and decrease it by 1. Let's look at an example. Let there be a program like this: 10 INPUT A: INPUT B 20 LET C=A+B 30 PRINT C and we need to rewrite line 20 in assembler. It is known that variables A, B and C are integers and their values belong to the range 0..65535. In this case, the assembly text will be like this: ORG 40000 MAKE_ROOM EQU #1655 E_LINE EQU 23641 LD DE,NAME_A CALL FIND_VAR ;Now HL points to the value of variable A, ;DE points to NAME_B. INC HL INC HL LD C,(HL) INC HL LD B,(HL) ;BC is the value of variable A. CALL FIND_VAR INC HL INC HL LD E,(HL) INC HL LD D,(HL) ;DE is the value of variable B. EX DE,HL ADD HL,BC ;calculated C PUSH HL ;remembered on the stack ;Allocate space for variable C. LD HL,(E_LINE) DEC HL; where we select PUSH HL LD BC,6 ;how much we allocate CALL MAKE_ROOM POP HLLD (HL),"c" ;variable name INC HL POP DE ;popped from stack LD (HL),0 ;variable value INC HL ; and write it down LD (HL),0 ;in 5-byte INC HL ;form LD(HL),E INC HL LD(HL),D INC HL LD(HL),0 RET ;output NAME_A DB "a" ;variable name A DB 0 NAME_B DB "b" ;variable name B DB 0 Literature ────────── 1. "Basic ZX Spectrum". Moscow, VA PRINT, 1993. 2. "Secrets of ROM". "ZX-Review" 10/1991. 3. "ZX Spectrum personal computer. Programming in machine codes and assembly language." Moscow, "Inforcom", 1993. 4. I. Roshchin. "Optimization using the example of intro "Start". "Radiomir. Your computer" 7-10/2001. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.1 ══════════════════ (c) Ivan Roshchin, Moscow Fido: 2:5020/689.53 ZXNet: 500:95/462.53 E-mail: asder_ffc@softhome.net WWW: http://www.ivr.da.ru Passing parameters ═══════════════════ when calling assembly procedures from a BASIC program ════════════════════════════ ════════════════════════════ ("Radiomir. Your computer" 10/2001) Introduction ──────── After a BASIC program is written, often it turns out that it works prohibitively slowly. Yes several ways to solve this problem. You can completely rewrite the program in assembler, achieving maximum performance - but this will have to cost a lot of time and effort. You can use the BASIC compiler - this will not require any significant effort, but the program will not be as fast as one written in assembly language, besides There may also be problems with insufficient memory during compilation or when trying to run a compiled program. It is possible finally, rewrite in assembler only those sections of the program on which most of the time is spent. At the same time performance will be only slightly lower compared to full rewriting the program in assembler, and the amount of work will be much less. It is this method of optimization in a number ofcases turns out to be the most preferable. When using assembly procedures, the question arises passing parameters. In standard BASIC there are means for this very modest: it is only stipulated that the called procedure can return one value in register pair BC, representing which is an integer in the range 0-65535. Let's say, when executing the command .... 1000 LET A = USR 40000 .... the assembler procedure located at the address will be called 40000, after which variable A will be assigned the value register pair BC. You can select a specific area for transferring parameters memory, write values there before calling the procedure passed variables using the POKE operator, and then call - read return values using operator PEEK. Let, say, you need to pass the scaling procedure coordinates located at address 40004, variables X and Y (integers, in the range 0-65535) through memory area 40000-40003 (with Address 40000 contains the value X, in the format minor byte/high byte; with 40002 - Y value, in the same format). The procedure will change these values in a certain way, leaving the result is in the same memory cells; after that you need to read returned values and assign them to variables X1 and Y1. ..... 1000 POKE 40000,X-INT(X/256)*256: POKE 40001,INT(X/256)1010 POKE 40002,Y-INT(Y/256)*256: POKE 40003,INT(Y/256) 1020 RANDOMIZE USR 40004 1030 LET X1=PEEK(40000)+PEEK(40001)*256 1040 LET Y1=PEEK(40002)+PEEK(40003)*256 ..... As we can see, with this method of passing parameters The volume of the BASIC program increases, time is wasted on transmission values (sometimes quite significant - for example, when transmitting arrays), you have to remember which address is which the variable is located, and, finally, it simply may not be enough memory. A more promising way seems to be when an assembler program directly works with variables BASIC. Let's consider this method in more detail. BASIC Variables ────────────────── Let's first consider what variables there are in BASIC, where and in what format they are stored. BASIC program variables are located in the memory area the beginning of which is addressed to the VARS system variable, located at #5C4B=23627. Variables are strictly different after each other, and after the last of them there is byte #80 - a sign end of the variable area. Although variable names are allowed in both uppercase and lowercase Latin letters, as well as spaces and numbers (a number cannot be the first character), in the storage area for variable names are converted to lowercase letters and spaces are not stored (so Thus, for the interpreter the variables Size X and sizex are one and the samethe same), the "$" sign for symbolic variables is also not stored. Below are the different types of variables and the format: their storage (format data given in [1], frankly speaking, do not differ in completeness and accuracy, so a lot had to be study through practical experiments). ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.3 ══════════════════ The first byte of the variable area is #98. He belongs range #81-#9A, therefore the first variable is numeric array. As we remember, for a numeric array the name character code is stored increased by #20. Let's define the name: #98-#20=#78, this is the code character "x". The next two bytes contain the length of the array (not counting the name byte and the two bytes of the length itself). After reading it (#23=35) and moving forward the appropriate number of bytes, we We can immediately move on to the next variable. But for now do this Let's not, but consider the structure of the array. In the next byte 2 is stored, which means the array is two-dimensional. According to the first dimension it size is 2, according to the second - 3 (and in total, it means 6 elements). Next are the elements themselves. X(1,1)=4, X(1,2)=0, subsequent elements are also zero. The first byte of the next variable is #C1, therefore it is a character array named A$... And so on; I hope with you can figure out the rest of this variable area on your own. Procedure for determining the address of a variable ─────────────────────────────────────── To determine the location of a BASIC variable it is convenient use the procedure below. Here are its inputs and output parameters. Input: DE points to variable name converted toin accordance with its type (i.e. the name must be in exactly this form as it is stored in the variable area), ending byte 0. Output: if the variable is found, the Z flag is cleared, HL points in the variable area to the first byte after the name found variable, DE points to the next byte after 0 (which means if you store the names of the sought variables one after another, then, first loading the address of the first name into DE and then calling the procedure sequentially, we will sequentially get the addresses of these variables). If the variable is not found - the Z flag is set, DE remains unchanged. The procedure, when running, changes the contents of register A. VARS EQU #5C4B FIND_VAR LD HL,(VARS) PUSH BC FIND_M0 PUSH DE PUSH HL ;Comparing the name of the current variable with the name of the desired one: FIND_M1 LD A,(DE) INC DE AND A JR Z,FIND_YES ;names match CP(HL) INC HL JR Z,FIND_M1 ;The names do not match - we skip the current variable: POP HL POP DE LD A,(HL) INC HL CP #80 ;Have you reached the end of the variable area? JR Z,FIND_NO ;If yes, exit, flag Z is set. CP#60 JR C,SKIP_M ;skip the character variable CP#80 FIND_M4 LD BC,5JR C,SKIP_BC ;skip the numeric variable ;with a name of one letter CP#A0 JR C,SKIP_M ;skip the numeric array CP#C0 JR NC,FIND_M3 ;Skip a numeric variable with a name of several characters: FIND_M2 LD A,(HL) INC HL R.L.A. JR NC,FIND_M2 JR FIND_M4 FIND_M3 CP #E0 LD C,18 ;B=0! JR NC,SKIP_BC ;skip the loop variable ;Skipping a character variable or array: SKIP_M LD C,(HL) INC HL LD B,(HL) INC HL SKIP_BC ADD HL,BC JR FIND_M0 FIND_YES POP BC ;remove two now unnecessary numbers from the stack POP B.C. INC A ;A will become equal to 1, flag Z will be reset FIND_NO POP BC RET ;output The BASIC interpreter performs a similar search every time accessing any variable - here is one of the reasons low speed of BASIC programs. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.4 ══════════════════ Optimization example ────────────────── Let's try to optimize for performance some a simple BASIC program - for example, the one below. 10 LET N=0: INPUT A$ 20 IF A$="" THEN GO TO 60 30 FOR I=1 TO LEN (A$) 40 IF A$(I)="X" THEN LET N=N+1 50 NEXT I 60 PRINT N This program prompts the user for a string and counts how many times the "X" character appears in it. Critical in terms of performance, the area is obviously a loop in lines 30-50. Let's rewrite it in assembler. Let it be placed Let's say from address 40000. ORG 40000 LD DE,NAME_A ;look for variable A$ CALL FIND_VAR ;Now HL points to a 2-byte value defining ;length of string A$. LD E,(HL) INC HL LD D,(HL) INC HL ;DE is the length of the string, HL indicates the first character of the string. LD BC,0 ;character counter "X" M1 LD A,(HL) CP "X" JR NZ,M2 INC B.C. M2 INC HL DEC DE LD A,D OR E JR NZ,M1 ;BC - number of "X" characters in the line. LD DE,NAME_N ;looking for variable N CALL FIND_VAR ;Now HL points to the value of the variable N. Place it there ;contents of BC, represented in 5-byte form:LD(HL),0 INC HL LD(HL),0 INC HL LD(HL),C INC HL LD(HL),B INC HL LD(HL),0 RET ;output NAME_A DB "a"-#20 ;variable name A$ DB 0 NAME_N DB "n" ;variable name N DB 0 The result of the compilation will be written to the file "file1". After that All that remains is to rewrite the original program: 5 CLEAR 39999: RANDOMIZE USR 15619: REM: LOAD "file1" CODE 10 LET N=0: INPUT A$ 20 IF A$="" THEN GO TO 60 30 RANDOMIZE USR 40000 60 PRINT N Let me remind you of the conditions that the called one must satisfy. BASIC assembly procedure. - maskable interrupts when running your procedure can prohibited, but must be allowed before exiting. Please note that when interrupts are disabled, the value does not increase system timer - this may be important if you use it, say, to calculate execution time programs. - the value of the register pair HL' when exiting the procedure should be the same as at entry - equal to #2758. So what if in the procedure you used HL' for some of your purposes, before exiting, do not forget to enter the commands LD HL, #2758: EXX. - the value of register pair IY should not change whenenabled interrupts, since it is used by the system interrupt handling procedure. So if you need use IY, disable interrupts first, and before resolution, do not forget to restore the contents of IY (there should be number #5C3A). ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 8 February 2002

Hello, All! ═══════════════════ call_asm.5 ══════════════════ Some useful tips ────────────────────────── It is better to convert the values of numeric variables to post-processing from a 5-byte form into a single or double-byte, depending on the range: this way they can be faster to process. If you need to work with arrays, and in there is enough free space in memory, it is worth copying them to addresses divisible by 256: this will speed up access to elements such an array (read more about how to quickly work with arrays, you can read in [4]). Creating New Variables ───────────────────────── It may be that in the rewritten program fragment a value is assigned to a previously unused variable. In this case, there is no information about it in the area variables, and therefore we need to add it there. For this must be allocated at the end of the variable area (between the end last variable and byte #80) memory area required length and enter the name and value of the new variable into it. Memory area is allocated using the procedure MAKE_ROOM, located in ROM at address #1655. When she calls the HL register pair must contain the address from which you need to allocate space, and in BC - the length of the allocated area. The address of the allocated memory area is easy to determine iftake into account that directly behind the variable area there is area of editable program lines, the beginning address of which stored in the E_LINE system variable. Therefore, for to obtain the desired address, just take the value E_LINE and decrease it by 1. Let's look at an example. Let there be a program like this: 10 INPUT A: INPUT B 20 LET C=A+B 30 PRINT C and we need to rewrite line 20 in assembler. It is known that variables A, B and C are integers and their values belong to the range 0..65535. In this case, the assembly text will be like this: ORG 40000 MAKE_ROOM EQU #1655 E_LINE EQU 23641 LD DE,NAME_A CALL FIND_VAR ;Now HL points to the value of variable A, ;DE points to NAME_B. INC HL INC HL LD C,(HL) INC HL LD B,(HL) ;BC is the value of variable A. CALL FIND_VAR INC HL INC HL LD E,(HL) INC HL LD D,(HL) ;DE is the value of variable B. EX DE,HL ADD HL,BC ;calculated C PUSH HL ;remembered on the stack ;Allocate space for variable C. LD HL,(E_LINE) DEC HL; where we select PUSH HL LD BC,6 ;how much we allocate CALL MAKE_ROOM POP HLLD (HL),"c" ;variable name INC HL POP DE ;popped from stack LD (HL),0 ;variable value INC HL ; and write it down LD (HL),0 ;in 5-byte INC HL ;form LD(HL),E INC HL LD(HL),D INC HL LD(HL),0 RET ;output NAME_A DB "a" ;variable name A DB 0 NAME_B DB "b" ;variable name B DB 0 Literature ────────── 1. "Basic ZX Spectrum". Moscow, VA PRINT, 1993. 2. "Secrets of ROM". "ZX-Review" 10/1991. 3. "ZX Spectrum personal computer. Programming in machine codes and assembly language." Moscow, "Inforcom", 1993. 4. I. Roshchin. "Optimization using the example of intro "Start". "Radiomir. Your computer" 7-10/2001. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.