Feb 10, 2011

Assembly macro - Some useful stuffs

Hello :)

After running through the nuisance of printing output and debugging, I have came up with these macro. It might be useful for you somehow :)

All bug free :) I hope the code is self-explained. But if there are any errors or things you want to add, please leave a comments :)

    ;useful macro call
    ;make new line: printChar 10 printChar 13
    ;add a break point in your code that stop TurboDebugger when you hit F9: addBreakPoint

    addBreakPoint macro
        ;save register
        push AX
  
        pushf                                                        ;AX=PSW
        pop AX                                                   ;
       
        or AX,0100h                                           ;set 8th bit (trap flag)
       
        push AX                                                  ;PSW=AX
        popf                                                         ;
       
        ;restore register
        pop AX
    endm

    printChar macro    character                        ;print a character
    ;save register
        push DX
        push AX
                   
        mov DL, character                                    ;
        mov AH, 02h                                    ;
        int 21h                                        ;
       
        ;restore register
        pop AX
        pop DX
    endm
   
    printMsg macro msgString                        ;print a message
        ;save register
        push DX
        push AX
                                   
        mov DX, offset msgString                    ;print q1_1 string
        mov AH, 09h                                    ;
        int 21h                                        ;           
       
        ;restore register
        pop AX
        pop DX
    endm
Some quick thing to note:
  • I tried doing CMP with 8-bit register and use the "less than" jump command, but it does not turn out as expected. Instead, JL only works when CMP is called for 2 16-bit register.

Feb 8, 2011

Printing integer with assembly

Assembly is really a trouble some language when it comes to performing "thought-to-be-simple" task. Printing an integer is an example.

Having completed the code for that, I hope posting it here will help those who are looking for away to do it :)
The code is not optimized, nevertheless, so you should use it as a reference only.

I made use of the 21, 9 interrupt, which prints a string delimited by the '$' to the screen.


