NewBasic Compiler -- An x86 Compiler/Assembler/Disassembler for DOS

Specifying the type of mode.

When writing boot sectors, loaders, and kernels, you need to tell the compiler and assembler whether to output 16-bit real mode code, 32-bit real mode code, or 32-bit protected mode code.  The NBC compiler gives this functionality using #pragmas.

Let's start out with the C source code:

//.optoff                        // we don't want anything changed unknowingly
#pragma optimizer(off)

//.rmode                         // bios starts with (un)real mode
#pragma ptype(rmode)

//.186                          // only allow 80x186 code at start
#pragma proc(186)

// prototypes here
void do_32bit_real();
void do_32bit_pmode();

/* As with many boot sectors and loaders, your code may start
 *  out in 16-bit real mode.  However, once you have done what
 *  you need to do in real mode, you can then move to protected
 *  mode.
 * With this example, I will show that the first part of this
 *  code, the main() function, will be in 16-bit real mode.
 *  Then it will call a function that is in 32-bit real mode
 *  to show the 32-bit conditional jumps, yet still in real mode.
 * Then this function will call a 32-bit pmode code to show the
 *  output of that function.
 * Please note that this example is to show how to make NBC emit
 *  16-bit or 32-bit code.  This example in no way has the code
 *  to actually switch the processor from one to the other.
 */
int main() {
  int  i = 0;
 
  // the 'i' above is 16-bit.  You will be able to see this
  // in the .asm output shown below.
  
  // now let's do something with this 'i' and then show a
  //  conditional jump to see the 16-bit jump.
  if (i == 1) {
    i = 0;
  }

  do_32bit_real();
}

/* Allow 32-bit code.
 *  Please note that we are still in real mode.  However, the
 *  .asm out code will now use 32-bit assembly along with 32-bit
 *  conditional jumps.
 */
#pragma proc(386)

void do_32bit_real() {
  int i = 0;

  // the 'i' above is 32-bit.  You will be able to see this
  // in the .asm output shown below.

  // now let's do something with this 'i' and then show a
  //  conditional jump to see the 32-bit jump.
  if (i == 1) {
    i = 0;
  }

  do_32bit_pmode();
}

/* Allow 32-bit protected mode code.
 *  Please note that we are now in protected mode code.  The
 *  overrides (66h and 67h) or now the opposite of above.
 */
#pragma ptype(pmode)  //.pmode

void do_32bit_pmode() {
  int i = 0;

  // the 'i' above is still 32-bit.

  // now let's do something with this 'i' and then show a
  //  conditional jump is still a 32-bit jump
  if (i == 1) {
    i = 0;
  }
}

/* Please note that as far as NBC is concerned, NBC will
 *  create the exact same .asm output whether you are in
 *  32-bit real mode or 32-bit pmode.  Therefore, the two
 *  functions above are identical (minus the call in the first).
 * However, since the #pragma directive now added the .pmode
 *  directive to the .asm file, the assembler will now
 *  assemble the code accordingly, real mode or pmode.
 */
Now for the produced assembly code. (Please note that I instructed NBC to include the C source lines)
.model tiny
.code

; //.optoff                        // we don't want anything changed unknowingly
; #pragma optimizer(off)
.optoff

; //.rmode                         // bios starts with (un)real mode
; #pragma ptype(rmode)
.rmode

; //.186                          // only allow 80x86 code at start
; #pragma proc(186)
.186

; // prototypes here
; void do_32bit_real();
; void do_32bit_pmode();

; /* As with many boot sectors and loaders, your code may start
;  *  out in 16-bit real mode.  However, once you have done what
;  *  you need to do in real mode, you can then move to protected
;  *  mode.
;  * With this example, I will show that the first part of this
;  *  code, the main() function, will be in 16-bit real mode.
;  *  Then it will call a function that is in 32-bit real mode
;  *  to show the 32-bit conditional jumps, yet still in real mode.
;  * Then this function will call a 32-bit pmode code to show the
;  *  output of that function.
;  * Please note that this example is to show how to make NBC emit
;  *  16-bit or 32-bit code.  This example in now way has the code
;  *  to actually switch the processor from one to the other.
;  */

; int main() {

_main:
  push   bp
  mov    bp,sp
  jmp    L2
L1:
;   int  i = 0;
  mov    ax,0
  mov    [bp-2],ax
;   // the 'i' above is 16-bit.  You will be able to see this
;   // in the .asm output shown below.
;   
;   // now let's do something with this 'i' and then show a
;   //  conditional jump to see the 16-bit jump.
;   if (i == 1) {
  mov    ax,[bp-2]
  cmp    ax,1
  je     L6
  jmp    L5
L6:
;     i = 0;
  mov    ax,0
  mov    [bp-2],ax
;   }
L5:
;   do_32bit_real();
  call   _do_32bit_real
  mov    ax,0
L3:
  mov    sp,bp
  pop    bp
  ret  
L2:
  sub    sp,2
  jmp    L1

; /* Allow 32-bit code.
;  *  Please note that we are still in real mode.  However, the
;  *  .asm out code will now use 32-bit assembly along with 32-bit
;  *  conditional jumps.
;  */
; #pragma proc(386)
.386

; void do_32bit_real() {

_do_32bit_real:
  push   ebp
  mov    ebp,esp
  jmp    L9
L8:
;   int i = 0;
  mov    eax,0
  mov    [ebp-4],eax
;   // the 'i' above is 32-bit.  You will be able to see this
;   // in the .asm output shown below.
;
;   // now let's do something with this 'i' and then show a
;   //  conditional jump to see the 32-bit jump.
;   if (i == 1) {
  mov    eax,[ebp-4]
  cmp    eax,1
  jne    L12
;     i = 0;
  mov    eax,0
  mov    [ebp-4],eax
;   }
L12:
;   do_32bit_pmode();
  call   _do_32bit_pmode
L10:
  mov    esp,ebp
  pop    ebp
  ret  
L9:
  sub    esp,4
  jmp    L8

; /* Allow 32-bit protected mode code.
;  *  Please note that we are now in protected mode code.  The
;  *  overrides (66h and 67h) or now the opposite of above.
;  */
; #pragma ptype(pmode)  //.pmode
.pmode

; void do_32bit_pmode() {

_do_32bit_pmode:
  push   ebp
  mov    ebp,esp
  jmp    L16
L15:
;   int i = 0;
  mov    eax,0
  mov    [ebp-4],eax
;   // the 'i' above is still 32-bit.
;
;   // now let's do something with this 'i' and then show a
;   //  conditional jump is still a 32-bit jump
;   if (i == 1) {
  mov    eax,[ebp-4]
  cmp    eax,1
  jne    L19
;     i = 0;
  mov    eax,0
  mov    [ebp-4],eax
;   }
L19:
L17:
  mov    esp,ebp
  pop    ebp
  ret  
L16:
  sub    esp,4
  jmp    L15
.end


Please Note: