Chapter 14 MACHINE DEPENDENT FACILITIES PREREQUISITES FOR THIS MATERIAL ______________________________________________________________ Before attempting to study this material, you should understand the material presented in Part I of this tutorial and have a clear understanding of the material on pointers in Part II. THIS IS WHERE YOU CAN GET INTO TROUBLE ______________________________________________________________ Modula-2 does a good job of insulating you from the underlying peculiarities of your computer due to the strong type checking which it does. It can prevent you from making many kinds of rather stupid blunders simply by forcing you to follow its predefined conventions. There are times, however, when you wish to ignore some of its help and do something that is out of the ordinary. If you had a need to directly interface with some external device, you would need to get down to the nitty gritty of the operating system and do some things that are outside of the realm of normal programming practice. The principles taught in this chapter can lead you directly into the operating system where you will have more freedom than you would have thought possible with Modula-2, but it will place more responsibility on you. This material is only for the advanced programmer because it will require a knowledge of the inner workings of the computer and the operating system. Nevertheless, it would be good for you, as a student of Modula-2, to at least read this material, study the example programs, and compile and run them. You will then have a store of knowledge of these things so that you can use them when you need them. TYPE RELAXATION EXAMPLE ______________________________________________________________ Examine the program named TYPEREL.MOD for =============== an example of a program with some very TYPEREL.MOD unusual type transfer functions. Note =============== first that three types are defined, each being the same size considering storage requirements. The first type is 10 integers, the second is 10 cardinals, and the third is 20 char variables which requires the same amount of storage as 10 integers or cardinals on most microcomputers. If you are using a larger computer, you may need to adjust 14-1 Chapter 14 - Machine Dependent Facilities some of these to make them the same size. The fact that all three types are the same size is very important for what we will do later in the program. We begin the program part of the module by assigning the value 10 to the variable Count, a cardinal type variable. In the next line we assign the value of Count to Index even though they are of different types because we transform the type in the same manner that we did back in Chapter 3 when we studied the program named TRANSFER.MOD. Actually, we don't need the type transformation here because integer and cardinal are assignment compatible. We load up the integer array named IntVars with some nonsense data to work with, the data being the series of numbers from 65 to 74, which should be easy for you to ascertain. Then in line 23, we copy one of the array data points to one of the other to illustrate that the type transformation works even on array elements. NOW FOR THE BIG TYPE TRANSFORMATION ______________________________________________________________ In line 24 of the program we copy the entire field of 10 integer type variables into the array of 10 cardinal type variables. The only restriction is that both of the fields must be exactly the same size which these two are. In order to do the transformation, the type of the resulting data area is used in front of the parentheses of the source variables. Line 25 goes a step farther and copies the new cardinal data into 20 char type variables, which is permissible because 20 char variables uses the same amount of storage as 10 cardinal variables. You could even transform a record made up of several different types into all char variables, or all integers, or even another completely different record. The only requirement is that both of the groups be exactly the same size. This may appear to be a really neat thing to be able to do but there are problems that you will find with this new transformation. There are no data conversions done, only type conversions where the data is copied byte for byte with no concern for the meaning of each byte, which means that you may wind up with a real mess trying to decipher just what the transformed data means. This is called type coercion and is simply a byte for byte copy with no concern for the meaning of each bit in the data pattern. In addition, since each compiler may define the various types of data slightly different, your program will not be easily transportable to another computer, or maybe not even to another Modula-2 compiler on the same computer. 14-2 Chapter 14 - Machine Dependent Facilities Five of the cardinal numbers are displayed on the monitor, then 10 of the char numbers are displayed to show you that they really are the same numbers. The order of the numbers may be reversed when output as individual bytes because of the way the data is stored in the microprocessor in your computer. This in itself is an indication that there is no data conversion, but only a data copying, byte by byte. One other rule must be pointed out, you cannot do a data transformation within a function call, but it is simple enough to do the transformation to a dummy variable and use the dummy variable in the function call if that is necessary. This will be illustrated shortly. Compile and run this program after you study it. WORD AND ADDRESS VARIABLES ______________________________________________________________ Examine the program named WORDADDR.MOD for ================ an example using some new data types. In WORDADDR.MOD order to get down to the lowest level of ================ the machine, we need these new types, ADR, WORD, and ADDRESS, which must be imported from the pseudo module SYSTEM. The pseudo module SYSTEM does not exist as an external module as the others do because the kinds of things it does are closely associated with the compiler itself. The designers of Modula-2 have therefore defined this module to make these things available to us, and we import them just as if the pseudo module SYSTEM existed as a regular library module. The new data type WORD is compatible with all data types that use a single word for storage, but it is somewhat limited in what you can do with it. It is most useful as the formal argument to a function which can be called with any data type that is contained in one word. In lines 27 and 28, the same procedure is called, once with an integer type variable, and once with a cardinal type variable. Since the procedure is designed to handle either, it will print out both numbers by converting them first to cardinal using the type transformation in line 17, then calling the output procedures. Once again, the type transformation cannot be done in the procedure call so a temporary variable is used. A NEW KIND OF POINTER ______________________________________________________________ The variable Peach is assigned the type ADDRESS which is also imported from the pseudo module SYSTEM, and is therefore a pointer to any word type of variable. Peach can therefore 14-3 Chapter 14 - Machine Dependent Facilities point to an integer or a cardinal as is done in lines 25 and 26. The procedure ADR returns the address of any word type of variable and it too must be imported from the pseudo module SYSTEM. ABSOLUTE ADDRESSES ______________________________________________________________ Notice the two strange looking variables in lines 10 and 11. The variable MonoVideo is an array of 4000 char type variables, but we have forced it to be located at a very specific location in memory, namely at segment=B000(hex) and offset=0000(hex). This is the method provided for you by Modula-2, by which you can force a variable to be at a specific memory location. In this case we have defined the variable to be stored in the locations in memory where the monochrome monitor display is stored so we can store data directly into the monochrome monitor display area if we are using an IBM-PC or compatible running MS-DOS. The variable ColorVideo is the same except that the location referenced is that area where the output for a color monitor is stored on an IBM PC or compatible. It should be apparent that you can gain control over the actual hardware with this capability but it does require a lot of knowledge of the hardware and the operating system. In the last line of the program the variable Peach is assigned the address of a specific location as an illustration only. This is only possible because Peach is a variable of type address. Your computer and compiler may use an entirely different method of address specification than that illustrated here. It will be up to you to study your documentation for the details of your particular system. It should be clear to you that with these functions, it is possible to do a lot of data shuffling that could not otherwise be done. The next example program will illustrate their use further. MORE ADDRESSING EXAMPLES ______________________________________________________________ Examine the program named ADRSTUFF.MOD. ================ This program uses the address type and ADRSTUFF.MOD adds two new, rather simple functions, ================ SIZE and TSIZE. Actually, these are not completely new since we used the TSIZE function in the chapter on pointers and dynamic allocation. These two functions will return the size in bytes of any variable or of any type. The program on your monitor has several types defined, then 14-4 Chapter 14 - Machine Dependent Facilities several variables, and finally initializes all of the elements of the array Stuff to some nonsense data. The really interesting things begin happening at line 25. The pointer NeatPoint is pointed at the first element of the array Stuff, and its value is dereferenced into Index. The type transformation is required because the result of the dereferencing is a cardinal type value. The data is written out to the monitor. Next the size of the type IntArray is assigned to the variable IncreAmt, which should be 8 words or 16 bytes, but may be different with you computer ans compiler. In line 29 we do some pointer arithmetic by adding the size of the type IntArray to the original value of the pointer which should cause it to point to the next row of the array. After dereferencing the pointer and getting its new value, we print it out to find that it did indeed move to the next row of the array. Based on the above discussion, it should be apparent to you that you can move the pointer all around the array named Stuff and get whatever data you wish. The next section of the program uses a loop to continue the process through all five rows. The only thing that may be confusing is line number 34 where we get the size of the BigArray type and divide it by the size of the IntArray type. The result should be 5, and you will see that it does five iterations through the loop. This is really a dumb way to get through this particular loop but it is only for purposes of illustration that it is done. Notice all of the type transformations to integer in these statements, this is because the functions all return a cardinal type of data. Doing all of this in cardinal numbers would have made it much cleaner, but this was more illustrative for you. TWO MORE LINES OF ILLUSTRATION ______________________________________________________________ Lines 42 and 43 are given as an illustration for you of how to use the SIZE function. It simply returns the size, in bytes, of any variable used as an argument. Even though we went to a lot of trouble to illustrate and explain the pointer operations in the last program, you should be discouraged from using this technique for software development. In this case, you should use the usual method of working your way through the array rather than through use of this confusing and obscure method of using pointer arithmetic. You will find places where pointer arithmetic can be used to great advantage, but until then, you should favor the use of the clear and easy to understand constructs available in Modula-2. 14-5 Chapter 14 - Machine Dependent Facilities PROGRAMMING EXERCISES ______________________________________________________________ 1. Modify ADRSTUFF.MOD to print out some of the type and variable sizes such as those calculated in lines 41 and 42. 2. Write a program with an array of 100 CARDINAL elements, fill the elements with nonsense data, and use a pointer to print out every 12th value starting at the highest element (number 100) and working downward. 14-6