Turbo C User's Guide:
Embedded Assembly Language. Part I - Basic Principles

> BASM.DOC is on online file that tells you how to use the Turbo C++ built-in inline assembler (BASM) to include assembly language routines in your C and C++ programs without any need for a separate assembler. Such assembly language routines are called inline assembly, because they are compiled right along with your C routines, rather than being assembled separately, then linked together with modules produced by the C compiler.

> Turbo C++ lets you write assembly language code right inside your C and C++ programs. This is known as inline assembly and has certain restrictions.

> - It cannot use assembler macros
> - It cannot handle 80386 or 80486 instructions
> - It does not permit Ideal mode syntax
> - It allows only a limited set of assembler directives

> To invoke the in-line assembler, you need only use the keyword asm to introduce an inline assembly language instruction. The format is

> > asm opcode operands

> where opcode is a valid 80x86 instruction, and operands contains the operand(s) acceptable to the opcode, and can reference C constants, variables, and labels.

> To include a number of asm statements, surround them with braces: The initial brace must appear on the same line as the asm keyword.

> Semicolons are not used to start comments (as they are in TASM). When commenting asm statements, use C-style comments, like this:

> > asm mov ax,ds; /* This comment is OK */
> > asm {pop ax; pop ds; iret;} /* This is legal too */
> > asm push ds ;THIS COMMENT IS INVALID!!

> The assembly language portion of the statement is copied straight to the output, embedded in the assembly language that Turbo C++ is generating from your C or C++ instructions. Any C symbols are replaced with ap-propriate assembly language equivalents.

> Because the inline assembly facility is not a complete assembler, it may not accept some assembly language constructs. If this happens, Turbo C++ will issue an error message. You then have two choices. You can simplify your inline assembly language code so that the assembler will accept it, or you can use an external assembler such as TASM. However, TASM might not identi-fy the location of errors, since the original C source line number is lost.

> You can include any of the 80x86 instruction opcodes as Opcodes inline assembly statements. There are four classes of instructions allowed by the Turbo C++ compiler:

> - normal instructions--the regular 80x86 opcode set
> - string instructions--special string-handling codes
> - jump instructions--various jump opcodes
> - assembly directives--data allocation and definition

> Note that all operands are allowed by the compiler, even if they are erroneous or disallowed by the assembler. The exact format of the operands is not enforced by the compiler.

> Prefixes

> The following prefixes can be used:

> > lock rep repe repne repnz repz

> Jump Instructions

> Jump instructions are treated specially. Since a label cannot be included on the instruction itself, jumps must go to C labels. The allowed jump instructions are given in the next table.

>     	ja 	jge 	jnc 	jns 	loop

>     	jae 	jl 	jne 	jnz 	loope

>     	jb 	jle 	jng 	jo 	loopne

>     	jbe 	jmp 	jnge 	jp 	loopnz

>     	jc 	jna 	jnl 	jpe 	loopz

>     	jcxz 	jnae 	jnle 	jpo 	je

>     	jnb 	jno 	js 	jg 	jnbe

>     	jnp 	jz

> Assembly Directives

> The following assembly directives are allowed in Turbo C++ inline assembly statements:

>     	db 	dd 	dw 	extrn

> C Symbols

> You can use C symbols in your asm statements; Turbo C++ Inline assembly automatically converts them to appropriate assembly references to data language operands and appends underscores onto and functions identifier names. You can use any symbol, including automatic (local) variables, register variables, and function parameters.

> In general, you can use a C symbol in any position where an address operand would be legal. Of course, you can use a register variable wherever a register would be a legal operand. If the assembler encounters an identifier while parsing the operands of an inline assembly instruction, it searches for the identifier in the C symbol table. The names of the 80x86 registers are excluded from this search. Either uppercase or lowercase forms of the register names can be used.

> Inline Assembly and Register Variables

> Inline assembly code can freely use SI or DI as scratch registers. If you use SI or DI in inline assembly code, the compiler won't use these registers for register variables.

> When programming, you don't need to be concerned with the exact offsets of local variables. Simply using the name will include the correct offsets. However, it may be necessary to include appropriate WORD PTR, BYTE PTR, or other size overrides on assembly instruction. A DWORD PTR override is needed on LES or indirect far call instructions.

> Examples of Inline Assembly Language

> #### 1. Example of window scrolling routines with keyboard IO.

> >     #include <stdio.h>

> >     void screen( void );

> >     void scroll( void );

> >     void get_char( void );

> >     char char_in; // variable defs

> >     unsigned char row, col, row_up, row_down, col_up, col_down;

> >     void main()

> >     {

> >       row = 0;

> >       col = 0;

> >       row_up   = 3;    // define a 10 line by 40 col

> >       row_down = 13;   // window for scrolling

> >       col_up   = 20;

> >       col_down = 60;

> >       screen();        // erase the screen

> >       scroll();        // scroll the screen

> >       get_char();      // get char to terminate...

> >     }

> >     void screen()

> >     { asm{

> >           mov cx,50h     /* 80 interations */

> >     }

> >     disp_loop:

> >       asm{

> >           mov ah,02h     /* cursor position */

> >           mov bh,00h     /* BIOS call */

> >           mov dh,row

> >           and dh,0Fh     /* limit 32 lines */

> >           mov row,dh     /* restore row value */

> >           mov dl,col

> >           int 10h

> >           inc row        /* incr row,col ptrs */

> >           inc col

> >           mov ah,02h     /* DOS char output */

> >           mov dl,'x'     /* output the X char */

> >           int 21h

> >           loop disp_loop /* loop until done */

> >          }

> >     }

> >     // ............................................

> >     void scroll()

> >     { asm{

> >           mov ah,06h       /* BIOS scroll function */

> >           mov al,10h       /* 16 lines */

> >           mov bh,00h

> >           mov ch,row_up    /* set window limits */

> >           mov cl,col_up

> >           mov dh,row_down

> >           mov dl,col_down

> >           int 10h

> >          }

> >     }

> >     // ............................................

> >     void get_char()

> >     { asm{

> >           mov ah,02h    /* cursor pos BIOS call */

> >           mov bh,00h

> >           mov dh,06d

> >           mov dl,25d

> >           int 10h

> >           mov ah,02h    /* DOS char output call */

> >           mov dl,'?'

> >           int 21h

> >           mov ah,01h    /* keyboard in, no echo */

> >           int 21h

> >          }

> >     }

> #### 2. Array Manipulation

> >     #include <stdio.h>

> >     #include <graph.h>

> >     void  main()

> >     {

> >       int  array1[64], array2[64], i, *a1, *a2;

> >       char ch;

> >       for( i=1; i<64; i++ )

> >         array1[i] = i;         // fill array

> >       a1 = &array1[0];         // set up pointers to the

> >       a2 = &array2[0];         // first elements in each array

> >       { asm{

> >             mov  si,a1    /* get first pointer  */

> >             mov  di,a2    /* get second pointer */

> >             mov  cx,64d   /* set up count       */

> >            }

> >      here:

> >         asm{

> >             mov  ax,[si]  /* get source value   */

> >             mov  [di],ax  /* into dest location */

> >             add  si,2     /* increment pointers */

> >             add  di,2

> >             loop x

> >            }

> >       }

> >       for( i=0; i<20; i++ )

> >       printf("\t%d \t%d \n", array1[i], array2[i] );

> >     }

Developed and maintained by F. J. Looft, fjlooft@ee.wpi.edu.