|
DMA
Disclaimer
Direct Memory Access is a very dangerous thing, when used improperly. That is why there is not much information regarding it. Please read and reread this entire article before actually using any of the information presented here. Misuse of this information can result in permanent damage to your computer. Neither I, nor anyone else associated with the presentation of this article can be held responsible for any damage that occurs to your system through use or misuse of the information presented here. USE AT YOUR OWN RISK!!!
What is Direct Memory Access?
The first question I'm sure your asking yourself is this: "What the hell is Direct Memory Access, anyway?" The answer to that question is relatively simple, if you understand a couple things about the way that computers store temporary data, also, knowing this will make using Direct Memory Access (DMA) easier to understand.
Temporary Data is stored in the computer's Random Access Memory (RAM). You can think of RAM as a large drawer in a filing cabinet. Each folder is assigned a number by the computer, and the folders are placed in sequential order (i.e. folder number 3 comes after folder number 2 and before folder number 4), so that the computer knows where to look in the drawer to find that particular folder.
Now, each folder is large enough to hold one byte of data. A byte is large enough to hold 8 binary digits, or bits, (that's enough to provide 256 combinations of 1's and 0's, and thus it can hold numbers 0-255). As you can tell, that's not a lot of data per folder, so, more often than not, the computer uses more than one folder to store information. It's not important to know how the computer does this, but what is important, is to know that the computer uses adjacent folders (i.e. folders 3 & 4 or 12555 & 12556 or all the folders between 1566486 and 156650) to store larger information.
Another important thing to remember is that by using two folders (16 bits) does not provide space to hold up to the number 510, but rather it provides 16 binary digits to work with, and thus 65536 possible combinations. So, for a quick review, one byte can hold the numbers 0-255, while two bytes can hold the numbers 0-65565, and four bytes (32 bits) can hold the numbers 0-4,294,967,296. One thing to keep in mind with Verge, is that it uses Signed integers, meaning that, while there are 256 possibilities, that includes both positive and negative numbers giving you these actual ranges:
One Byte : -128 to 127
Two Bytes : -32768 to 32767
Four Bytes: -2147483648 to 2147483647
So, why didn't I tell you three bytes? Because with VC you can work with either sets of one byte, two bytes, or four bytes (we'll get to that later, though)
What good is it?
Well, one of the best examples I can think of is Save/Load functions. You can find a set of Save/Load functions I wrote. Another noted example is Kisai's PCX ScreenShot script.
How you and your computer think
Now that you understand the fundamentals about how a computer stores data, we can go back to the original question of what DMA is. DMA is getting down and dirty with your computers RAM and working with data directly.
Here's an example of how your used to working with data in VC:
int x;
x = 100;
x = 1000;
Here's what your thinking when you write that:
int x;
// I need a number that I can call by typing 'x'
x = 100;
// Okay, tell the computer what number I want
x = 1000;
// Now, I need 'x' to be bigger
Here's what your computer is thinking when you write that:
int x;
// Okay, need to store a number so let's get ready
// to find enough space for it. Also let's make sure
// that we record somewhere in the RAM that the user
// wants to use 'x' to find it.
x = 100;
// Okay, they want to store a number that's under 255
// so we only need to allocate one folder for it.
// Now, let's write that value and make sure that we
// record the folder number it's in so that we can
// associate it with 'x' for them.
x = 1000;
// Now, they want to change the number, so let's go
// to our lookup table and find where we put 'x'.
// Now that we know where x is it turns out that we
// need more than one folder to hold that number since
// it's between 255 and 65535, fortunately the next
// folder is empty so we don't have any problem with it.
Now that's all pretty simple, isn't it? Well, it gets a little more complex when your dealing with numbers that are larger than 255 because the folder that is associated with 'x' is only the first one. This is an important fact to keep in mind when you start to actually work with the memory directly.
Tools of the trade
There is one function and three quasi-functions (which act as both functions and variables) that you will need to use in order to work with your computers memory directly, through VC. The function is:
int malloc(int amount);
And the three quasi-functions are:
(int) Byte[ptr]
(int) Word[ptr]
(int) Quad[ptr]
Memory Allocation
Let's take a closer look at one of the most important functions in DMA, malloc. malloc stands for Memory Allocate and that's just what it does. You enter how many bytes of space you want to reserve for later use. The function then returns the address of the first byte (i.e. the number of the first folder) Because this number is EXTREMELY important, you need to declare an integer to hold it. You'll use this number a lot when using DMA. For the following example, the integer 'buffer' will hold the address of the first folder of the allocated memory 'block'
int buffer;
buffer = malloc(10);
Basically, what that accomplished was to reserve 10 bytes of space in your RAM and put the address of the first byte into the variable 'buffer'.
 The "Quasi-Functions": Reading From Them
