What is assembler?
Learning the MOV operator.
Learn to call interrupts.
Learn to call the I/O ports.
Learn to read/write with memory addresses in 16 bit real mode.
Learn to read/write with memory addresses in 32 bit protected mode.
Linked registers.
Logical operators.
Assembler is a low generation programming language. It stands very close to machine code so you're actually telling the processor to do things. This course has been optimized for programming languages that support assembler-code such as: Pascal, C(++), and some BASIC compilers. When you have a standalone assembler you can learn some things from this page but I don't recommend that you use a standalone assembler, at least for now.
Note for C++ users: the character 'h' after a number indicates that it's an hexademical number. To use this in C++ use 0x13 in stead of 13h.
In assembler each line is called an instruction. In contains an operator and operands if
necessary. Now let's learn the MOV operator. It needs two operands. This is a very useful and
easy operator, and used very frequently. I recommend that you have a compiler or assembler at
hand so you can ALT-TAB to it when necessary.
This is the syntax: MOV dest, src
The yellow word is the operator, the two arguments are the operands. The value from src(source)
is placed in dest(destination). An example:
MOV VAR, 10.
What happens here is that the value 10 is placed in VAR. compare it with: VAR = 10 or VAR := 10 Now you can try it yourself. To open up an assembler block in some compilers you can use the ASM statement. You have to declare the variable first! Now that you have learned it let's call the registers in the story. You can compare registers with variables. They are automatically declared variables by the processor and there are many types. Look at the table below.
Register | Description |
AL, AH, BL, BH, CL, CH, DL, DH | 8bit (byte, unsigned char) |
AX, BX, CX, DX | 16bit (word, unsigned short) |
EAX, EBX, ECX, EDX | 32bit (longint, unsigned long) |
MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7 | 64bit (quadword) |
DI, SI | 16bit memory addressing |
EDI, ESI | 32bit memory addressing |
CS, DS, ES, SS | Segment selector |
FS, GS | 32bit segment selector |
SP | Stack pointer |
ESP | 32bit stack pointer |
IP | Instruction pointer |
EIP | 32bit instruction pointer |
BP | Base pointer |
EBP | 32bit base pointer |
AF, CF, OF, PF, SF, ZF | Flags (true or false) |
Now let's do 2 MOV instructions with a register. First declare a variable as word or unsigned short. Now look at this example:
MOV AX, 13 MOV VAR, AXThe value 13 is placed in the register AX. Then it is exported from AX to VAR. Now try it out yourself. Maybe you've got the guts to learn the next lesson.
Now we're actually going to do something! There are 3 ways to call the computer functions:
interrupts, I/O ports and I/O Memory addresses. We're going to learn the interrupts. The
interrupts are the power of assembler and have functions that your compiler doesn't have. The
mouse is a very good example of this. In almost every compiler there seems to be an absence of
calling the mouse. Here you're going to need the registers. If you don't know what I'm talking
about read the first lesson. The syntax is: INT intnr.
Nr is the number of the interrupt. We're going to study interrupt 10h (Video Services) and
interrupt 33h (Mouse routines). Almost each interrupt has sub-functions. Subfunction 0 of
interrupt 10h is setting the screenmode. Before calling an interrupt it expect certain
registers to be filled with data. Interrupt 10h expects the subfunction in AH. Subfunction 0
expects the screenmode in AX. An example:
MOV AH, 0 MOV AX, 19 INT 10hHere the subfunction 0 is in AH (setting the screenmode). Then AX is filled with the screenmode 19 (320x200 256 colors). Then INT 10h is called that reads those registers and does the job. You can try out to set different screenmodes as you like (0-19). Just fill AX with different numbers. Now we're going to put a pixel. This is subfunction Ch. It expects the X position in CX and the Y position in DX. Put the color value in AL. Value 15 is white. But you can try other colors as well. An example:
MOV AH, Ch MOV CX, 100 MOV DX, 100 MOV AL, 15 INT 10hHere the subfunction Ch is in AH (Write graphics pixel dot). Position [100,100] is filled in CX and DX and color 15 (white) is filled in AL. This function puts a white pixel at [100,100]. Now you can try and put pixels as you like. For setting the screenmode back to text fill AX with 3 (subfunction 0). An example:
MOV AH, 0 MOV AX, 3 INT 10hI hope you still understand this. Now let's go to interrupt 33h. Because we're using standard screenmodes this interrupt is easy to call. Let's put the mousecursor on. This is subfunction 1, but this interrupt expects the subfunction in AX. Remember that! Further it doesn't expect anything. An example:
MOV AX, 1 INT 33hThat's it! If you're in graphics you'll see the well-known arrow. In textmode you'll see a block. The mousedriver manages all the moving. Now let's turn it off. This is subfunction 2 and doesn't expect anything. An example:
MOV AX, 2 INT 33hNow it's turned off. Is this easy or what! Now you've learned to work with interrupt that does something. Let's learn to work with interrupts that returns values. In this case you still have to fill certain registers, but other registers are filled after calling the interrupt. A good example is checking if a mousedriver is present. This is subfunction 0. It returns a value in AX. If it is 0 there is no mousedriver. If it is 65535 there is a mousedriver. An example:
MOV AX, 0 INT 33h MOV VAR, AXHere AX is filled with subfunction 0. Then the interrupt fills AX with a value. But the value in AX is exported to a variable (declare it as word or unsigned short!). Now you've learned a lot of things and with this small knowledge you can do many things! If you want to learn more go to the next lesson.
MOV AH, 0 MOV AX, 13h INT 10hThe number 13h is the same as 19 but the first number is in HEX. At start the whole screen is filled with pixels of value 0 (black). The port we're going to use can give a colornumber a red, green and blue value. Then all pixels of that colornumber becomes that color. This is very fast and are called palette operations. First put the colornumber in port 3C8h. Then write the red, green and blue value in port 3C9h (write 3 times!). Let's make colornumber 0 and the screen red. An example:
MOV DX, 3C8h MOV AL, 0 OUT DX, AL MOV DX, 3C9h MOV AL, 63 OUT DX, AL MOV AL, 0 OUT DX, AL OUT DX, ALFirst put the port in a 16 bit register. Then we're setting the colornumber to AL (8 bit register) That's 0. Then use the OUT instruction. Then we'll put a 63 value in AL and use the OUT instruction. Then put a 63 value in AL and use the OUT instruction 2 times. Only red must get a high value so we're writing the value 63 first. Then we're writing two ZERO values (green and blue). You can play with the palette as you like. Now let's read the red, green and blue value from a colornumber. Then you must send the colornumber to port 3C7h. Then READ 3 times from port 3C9h. An example:
MOV DX, 3C7h MOV AL, 0 OUT DX, AL MOV DX, 3C9h IN AL, DX MOV red, AL IN AL, DX MOV green, AL IN AL, DX MOV blue, ALAs you can see always put the port in a 16 bit register and the value in an 8 bit register. Now you see an IN instruction. Then the values are exported to the declared variables red, green and blue (byte). Now you have mastered the IN's and OUT's and the palette.
MOV ah, 0 MOV ax, 13h INT 10hThe videocard stores the colornumbers of each pixel in the videosegment. If you change the value of the first address the first pixel will change too. This is a table that show you how the pixels are stored:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 |
90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
MOV BX, A000h MOV ES, BX MOV DI, 0 MOV ES:[DI], 15You can't put a value in ES directly so we're using BX first. You can now plot pixels very fast. Don't change ES. Just change DI from 0 to 65535. If DI=16 you can increment the ES register and put 0 in DI. But many programmers don't do that.
MOV EDI, pointer MOV AL, 32 MOV [EDI], ALpointer is a declared pointer in your compiler. The address of the pointer is moved into EDI, and the value 32 is put in the first byte of the allocated memory. Try to write the first byte of your allocated memory to the screen. That's all about 32 bits memory addressing.
MOV AX, 0 MOV AL, 12 MOV VAR, AXVAR is a 16 bit variable. This is an advantage: You don't have to declare a 8 bit variable to get the 8 bit value from AL. This knowledge can be VERY useful.
MOV AH, 0 MOV AX, 13h INT 10hYou'll see that the first instruction line isn't needed because AH will be 0 when the value 13 is put into AX.
10011101 (1+4+8+16+128=157) 00001111 (1+2+4+8=15) -------- XOR 10010010 (2+16+128=146)When the bits are the same, the destination bit will be 0, else it will be 1. The result is stored in op1. All logical operators have the same syntax and store the result in op1. AND works like this:
10011101 (1+4+8+16+128=157) 00001111 (1+2+4+8=15) -------- AND 00001101 (1+4+8=13)When the bits are both 1, the result bit is set to 1, else it will be 0. OR works like this:
10011101 (1+4+8+16+128=157) 00001111 (1+2+4+8=15) -------- OR 10011111 (1+2+4+8+16+128=159)When the bits are both 0, the result bit is set to 0, else it will be 1. There is another logical operator NOT. This works different than the others.
10011010 (before calling not) 01100101 (after calling not)NOT toggles each bit and stores the result in op. Now that you've learned these let's optimize some code. An example:
MOV AX, 12 XOR AX, AX MOV VAR, AXTry filling AX with different numbers before XOR is called. Use VAR to let the compiler write the value in AX to the screen. Whatever you do, AX stays ZERO. Now what really happens:
00000000 00001100 (4+8=12 <-AX) 00000000 00001100 (4+8=12 <-AX) ----------------- XOR 00000000 00000000 (0 ->AX)Remember? When the bits are the same the result bit is 0. Now you've learned that when you are passing the same operands to XOR the result will always be ZERO. It's like MOV AX, 0. But why using XOR? If you remember: XOR is faster than MOV. This means that you can set registers faster to ZERO. This technique is used very often. Another technique: when you want to take the modulus of 32. This means that the maximum value will be 31. To do this you can mask out the other bits. An example to make it clear:
10110110 (2+4+16+32+128=182) 00011111 (1+2+4+8+16=31) -------- AND 00010110 (2+4+16=22)And if you take the remainder of 182/32 you'll see that it is 22, just like the answer. You can only do this trick on special binary numbers like 2,4,8,16,32 etc.
If you think something should be added or changed E-mail me at
[email protected]
Go to the top of this page