;count the number of digit of a 1-byte integer
;number stored in AX (AL actually, since it's 1-byte)
;count value stored in CX

;convert the number into a string and print out

myStackSeg segment stack      
                    db 128 dup (?)                    ;space for stack
    tos                label word                        ;top of stack
myStackSeg ends


myDataSeg segment  
    _dec_10 db 10                                    ;declare decimal value 10
    intStr    db 4 dup(?)                                ;1-byte integer -> 3 digit max -> 4 space (1 for '$')
    myNumber equ 176
    _eos db '$'
myDataSeg ends


myCodeSeg segment
assume CS:myCodeSeg, DS:myDataSeg, SS: myStackSeg

start:
    ;initialize segment register
    mov    AX,    seg myDataSeg                            ;
    mov    DS,    AX                                        ;initialize DS
    mov AX, seg myStackSeg                            ;
    mov SS, AX                                        ;
    mov SP, offset tos                                ;initialize SS

  
    ;convert the digits into string
    mov DX, myNumber
    mov BX, offset intStr
  
    ;count the number of digit of a number in AX      
    mov AX, DX                                        ;AX store the number
    xor CX, CX                                        ;clear CX
    jmp countDigit                                    ;start counting
  
    nextDigit:                                        ;still got digit remain
        mov AH, 00h                                    ;clear remainder
        jmp countDigit                                ;count again
  
    countDigit:                                        ;count and div 10
        div _dec_10                                    ;div 10; AL=remainder, AH=div result
        inc CX                                        ;at least 1 digit      
        cmp AL, 0                                    ;if (div result)!=0
        jne nextDigit                                ;prepare to count again

    ;CX hold no of digit
    mov DL, CL                                        ;
    add DL, 48                                        ;convert to corresponding ASCII character
    mov AH, 02h                                        ;print character to screen
    int 21h                                            ;
  
    mov DI, BX                                        ;DI=@intPtr (array storing the characters to print)
    add DI, CX                                        ;move DI to end of string (eos)
    mov AH, _eos                                    ;copy the string delimiter '$'
    mov [DI], AH                                    ;to then end of string
    mov AX, myNumber                                ;AX=number to print
    ;jmp convertDigit                                ;start printing
  
    convertDigit:
        div _dec_10                                    ;div 10 AX
        add  AH, 48                                    ;AH=AX mod 10. convert it to ASCII character
        mov [DI], AH                                ;copy the character to its position in the output str
        mov AH, 00h                                    ;clear the character -> AX=AX div 10
        dec DI                                        ;move back 1 space in the output str
        loop convertDigit                            ;loop till all digits are converted
      
    mov DX, BX                                        ;print the converted string
    mov AH, 09h                                        ;
    int 21h                                            ;
  
exit:
    mov AH, 4Ch                                        ;exit
    int 21h                                            ;
myCodeSeg ends
end start

Jan 17, 2011

Assembly language for Intel 8086 - The intro

To many of us (especially those who studies CG2007 and haven't touched assembly language before, like myself 3 hours ago), the word "assembly" might be a bit scary. As we all know, it's one of the language that is most closed to machine code (which is not readable, if you are human =.=" ) and hence, one of the hardest to learn, understand and code.

It took me a while to get my first Assembly program running, as well as numerous search on Google. books and help file. And in the end, all I did was just outputting some text to the screen.

However, I would like to sum up all the steps here, for all those who haven't tried to get a better start.
 
Not to delay any more, we are going to build our first assembly program, which is a "simple" Hello World program.

The assembler
First, you will need to get some tools. In CG2007, we are assigned to use the TurboASM to assemble the code. However, as far as I had look through the sample code, it's quite complicated (especially, if you 've just started to learn like me). Hence, found another assembler that might do the trick: the A86 macro assembler.

To start, we will download the assembler here and put on to one of your directories on your HDD.
Next, go to the DOS command prompt (Start menu - Programs - Accessories - Command Prompt) and move to the directory you have extracted the A86 compiler (H:\A86 for me).
 
Tips:
When you open the command prompt, it will look something like this:
C:\>
You will move to another directory with the "cd" command. Type:
cd H:\A86
and the result will look like
H:\A86>


So you are now ready to compile your program.

Coding assembly

Next, you need to code. At this point, coding with assembly might seem challenging, because the syntax is quite different from any other high-level language like C, C++, C#, Java, etc.
Typically, a command in Assembly will have 3 component (not always, as you will soon see)
[command] [operand1] [operand2]

The command will determine the type of action, operand1 and 2 are registers. Since we are coding for the Intel 8086 chip, which offers 4 general 16-bit register (AX, BX, CX, DX) or 8 8-bit registers split from those (AH, AL, BH, BL, CH, CL, DH, DL), we will only be able to use these names (For more information about register, you will need to read through my lecturer's note or an external guide that I will provide at the end of the post).

Next, you will need a text editor. Notepad of Notepad++ will do.

Now, enter the following line code. I hope it's self-explained:

;An assemble comment is denoted with a semi-colon at the beginning
;it extends till the end of the line

MOV AH,02
;notice that the command doesn't end with anything, and there are 3 components
;    with a comma between the second and the third

;MOV is the command to move data. AH and 02(number 02)
;The commands move the DATA from the SECOND operand to the FIRST.
;In this case, since 02 is data already, it will move the VALUE 02 to the register AH
;You can have ~MOV AH, BL~ (w/o the ~), which moves data from register BL to AH
;You can also have ~MOV CH, "A"~, which moves the LETTER A (ASCII value 65 or 41H) to CH
;Doing ~MOV 12, CL is not acceptable, as the first operand is the destination register
;    which can't be a value

;By moving the value 02 to AH, we call a subfunction to handle outputing a character
;    this character is stored in DL

MOV DL,"H"
;here, we store the "H" into DL. The program hasn't output anything at this point

INT 21h       
;Here, 21h means number 21 in hexadecimal
;INT is the command to call the interrupt. the number after it defines the iterrupt to call
;    in this case, it's a dos interrupt, which calls the subfunctions about
;    to display the character

MOV AH,04Ch   
;Again, we call a sub-function to exit the program

MOV AL,00
;AL will store the exit code

INT 21h
;call the DOS interrupt, executing the sub-function above and exit

As you can see, to call a functions, we don't use function names but rather very obscure number. Hence, it would help to have a list of functions and interrupt available for reference. You can look at some commonly used functions here.

Compile and assemble

Then, we need to compile our program. As your DOS command prompt is in the directory of the A86 already, save the code file there also (example: H:\A86\test1.asm).

Then, from the DOS command prompt, type
A86 test1.asm
(or replace the filename you have chosen)
The assembly source code will get assembled into a .COM file.
Then, in type this to execute it in the command prompt
test1

You should see a single character H on screen.

Things to note

In conclusion, you will need these three command to write a single ASCII letter:

MOV AH,02
;This is to select the display character sub-function. It must be loaded to AH
MOV DL,"H"
;copy the data to be used. refer to the documents to know which register to store it
INT 21h
;call the interrupts that handles the sub-function.

For your pratice, try writing out the rest of the "ello World!" text.


I hope this guide helps as the first and easy step to assembly. Be wary that if you are coding with TurboASM, it's really different. I am working hard to understand it, so perhaps we will have an another guide soon.

Sincerely yours,


This guide was based on reference from:
  • http://www.skynet.ie/~darkstar/assembler