Now, as far as the quasi-functions go, let's first look at retrieving data using them. This is very simple. All you need to do is declare an integer variable and get the data using the following syntax:
int x, ptr;
x = byte[ptr];
The "Quasi-Functions": Writing To Them
Get it? Got it? Good. Now for the fun part. Writing data. In order to better demonstrate how this is accomplished, we'll simply build on the previous example:
int buffer;
buffer = malloc(10);
byte[buffer] = 20;
word[buffer + 1] = 15662;
quad[buffer + 3] = 1222333554;
byte[buffer + 7] = 0;
This example uses the variable aspect of those three functions to assign values to specific bytes of the memory allocated with malloc. Now would be a good time to take a look at what those three keywords (byte, word and quad) refer to. Byte, as I'm sure you guessed, is used to access one byte of memory. Word is used for two bytes, and quad is used for four.
Now, your probably curious about how 'buffer' was used to specify which byte to change the data in. Well, using the folder analogy, if buffer hold the number 100 as the first folder, to access the second folder (which is number 101) you can say 100 + 1. You have to do it this way since every time you execute malloc(10) a different address is returned. Since you have no way of knowing where the first folder will be located you just tell the computer, "I want this placed in the second folder, so look in 'buffer' to find the address of the first folder and go to the one after it (i.e. buffer + 1)"
Now, that's all fine and dandy as long as your just using bytes, but once you start using words and quads, you need to be a little more careful. For instance, in the above example, you'd need to use 'word[buffer + 1]' since the first folder (buffer) already has something in it. The same goes with 'quad[buffer + 3]'. Since a word takes up two bytes, you'd need to start the quad two bytes away from where you started the word. In the above example, the byte takes up the first folder and the word takes up the second and third folders so we need to start the quad (which takes up four folders) in the fourth folder. The easiest way to find what you need to add to 'buffer' in order to find the next empty byte is just add up everything you've put in so far. In the above example, to find what you'd need to add to buffer to find the next open byte for the second byte command, you can just add 1 (since the first byte takes up one byte), 2 (since the word takes up two) and 4 (since a quad takes up four) to get 7 (1 + 2 + 4 = 7) so you need to use 'buffer + 7' to get to the next open byte. Now, let's say that you want to add a third byte after the second, you'd use 'buffer + 8' (1 + 2 + 4 + 1 = 8).
One thing you have to be VERY careful about is exceeding the memory allocated with malloc. You can go up to buffer plus the number of bytes you allocated minus 1. In the above example, you must be very careful not to go above buffer + 9. You also need to keep in mind the size of the byte, word or quad your using. For instance, if you cannot exceed 'buffer + 9', then the highest 'ptr' value you can use for a quad is 'buffer + 5' (your maximum, 9 - 4, the size of a quad = 5, the highest 'ptr' value). So, you ask yourself, what happens if I go over the value. Well, you could very easily write over some important bit of information that belongs to another program, or even your OS. If your lucky, it won't be occupied and you are saved, this time. If you write over something, at best that program crashes, at worst your computer becomes a paperweight. In other words, NEVER EVER EXCEED YOUR LIMIT! If you need more space, then just allocate more memory with the malloc. Always double and triple check everything before you run any code that uses DMA.
Permanent Storage
Now, that's all fine and dandy if you only need to temporarily store information. But what if you want to save that data for later use? Now that you know how to write data to your computers RAM, let's take a look at how to actually save this information to your computers hard disk. Fortunately, VC makes this very simple by having a built in function called fwrite. The basic syntax is:
void fwrite(int ptr, int length, int filehandle);
If we wanted to save the information from the previous example, we'd simply type the following:
int file;
file = fwopen("data.xyz");
fwrite(buffer, 10, file);
 Cleaning Up
Now that you know how to read from and write to the RAM as well as save that information to your hard disk, all that's left is to clean up the little mess you left, before you end your script. The two functions you used, malloc and fwopen, each have a counter-function to free up the memory when your done with it. These counter-functions are:
void free(int pointer); (opposite of malloc)
void fwclose(int filehandle); (opposite of fwopen)
It's very important NOT to forget to free the memory you allocate with malloc. Until you free() the memory, your computer can't use it, and you may soon run out of memory, if your not careful. So now we can add those last few lines of code to our example and our final code looks like this:
int buffer, file;
buffer = malloc(10);
byte[buffer] = 20;
word[buffer + 1] = 15662;
quad[buffer + 3] = 1222333554;
byte[buffer + 7] = 0;
file = fwopen("data.xyz");
fwrite(buffer, 10, file);
fwclose(file);
free(buffer);
I hope you have fun with DMA. It's a wonderful and powerful tool, when used correctly. When the power is abused, the consequences are grave, so whatever you do, BE CAREFUL. Enjoy!
|