Scenergy #02
31 декабря 1999 |
|
Coding - Flying is makrobiblioteku: Memory Management Library.
Memory Management Library 0. Entry In this article we'll discuss the one on my opinion, very necessary for all things - my makrobiblioteke Memory Management Library. Hmm ... Judging from the top, from modesty I am not die:) But I have reasons to talk such things as what will be discussed in This article can really strongly make life easier for the encoder. Well, that's enough praise yourself - get down to business. 1. Overview So, as you may have noticed - Memory Management Library - a library. But not simple and makrobiblioteka. And it means that the use of this library will not impact on your code as there is nothing in a line that would compiled into executable code. "Why is it then necessary?" You ask. "And then!" - I will answer you:) Next to facilitate the implementation of a number of problems with which the encoder encountered in virtually every their program. Namely: - Memory allocation - Calculation of the screen address - Creation of tables of offsets, or pointers - Set the fields of data structures All these problems can be solved by using a set macros in this library. Ie they just help you organize your code so that he could easily if desired, be modified without undue Works by conversion of numbers in accordance with change the initial data. In this library there is one, in my opinion, a great advantage - as opposed from the rest of my code, which compiled only in TASM v4.12 and nowhere more, this library is ported to me and in ALASM v4.2! Ie users ALASM'a can also take advantage of work using this library is not transplanting anywhere from your favorite assembler. Moreover, if in any another assembler will support macros - this library will be without problems and move there. Below you will find detailed descriptions of all Parts of the library, as well as examples of its use. In the Appendix you will find yourself source code library formats TASM4 and ALASM. In addition, as an example of its You can see the use of sources ZXA library. But before I begin to describe itself library, I have to make a comment, concerning ALASM'a. The fact that this assembler does not function DISPLAY (not understand why KVA / E-Mage it did not), but this function is used in the library to issue warnings about the overflow memory during compilation. Therefore, there is one difference in the work of the library in TASM'e and ALASM'e: in ALASM'e macro DISPLAY_INFO simply creates a variable which contains statistical information on the distribution of memory in the program, while TASM'e he In addition, displays it on screen as well, if necessary, issues a warning overpayment of Memory. But this is the only difference in these versions of libraries, Otherwise, their work is identical. And now, direct descriptions. 2. Storage allocation This is undoubtedly the most important part of this library. You could even say that all the rest - no more than supplements to this the main function for which the library developed initially. If you've read in Scenergy # 1 my article "On use macros, then you probably remember, I've mentioned it on the possibility of use macros to solve the problem memory allocation in the program. More that - in an application in the archive MusSync.Z, could find the file MEMORY.A which, essence, is the first version of the library. K Unfortunately, that version was severely sharpened under one single distribution model memory and could not be used as General Library. Moreover, It turned out to be a bug, which I just learned today, after almost 2 years using it:) So, what can this library? 1) It allows you to allocate blocks of memory in your program. It is possible to distinguish unlimited number of blocks. Dimensions blocks are also unrestricted. Except You can also select blocks with alignment addresses for interface # 100-byte (so that address of the selected block has the address of the form # Xx00, where # xx - any number). 2) It has two modes: you can consider all the available memory as one large piece or split it into slow (SLOW) and fast (FAST). Except addition, a separate unit is considered typed into the main memory page. 3) You can allocate memory in the usual way (From lowest address to highest) or the principle of the stack (from highest to lowest). 4) Location and dimensions of any piece memory in which to allocate memory you can customize. Method of allocation (See p.3) is also configured for each block. 5) After compiling the program, all data Statistics on memory allocation can be obtained from the special variables. For TASM'ovskoy version of the library, these data also printed directly on the screen. 6) In TASM'ovskoy version of the library also implemented control over memory allocation. If the allocated memory blocks "Climb" to the code or data - issued a warning. In addition You can control the "climbing" the code or data in page memory. Unfortunately, the last point is realized only because TASM'e ALASM does not support function DISPLAY. Therefore, users ALASM'a have to manually control overflow when allocating memory. Well, or ALASM'e finish in the feature:) And now the details of all the listed above functions. 2.1 macros for memory allocation As has been said - there are two modes of library work, depending on whether What pattern of memory you need in your program: - All the memory is one big piece. This mode is appropriate if, for example, your program is to address # 6000, and the memory above it should be used to allocate blocks of memory. - Memory is divided into the SLOW and FAST. This mode is suitable if your program written based on the availability of computers with "Slow" memory. In this case, the code usually located at address # 8000, Region # 6000 - # 7FFF regarded as "Slow" memory and is used under storage tables, and all the memory up to # C000 considered "fast" and is used under posed procedure. Note that in both modes, page- Memory (# C000-# F) is considered as separate block UPPER memory. Usually this it may be necessary because program now usually written under 128kb of memory and need to considered separately paged memory. However, if your program does not require switching pages - this is possible together with some others. But back to the operating modes of the library. Mode is set to variable USE_COMMON_MEMORY. It can take two values: YES and NO. If USE_COMMON_MEMORY = YES, the library will work in the first mode (with general memory unit), if NO, the memory will divided into SLOW and FAST. By default USE_COMMON_MEMORY = NO. As you can see from all written above - all in all modes, there Unit 4, in which we can allocate memory: - Total (COMMON) - "Slow" (SLOW) - "Fast" (FAST) - Pagination (UPPER) In addition, as already mentioned - you can also allocate memory aligned to addresses for interface # 100 bytes. Ie just library, there are eight macros. Their names made under the scheme: GET_x_MEMORY - for memory allocation. GET_x_MEM_XX00 - for memory allocation aligned to address the border # 100 bytes (the address mask - # xx00). Here "x" - any of the identifiers memory unit (COMMON, SLOW, FAST, UPPER). The only exception - the identifier COMMON skipped. Ie asked the following macro names: For memory allocation to allocate memory from address alignment GET_MEMORY GET_MEM_XX00 GET_SLOW_MEMORY GET_SLOW_MEM_XX00 GET_FAST_MEMORY GET_FAST_MEM_XX00 GET_UPPER_MEMORY GET_UPPER_MEM_XX00 However, their work depends on the mode of the library: If USE_COMMON_MEMORY = NO, then the macros GET_MEMORY GET_MEM_XX00 and do nothing as block of memory for them at this mode simply does not exist. In TASM'ovskoy version library when you attempt to use these Macros in this mode will be issued on display a warning. In ALASM'vskoy version coder have to control myself correct setting mode as in Otherwise, the memory simply will not allocated and the program will naturally unworkable. If USE_COMMON_MEMORY = YES, then all calls macros for SLOW and FAST units are redirected to the COMMON block. Thus can allocate memory by calling GET_SLOW_x and GET_FAST_x and not worry about that in which case it will have to rewrite code. It is so written in the library ZXA library and therefore it can be safely used in Both modes of library work - memory will still be allocated properly. The general format of a macro call: GET_x_MEMORY <Variable>, <Memory size> GET_x_MEM_XX00 <Variable>, <Memory size> Here <Variable> - a label for the allocated memory block, <Memory size> - block size in bytes. The label is automatically created so that you can create it manually through the EQU is not needed. To set <Memory size> can use any expression in the standard assembler syntax. 2.2 Macros for configuring memory In addition to the operating mode on the results of libraries also directly influences memory configuration. Memory Configuration mean job location and the size of the memory areas to be used to allocate memory, also how memory allocation in each of the these sites. Not necessarily ask these data for all blocks of memory, enough ask them for only those blocks that you really will use in its program. For example, if your program located at address # 6000 and the entire memory above it is free and can be used for memory allocation, then it will be enough determine the data only for COMMON block memory. Memory configuration is also made with macros. Their 4, according to the number given in the library of memory blocks: SET_MEMORY - for the COMMON memory SET_SLOW - for SLOW memory SET_FAST - for FAST memory SET_UPPER - for UPPER memory The general format of a macro call: SET_x <Low bound>, <High bound>, <YES/NO> Here <Low bound> - address the lower boundary memory area, which will be used for memory allocation, <High bound> - Address the upper limit of memory space. Last parameter defines how to stand out Memory: YES - the memory will be allocated on the basis of stack - from the upper memory to the younger. NO - the memory will be allocated from the younger address to the elders. It must be noted that in <High bound> actually specify a byte address, the next immediately after the allocated block memory. Ie such a challenge: SET_MEMORY # 6000, # 8000, YES allocate block of memory addresses # 6000 - # 7FFF with memory allocation on the basis of the stack. Through the use of the parameter specifying principle of allocation, you can more flexibly adjust the distribution scheme memory in your program. For example, if block of memory to allocate is directly at the code of your program, then you will clearly be useful to the memory distributed, moving "towards" code ie on the principle of the stack. But the bottom or Page memory is more convenient to have the usual scheme of distribution. Yes, still need to talk about how memory is configured by default, and how it can change. Memory configuration by default looks as follows: Type of memory block Start End Work Scheme Common Memory # 6000 # C000 Stack Slow Memory # 6000 # 8000 Normal Fast Memory # 8000 # C000 Stack Upper Memory # C000 # 0 Normal After seeing the source code of the library, you see that these data are given in the labels, whose names are drawn by the principle: <Name of the block> _LOW <Name of the block> _HIGH <Name of the block> _STACK So if you're in their programs are usually using a different memory configuration - her best set directly in the code libraries than each time to use macros, memory settings. There is only one thing: when you change the default memory configuration You will also need to rewrite the macro DISPLAY_INFO because it is written with a view precisely the configuration that is specified. In Otherwise, I can not guarantee that it will work correctly. 2.3 Control over memory allocation. Mechanism for memory allocation would not very easy to use, if not It was also a mechanism for monitoring memory allocation. In Memory Management Library for this control corresponds to a macro DISPLAY_INFO. With it you can the following information: - The size of program code. - Volume loadable data. - The total size of the program. - The volume of the remaining free memory in Each block of memory. - (*) Reported variances Memory selection. - (*) Message about "climbing" selection memory for code or loadable data. - (*) Message about "climbing" the code or loadable data on the page. Last 3 points, marked with (*) work only in TASM'ovskoy version. This, as I said earlier, due to the lack in ALASM'e function DISPLAY. In addition, this macro may also be very entered into the STS address run the program, with so that when you exit the STS you do not need was manually set start address, before you start debugging the program. As you can see, this macro is fairly useful. However, its use requires a few simple rules to so that the macro could get the necessary for his information. I will bring the program scheme as it should be to the macro worked properly. Necessary for its of the lines highlighted in yellow. I use the syntax TASM'a, but ALASM'a is similar. . INCLUDE MEMORY START_ADR = # 8000; Address compile and run programs ORG START_ADR ; Here is the code END_OF_CODE = $ ; Here are loadable data END_OF_DATA = $ DISPLAY_INFO As you can see - for the macro you want task 3 variables: START_ADR - Address compile and run program. END_OF_CODE - End of code block your program. Starting with this location positioning data. END_OF_DATA - End of data block. In addition, the program must perform 2 more conditions: - Address the compilation of the program should be equal to at startup. For most programs, this is so. - Block loadable data should be Located directly behind the code block the program. This is also true for most programs. Necessary to explain what I mean The term "loadable data. These are data, which are usually loaded to the program. INCBIN, and after the launch programs are thrown LDIR'om its location in memory. For example, usually music, sprites or tables are located somewhere in memory (or pages), but they are usually are linked together with the code to form a candy bar, and then, after starting their being moved to the place where they should located. Here is the data block I call the "loadable data. The importance of their that they exist only at the stage run the program, and then this memory is can be used beneath something else. This specificity allows the library to, firstly, use this memory to allocate, and secondly, separately to control, that the allocated memory "crawls" on the data and prevent possible conflicts over use the same plot memory. Simply put, it is assumed that a block of memory from START_ADR END_OF_CODE to touch it a block from END_OF_CODE to END_OF_DATA can used for memory allocation, but if the allocated memory "crawl" in this unit - you need to issue a warning. There, the truth in all this one "but." Case that there is a difference in the macro DISPLAY_INFO in cases when a program uses specified in default memory allocation scheme, or also creates its own. Library controls changes in memory configuration, and prohibits Some macro functions DISPLAY_INFO. If you use your own scheme memory allocation will not the following functions: - Automatic adjustment of the block size Fast Memory, so that it occupied the entire memory from the last byte of code to # C000. - Control of "climbing" memory blocks, identified in the Fast Memory for loadable data. In addition to its main function - control for memory overflow, DISPLAY_INFO More has a number of additional functions. 1) It may help if you are already write and debug a program and want to save to disk the code. In such ALASM'e feature, but it TASM'e works only if the program Only one ORG'a, so usually the code remains of the STS. And for this necessary know two things: start block address codes and the size of the block. That's where you and useful macro DISPLAY_INFO. In Memory Management Library is defined Tag FINAL_RELEASE. I usually use it in their programs in order to remove debug code when compiling the final Release program. Ie debug code in program is written as follows: . IF FINAL_RELEASE-NO , Where a piece of debugging code . ENDIF And at the very beginning of the program (usually in the main file) contains the following design (in TASM'a syntax): . IF [# 5C08] - # 0E FINAL_RELEASE = YES . ENDIF Normally when you compile a debug version this label is not overridden (its value The default is NO), and when necessary compile the final version of the code, when you compile just a key is pressed EXT.MODE - and without editing source code I get the program without debugging code. Well, except for this tag library also identifies and tags SAVE_START SAVE_END. If you use them the following as follows: SAVE_START = $ ; This block of code that must be ; Paged to disk. SAVE_END = $ then compile the final release of your program, but all other information will be displayed on the screen (for TASM'a) or simply defined (for ALASM'a) tags: SAVE_START - block address for the record. SAVE_SIZE_ - the size of the block. Going out into the STS, you can safely write you needed a code block to disk. Incidentally, the default (if these labels are not override) will be automatically installed in the following values: SAVE_START = START_ADR SAVE_SIZE_ = END_OF_DATA So in most cases you will receive information about anything without worrying. 2) Macro DISPLAY_INFO can "patch" STS in order to exit in her address PC was equal at program startup. To use this feature, set the variable STS_BANK page number where you lie STS, example STS_BANK = # 17. If Yet this feature is not needed - do not do nothing, by default, no patches, no produced. 3) This feature is only TASM'ovskoy version of the library. Typically, programs that use the page memory, should be placed below # C000, that there were no glitches in the event that will Included is not the page. The same applies to loadable data - if they "zalezut in Page memory, they will not so just throw in another page. All these things are automatically tracked Code libraries, and if something all also "climbed" on this page - will be issued a warning. If your program, for whatever reasons, do not requires such checks - you can just variable set CODE_ON_PAGES = YES, and these checks will be disabled. Members ALASM'a such a possibility denied, again because of the lack of ALASM function DISPLAY. And another thing. As a general rule for a block of memory located directly at the code program, we can not say in advance - what be its boundary as the size of a block of code known beforehand. Here you can help one fact that direct control over memory overflow in the allocation will be carried out only when calling the macro DISPLAY_INFO, ie at the very end. Therefore, for the unit, located directly for the program code is best to ask clearly only the upper limit and lower You can ask anything you like. In addition, it is necessary ask for this block distribution scheme memory on the basis of the stack (to code and allocated memory moving towards each other). Select all necessary components as usually, at the very end of the program, add one single line (for example, the FAST block): FAST_LOW = END_OF_CODE Thus You just set the block size all available memory. You can also make and with any other memory unit - control memory overflow will work correctly. 2.4 Examples Let me give a couple examples of memory allocation in blocks with a normal stack, and schemes of work. Let me remind you that the unit is located on the Slow Address # 6000 - # 8000 and works with the normal scheme, and the block located at the addresses Fast # 8000 - # C000 and allocates memory on the principle of stack. GET_SLOW_MEMORY TABLE_1, # A0 GET_SLOW_MEMORY TABLE_2, # 120 GET_SLOW_MEM_XX00 TABLE_3, # 200 In the standard memory configuration these Challenges lead to the following results: TABLE_1 EQU # 6000 TABLE_2 EQU # 60A0 TABLE_3 EQU # 6200; And no # 61C0!!! Similar memory allocation for FAST memory: GET_FAST_MEMORY TABLE_1, # A0 GET_FAST_MEMORY TABLE_2, # 120 GET_FAST_MEM_XX00 TABLE_3, # 200 Give the following results: TABLE_1 EQU # BF60 TABLE_2 EQU # BE40 TABLE_3 EQU # BC00; And no # BC40!!! I hope that everything here is simple and clear. 3. Calculation of the screen address Macros in this group should facilitate the solution of the encoder, which he faces almost every one of its program. I'm talking about per-screen addresses. It's no secret that because of sufficiently "original" screen structure Speccy problem of calculating the display address by coordinates is not trivial and not every coder can be carried out rapidly this conversion in mind. Ask the same screen addresses in the programs have sufficient frequently, and in different versions - both in a table, and as EQU. On all of these cases in Memory Management Library has its own macros. All they are doing same, the difference lies only in where to put the result. Macro names are composed of the following principle: _x_SCRADR - calculation screen addresses _x_ATTRADR - the calculation of addresses in the attributes Here, x can have two values: GET and DEFW. Depending on the level varies set of parameters for the macro: _GET_SCRADR <Label>, <X koord.>, <Y koord.> _DEFW_SCRADR <X Koordinata>, <Y koordinata> In this case, after calling the macro _GET_SCRADR label passed as a parameter, will be set to display the address. Macros _DEFW_SCRADR screen address will be placed in memory at the current at compile time. Macro call format to calculate the addresses of the attributes is similar. The X and Y coordinates depend on that is calculated: the address on the screen or in attributes. To calculate the on-screen address X given in familiarity, and Y - in pixels. For the calculation of addresses in the attributes X and Y are given in familiarity. Using macros is extremely simple: _GET_SCRADR SCREEN_ADR, 5,9; Result: SCREEN_ADR = # 4125 _GET_ATTRADR ATTR_ADR, 5,9; Result: ATTR_ADR = # 5925 Or an example of compiling a table display Address: _DEFW_SCRADR 0,0 _DEFW_SCRADR 0,1 _DEFW_SCRADR 0,2 ... _DEFW_SCRADR 0,191 In addition, there is another set of macros performs the same function, but screen located at the address # C000. Their names drawn on the same principle, but with by adding at the end of the letter 'H' (on High): _GET_SCRADRH _GET_ATTRADRH _DEFW_SCRADRH _DEFW_ATTRADRH Initially, TASM'ovskoy versions of these Macro was not. I could simply ask additional parameter in macro call to calculate the address for the lower screen - and calculation would be produced for the screen with the address # C000. For example: _DEFW_SCRADR 10,8; Meaning # 402A _DEFW_SCRADR 10,8,1; Meaning # C02A It's much more convenient, but, unfortunately, Unlike TASM'a, ALASM does not support macros with variable number of parameters (Although KVA / E-Mage and said that he did everything "One to one in TASM'e). Therefore, from For compatibility reasons, had to do 4 more macro. 4. Creating a table of pointers and data structures This group of macros designed for solutions of two types of tasks listed in header. Indeed, virtually each program, there are several tables pointers or data structures. They are usually define as a heap of numbers, which then, usually difficult to correct. This a set of macros to help you cope with that the best way. Total this section there are 3 macro differing only in where and how as a result of fit: _SZ <Label>,_SZ_DEFB _SZ_DEFW It is clear that macro _SZ assigns a new value label, and macros and _SZ_DEFB _SZ_DEFW Placed in memory, respectively byte and word. All these macros are used for their of the same variable (___ORG), which is a pointer to the current values. Therefore, before each new using any of the macros that group, you will need to re- initialize this variable to the new current value. And, naturally, in avoidance of doubt, not be confused calls different macros of this group without re-initialize the variable. I will try to show you, how use these macros. I will give you a couple of examples give the same result: a option in the standard syntax, and other using these macros. Example 1. Create a table of pointers to sprites. SPRITES - a pointer to a set of Sprites, SPR_SZ - the size of a sprite. Standard syntax: SPRITES_TABLE DEFW SPRITES + (0 * SPR_SZ) DEFW SPRITES + (1 * SPR_SZ) ... DEFW SPRITES + (2 * SPR_SZ) With the use of macros: ___ORG = SPRITES SPRITES_TABLE _SZ_DEFW SPR_SZ _SZ_DEFW SPR_SZ ... _SZ_DEFW SPR_SZ Notice how much easier will then if necessary, to change something in this table, insert or remove from it elements. Example 2. Quest EQUS for structure fields data. Let the data structure is as follows: STRUCTURE DEFB 0; BYTE_FIELD_1 DEFB 0; BYTE_FIELD_2 DEFW 0; WORD_FIELD_1 DEFB 0; BYTE_FIELD_3 DEFS 10,0; TABLE_FIELD_1 DEFS 25,0; TABLE_FIELD_2 DEFW 0; WORD_FIELD_2 Quest EQUS for fields of this structure data in a standard syntax: BYTE_FIELD_1 EQU 0 BYTE_FIELD_2 EQU BYTE_FIELD_1 +1 WORD_FIELD_1 EQU BYTE_FIELD_2 +1 BYTE_FIELD_3 EQU WORD_FIELD_1 +2 TABLE_FIELD_1 EQU BYTE_FIELD_3 +1 TABLE_FIELD_2 EQU TABLE_FIELD_1 +10 WORD_FIELD_2 EQU TABLE_FIELD_2 +25 Notice how uncomfortable would be something change in the structure of data, particularly if something should be added in the middle or remove. And now the same thing, but using Macro: ___ORG = 0 _SZ BYTE_FIELD_1, a _SZ BYTE_FIELD_2, a _SZ WORD_FIELD_1, 2 _SZ BYTE_FIELD_3, a _SZ TABLE_FIELD_1, 1910 _SZ TABLE_FIELD_2, 1925 _SZ WORD_FIELD_2, 2 Compare the clarity and convenience of the job! But nothing of the convenience you can edit simply silent:) I think that these examples show for themselves. 5. Conclusion That's all. It is ridiculous, of course, that the description of a library with a volume of order 400 lines of assembler takes almost 30Kb text, but it says only that features of the library, despite the small size, really big (well or that I can not summarize their thought:)). I very much hope that the library will help you in your work. Of course, with the first glance it may seem somewhat unusual, but trust me - she actually very easy job! Happy coding!
Other articles:
Similar articles:
В этот день... 21 November