OpenCores
URL https://opencores.org/ocsvn/zet86/zet86/trunk

Subversion Repositories zet86

[/] [zet86/] [trunk/] [soc/] [bios/] [rombios.c] - Diff between revs 47 and 49

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 47 Rev 49
// ROM BIOS compatability entry points:
// ROM BIOS compatability entry points:
// ===================================
// ===================================
// $e05b ; POST Entry Point
// $e05b ; POST Entry Point
// $e6f2 ; INT 19h Boot Load Service Entry Point
// $e6f2 ; INT 19h Boot Load Service Entry Point
// $f045 ; INT 10 Functions 0-Fh Entry Point
// $f045 ; INT 10 Functions 0-Fh Entry Point
// $f065 ; INT 10h Video Support Service Entry Point
// $f065 ; INT 10h Video Support Service Entry Point
// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
// $fff0 ; Power-up Entry Point
// $fff0 ; Power-up Entry Point
// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
// $fffe ; System Model ID
// $fffe ; System Model ID
 
 
#include "rombios.h"
#include "rombios.h"
 
 
#define BX_CPU           0
#define BX_CPU           0
 
 
   /* model byte 0xFC = AT */
   /* model byte 0xFC = AT */
#define SYS_MODEL_ID     0xFC
#define SYS_MODEL_ID     0xFC
 
 
#ifndef BIOS_BUILD_DATE
#ifndef BIOS_BUILD_DATE
#  define BIOS_BUILD_DATE "06/23/99"
#  define BIOS_BUILD_DATE "06/23/99"
#endif
#endif
 
 
  // 1K of base memory used for Extended Bios Data Area (EBDA)
  // 1K of base memory used for Extended Bios Data Area (EBDA)
  // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
  // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
#define EBDA_SEG           0x9FC0
#define EBDA_SEG           0x9FC0
#define EBDA_SIZE          1              // In KiB
#define EBDA_SIZE          1              // In KiB
#define BASE_MEM_IN_K   (640 - EBDA_SIZE)
#define BASE_MEM_IN_K   (640 - EBDA_SIZE)
 
 
/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
#define IPL_SEG              0x9ff0
#define IPL_SEG              0x9ff0
#define IPL_TABLE_OFFSET     0x0000
#define IPL_TABLE_OFFSET     0x0000
#define IPL_TABLE_ENTRIES    8
#define IPL_TABLE_ENTRIES    8
#define IPL_COUNT_OFFSET     0x0080  /* u16: number of valid table entries */
#define IPL_COUNT_OFFSET     0x0080  /* u16: number of valid table entries */
#define IPL_SEQUENCE_OFFSET  0x0082  /* u16: next boot device */
#define IPL_SEQUENCE_OFFSET  0x0082  /* u16: next boot device */
#define IPL_BOOTFIRST_OFFSET 0x0084  /* u16: user selected device */
#define IPL_BOOTFIRST_OFFSET 0x0084  /* u16: user selected device */
#define IPL_SIZE             0xff
#define IPL_SIZE             0xff
#define IPL_TYPE_FLOPPY      0x01
#define IPL_TYPE_FLOPPY      0x01
#define IPL_TYPE_HARDDISK    0x02
#define IPL_TYPE_HARDDISK    0x02
#define IPL_TYPE_CDROM       0x03
#define IPL_TYPE_CDROM       0x03
#define IPL_TYPE_BEV         0x80
#define IPL_TYPE_BEV         0x80
 
 
// This is for compiling with gcc2 and gcc3
// This is for compiling with gcc2 and gcc3
#define ASM_START #asm
#define ASM_START #asm
#define ASM_END #endasm
#define ASM_END #endasm
 
 
ASM_START
ASM_START
.rom
.rom
 
 
.org 0x0000
.org 0x0000
 
 
use16 8086
use16 8086
 
 
MACRO SET_INT_VECTOR
MACRO SET_INT_VECTOR
  mov ax, ?3
  mov ax, ?3
  mov ?1*4, ax
  mov ?1*4, ax
  mov ax, ?2
  mov ax, ?2
  mov ?1*4+2, ax
  mov ?1*4+2, ax
MEND
MEND
 
 
ASM_END
ASM_END
 
 
typedef unsigned char  Bit8u;
typedef unsigned char  Bit8u;
typedef unsigned short Bit16u;
typedef unsigned short Bit16u;
typedef unsigned short bx_bool;
typedef unsigned short bx_bool;
typedef unsigned long  Bit32u;
typedef unsigned long  Bit32u;
 
 
 
 
  void memsetb(seg,offset,value,count);
  void memsetb(seg,offset,value,count);
  void memcpyb(dseg,doffset,sseg,soffset,count);
  void memcpyb(dseg,doffset,sseg,soffset,count);
  void memcpyd(dseg,doffset,sseg,soffset,count);
  void memcpyd(dseg,doffset,sseg,soffset,count);
 
 
  // memset of count bytes
  // memset of count bytes
    void
    void
  memsetb(seg,offset,value,count)
  memsetb(seg,offset,value,count)
    Bit16u seg;
    Bit16u seg;
    Bit16u offset;
    Bit16u offset;
    Bit16u value;
    Bit16u value;
    Bit16u count;
    Bit16u count;
  {
  {
  ASM_START
  ASM_START
    push bp
    push bp
    mov  bp, sp
    mov  bp, sp
 
 
      push ax
      push ax
      push cx
      push cx
      push es
      push es
      push di
      push di
 
 
      mov  cx, 10[bp] ; count
      mov  cx, 10[bp] ; count
      test cx, cx
      test cx, cx
      je   memsetb_end
      je   memsetb_end
      mov  ax, 4[bp] ; segment
      mov  ax, 4[bp] ; segment
      mov  es, ax
      mov  es, ax
      mov  ax, 6[bp] ; offset
      mov  ax, 6[bp] ; offset
      mov  di, ax
      mov  di, ax
      mov  al, 8[bp] ; value
      mov  al, 8[bp] ; value
      cld
      cld
      rep
      rep
       stosb
       stosb
 
 
  memsetb_end:
  memsetb_end:
      pop di
      pop di
      pop es
      pop es
      pop cx
      pop cx
      pop ax
      pop ax
 
 
    pop bp
    pop bp
  ASM_END
  ASM_END
  }
  }
 
 
  // memcpy of count bytes
  // memcpy of count bytes
    void
    void
  memcpyb(dseg,doffset,sseg,soffset,count)
  memcpyb(dseg,doffset,sseg,soffset,count)
    Bit16u dseg;
    Bit16u dseg;
    Bit16u doffset;
    Bit16u doffset;
    Bit16u sseg;
    Bit16u sseg;
    Bit16u soffset;
    Bit16u soffset;
    Bit16u count;
    Bit16u count;
  {
  {
  ASM_START
  ASM_START
    push bp
    push bp
    mov  bp, sp
    mov  bp, sp
 
 
      push ax
      push ax
      push cx
      push cx
      push es
      push es
      push di
      push di
      push ds
      push ds
      push si
      push si
 
 
      mov  cx, 12[bp] ; count
      mov  cx, 12[bp] ; count
      test cx, cx
      test cx, cx
      je   memcpyb_end
      je   memcpyb_end
      mov  ax, 4[bp] ; dsegment
      mov  ax, 4[bp] ; dsegment
      mov  es, ax
      mov  es, ax
      mov  ax, 6[bp] ; doffset
      mov  ax, 6[bp] ; doffset
      mov  di, ax
      mov  di, ax
      mov  ax, 8[bp] ; ssegment
      mov  ax, 8[bp] ; ssegment
      mov  ds, ax
      mov  ds, ax
      mov  ax, 10[bp] ; soffset
      mov  ax, 10[bp] ; soffset
      mov  si, ax
      mov  si, ax
      cld
      cld
      rep
      rep
       movsb
       movsb
 
 
  memcpyb_end:
  memcpyb_end:
      pop si
      pop si
      pop ds
      pop ds
      pop di
      pop di
      pop es
      pop es
      pop cx
      pop cx
      pop ax
      pop ax
 
 
    pop bp
    pop bp
  ASM_END
  ASM_END
  }
  }
 
 
  // Bit32u (unsigned long) and long helper functions
  // Bit32u (unsigned long) and long helper functions
  ASM_START
  ASM_START
 
 
  idiv_u:
  idiv_u:
    xor dx,dx
    xor dx,dx
    div bx
    div bx
    ret
    ret
 
 
  ldivul:
  ldivul:
    mov     cx,[di]
    mov     cx,[di]
    mov     di,2[di]
    mov     di,2[di]
    call    ludivmod
    call    ludivmod
    xchg    ax,cx
    xchg    ax,cx
    xchg    bx,di
    xchg    bx,di
    ret
    ret
 
 
.align 2
.align 2
ldivmod:
ldivmod:
    mov     dx,di           ; sign byte of b in dh
    mov     dx,di           ; sign byte of b in dh
    mov     dl,bh           ; sign byte of a in dl
    mov     dl,bh           ; sign byte of a in dl
    test    di,di
    test    di,di
    jns     set_asign
    jns     set_asign
    neg     di
    neg     di
    neg     cx
    neg     cx
    sbb     di,*0
    sbb     di,*0
set_asign:
set_asign:
    test    bx,bx
    test    bx,bx
    jns     got_signs       ; leave r = a positive
    jns     got_signs       ; leave r = a positive
    neg     bx
    neg     bx
    neg     ax
    neg     ax
    sbb     bx,*0
    sbb     bx,*0
    j       got_signs
    j       got_signs
 
 
.align 2
.align 2
ludivmod:
ludivmod:
    xor     dx,dx           ; both sign bytes 0
    xor     dx,dx           ; both sign bytes 0
got_signs:
got_signs:
    push    bp
    push    bp
    push    si
    push    si
    mov     bp,sp
    mov     bp,sp
    push    di              ; remember b
    push    di              ; remember b
    push    cx
    push    cx
b0  =       -4
b0  =       -4
b16 =       -2
b16 =       -2
 
 
    test    di,di
    test    di,di
    jne     divlarge
    jne     divlarge
    test    cx,cx
    test    cx,cx
    je      divzero
    je      divzero
    cmp     bx,cx
    cmp     bx,cx
    jae     divlarge        ; would overflow
    jae     divlarge        ; would overflow
    xchg    dx,bx           ; a in dx:ax, signs in bx
    xchg    dx,bx           ; a in dx:ax, signs in bx
    div     cx
    div     cx
    xchg    cx,ax           ; q in di:cx, junk in ax
    xchg    cx,ax           ; q in di:cx, junk in ax
    xchg    ax,bx           ; signs in ax, junk in bx
    xchg    ax,bx           ; signs in ax, junk in bx
    xchg    ax,dx           ; r in ax, signs back in dx
    xchg    ax,dx           ; r in ax, signs back in dx
    mov     bx,di           ; r in bx:ax
    mov     bx,di           ; r in bx:ax
    j       zdivu1
    j       zdivu1
 
 
divzero:                        ; return q = 0 and r = a
divzero:                        ; return q = 0 and r = a
    test    dl,dl
    test    dl,dl
    jns     return
    jns     return
    j       negr            ; a initially minus, restore it
    j       negr            ; a initially minus, restore it
 
 
divlarge:
divlarge:
    push    dx              ; remember sign bytes
    push    dx              ; remember sign bytes
    mov     si,di           ; w in si:dx, initially b from di:cx
    mov     si,di           ; w in si:dx, initially b from di:cx
    mov     dx,cx
    mov     dx,cx
    xor     cx,cx           ; q in di:cx, initially 0
    xor     cx,cx           ; q in di:cx, initially 0
    mov     di,cx
    mov     di,cx
                            ; r in bx:ax, initially a
                            ; r in bx:ax, initially a
                            ; use di:cx rather than dx:cx in order
                            ; use di:cx rather than dx:cx in order
                            ; to have dx free for a byte pair later
                            ; to have dx free for a byte pair later
    cmp     si,bx
    cmp     si,bx
    jb      loop1
    jb      loop1
    ja      zdivu           ; finished if b > r
    ja      zdivu           ; finished if b > r
    cmp     dx,ax
    cmp     dx,ax
    ja      zdivu
    ja      zdivu
 
 
; rotate w (= b) to greatest dyadic multiple of b <= r
; rotate w (= b) to greatest dyadic multiple of b <= r
 
 
loop1:
loop1:
    shl     dx,*1           ; w = 2*w
    shl     dx,*1           ; w = 2*w
    rcl     si,*1
    rcl     si,*1
    jc      loop1_exit      ; w was > r counting overflow (unsigned)
    jc      loop1_exit      ; w was > r counting overflow (unsigned)
    cmp     si,bx           ; while w <= r (unsigned)
    cmp     si,bx           ; while w <= r (unsigned)
    jb      loop1
    jb      loop1
    ja      loop1_exit
    ja      loop1_exit
    cmp     dx,ax
    cmp     dx,ax
    jbe     loop1           ; else exit with carry clear for rcr
    jbe     loop1           ; else exit with carry clear for rcr
loop1_exit:
loop1_exit:
    rcr     si,*1
    rcr     si,*1
    rcr     dx,*1
    rcr     dx,*1
loop2:
loop2:
    shl     cx,*1           ; q = 2*q
    shl     cx,*1           ; q = 2*q
    rcl     di,*1
    rcl     di,*1
    cmp     si,bx           ; if w <= r
    cmp     si,bx           ; if w <= r
    jb      loop2_over
    jb      loop2_over
    ja      loop2_test
    ja      loop2_test
    cmp     dx,ax
    cmp     dx,ax
    ja      loop2_test
    ja      loop2_test
loop2_over:
loop2_over:
    add     cx,*1           ; q++
    add     cx,*1           ; q++
    adc     di,*0
    adc     di,*0
    sub     ax,dx           ; r = r-w
    sub     ax,dx           ; r = r-w
    sbb     bx,si
    sbb     bx,si
loop2_test:
loop2_test:
    shr     si,*1           ; w = w/2
    shr     si,*1           ; w = w/2
    rcr     dx,*1
    rcr     dx,*1
    cmp     si,b16[bp]      ; while w >= b
    cmp     si,b16[bp]      ; while w >= b
    ja      loop2
    ja      loop2
    jb      zdivu
    jb      zdivu
    cmp     dx,b0[bp]
    cmp     dx,b0[bp]
    jae     loop2
    jae     loop2
 
 
zdivu:
zdivu:
    pop     dx              ; sign bytes
    pop     dx              ; sign bytes
zdivu1:
zdivu1:
    test    dh,dh
    test    dh,dh
    js      zbminus
    js      zbminus
    test    dl,dl
    test    dl,dl
    jns     return          ; else a initially minus, b plus
    jns     return          ; else a initially minus, b plus
    mov     dx,ax           ; -a = b * q + r ==> a = b * (-q) + (-r)
    mov     dx,ax           ; -a = b * q + r ==> a = b * (-q) + (-r)
    or      dx,bx
    or      dx,bx
    je      negq            ; use if r = 0
    je      negq            ; use if r = 0
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b - r)
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b - r)
    sbb     bx,b16[bp]
    sbb     bx,b16[bp]
    not     cx              ; q = -1 - q (same as complement)
    not     cx              ; q = -1 - q (same as complement)
    not     di
    not     di
negr:
negr:
    neg     bx
    neg     bx
    neg     ax
    neg     ax
    sbb     bx,*0
    sbb     bx,*0
return:
return:
    mov     sp,bp
    mov     sp,bp
    pop     si
    pop     si
    pop     bp
    pop     bp
    ret
    ret
 
 
.align 2
.align 2
zbminus:
zbminus:
    test    dl,dl           ; (-a) = (-b) * q + r ==> a = b * q + (-r)
    test    dl,dl           ; (-a) = (-b) * q + r ==> a = b * q + (-r)
    js      negr            ; use if initial a was minus
    js      negr            ; use if initial a was minus
    mov     dx,ax           ; a = (-b) * q + r ==> a = b * (-q) + r
    mov     dx,ax           ; a = (-b) * q + r ==> a = b * (-q) + r
    or      dx,bx
    or      dx,bx
    je      negq            ; use if r = 0
    je      negq            ; use if r = 0
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b + r)
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b + r)
                                ; (b is now -b)
                                ; (b is now -b)
    sbb     bx,b16[bp]
    sbb     bx,b16[bp]
    not     cx
    not     cx
    not     di
    not     di
    mov     sp,bp
    mov     sp,bp
    pop     si
    pop     si
    pop     bp
    pop     bp
    ret
    ret
 
 
.align 2
.align 2
negq:
negq:
    neg     di
    neg     di
    neg     cx
    neg     cx
    sbb     di,*0
    sbb     di,*0
    mov     sp,bp
    mov     sp,bp
    pop     si
    pop     si
    pop     bp
    pop     bp
    ret
    ret
 
 
.align 2
.align 2
ltstl:
ltstl:
ltstul:
ltstul:
    test    bx,bx
    test    bx,bx
    je      ltst_not_sure
    je      ltst_not_sure
    ret
    ret
 
 
.align 2
.align 2
ltst_not_sure:
ltst_not_sure:
    test    ax,ax
    test    ax,ax
    js      ltst_fix_sign
    js      ltst_fix_sign
    ret
    ret
 
 
.align 2
.align 2
ltst_fix_sign:
ltst_fix_sign:
    inc     bx
    inc     bx
    ret
    ret
 
 
.align 2
.align 2
lmull:
lmull:
lmulul:
lmulul:
    mov     cx,ax
    mov     cx,ax
    mul     word ptr 2[di]
    mul     word ptr 2[di]
    xchg    ax,bx
    xchg    ax,bx
    mul     word ptr [di]
    mul     word ptr [di]
    add     bx,ax
    add     bx,ax
    mov     ax,ptr [di]
    mov     ax,ptr [di]
    mul     cx
    mul     cx
    add     bx,dx
    add     bx,dx
    ret
    ret
 
 
.align 2
.align 2
lsubl:
lsubl:
lsubul:
lsubul:
    sub     ax,[di]
    sub     ax,[di]
    sbb     bx,2[di]
    sbb     bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
laddl:
laddl:
laddul:
laddul:
    add     ax,[di]
    add     ax,[di]
    adc     bx,2[di]
    adc     bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
lorl:
lorl:
lorul:
lorul:
    or      ax,[di]
    or      ax,[di]
    or      bx,2[di]
    or      bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
lsrul:
lsrul:
    mov     cx,di
    mov     cx,di
    jcxz    lsru_exit
    jcxz    lsru_exit
    cmp     cx,*32
    cmp     cx,*32
    jae     lsru_zero
    jae     lsru_zero
lsru_loop:
lsru_loop:
    shr     bx,*1
    shr     bx,*1
    rcr     ax,*1
    rcr     ax,*1
    loop    lsru_loop
    loop    lsru_loop
lsru_exit:
lsru_exit:
    ret
    ret
 
 
.align 2
.align 2
lsru_zero:
lsru_zero:
    xor     ax,ax
    xor     ax,ax
    mov     bx,ax
    mov     bx,ax
    ret
    ret
 
 
.align 2
.align 2
landl:
landl:
landul:
landul:
    and     ax,[di]
    and     ax,[di]
    and     bx,2[di]
    and     bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
lcmpl:
lcmpl:
lcmpul:
lcmpul:
    sub     bx,2[di]
    sub     bx,2[di]
    je      lcmp_not_sure
    je      lcmp_not_sure
    ret
    ret
 
 
.align 2
.align 2
lcmp_not_sure:
lcmp_not_sure:
    cmp     ax,[di]
    cmp     ax,[di]
    jb      lcmp_b_and_lt
    jb      lcmp_b_and_lt
    jge     lcmp_exit
    jge     lcmp_exit
 
 
    inc     bx
    inc     bx
lcmp_exit:
lcmp_exit:
    ret
    ret
 
 
.align 2
.align 2
lcmp_b_and_lt:
lcmp_b_and_lt:
    dec     bx
    dec     bx
    ret
    ret
 
 
  ASM_END
  ASM_END
 
 
// for access to RAM area which is used by interrupt vectors
// for access to RAM area which is used by interrupt vectors
// and BIOS Data Area
// and BIOS Data Area
 
 
typedef struct {
typedef struct {
  unsigned char filler1[0x400];
  unsigned char filler1[0x400];
  unsigned char filler2[0x6c];
  unsigned char filler2[0x6c];
  Bit16u ticks_low;
  Bit16u ticks_low;
  Bit16u ticks_high;
  Bit16u ticks_high;
  Bit8u  midnight_flag;
  Bit8u  midnight_flag;
  } bios_data_t;
  } bios_data_t;
 
 
#define BiosData ((bios_data_t  *) 0)
#define BiosData ((bios_data_t  *) 0)
 
 
typedef struct {
typedef struct {
  union {
  union {
    struct {
    struct {
      Bit16u di, si, bp, sp;
      Bit16u di, si, bp, sp;
      Bit16u bx, dx, cx, ax;
      Bit16u bx, dx, cx, ax;
      } r16;
      } r16;
    struct {
    struct {
      Bit16u filler[4];
      Bit16u filler[4];
      Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
      Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
      } r8;
      } r8;
    } u;
    } u;
  } pusha_regs_t;
  } pusha_regs_t;
 
 
typedef struct {
typedef struct {
  union {
  union {
    struct {
    struct {
      Bit16u flags;
      Bit16u flags;
      } r16;
      } r16;
    struct {
    struct {
      Bit8u  flagsl;
      Bit8u  flagsl;
      Bit8u  flagsh;
      Bit8u  flagsh;
      } r8;
      } r8;
    } u;
    } u;
  } flags_t;
  } flags_t;
 
 
#define SetCF(x)   x.u.r8.flagsl |= 0x01
#define SetCF(x)   x.u.r8.flagsl |= 0x01
#define SetZF(x)   x.u.r8.flagsl |= 0x40
#define SetZF(x)   x.u.r8.flagsl |= 0x40
#define ClearCF(x) x.u.r8.flagsl &= 0xfe
#define ClearCF(x) x.u.r8.flagsl &= 0xfe
#define ClearZF(x) x.u.r8.flagsl &= 0xbf
#define ClearZF(x) x.u.r8.flagsl &= 0xbf
#define GetCF(x)   (x.u.r8.flagsl & 0x01)
#define GetCF(x)   (x.u.r8.flagsl & 0x01)
 
 
typedef struct {
typedef struct {
  Bit16u ip;
  Bit16u ip;
  Bit16u cs;
  Bit16u cs;
  flags_t flags;
  flags_t flags;
  } iret_addr_t;
  } iret_addr_t;
 
 
typedef struct {
typedef struct {
  Bit16u type;
  Bit16u type;
  Bit16u flags;
  Bit16u flags;
  Bit32u vector;
  Bit32u vector;
  Bit32u description;
  Bit32u description;
  Bit32u reserved;
  Bit32u reserved;
  } ipl_entry_t;
  } ipl_entry_t;
 
 
static Bit16u         inw();
static Bit16u         inw();
static void           outw();
static void           outw();
 
 
static Bit8u          read_byte();
static Bit8u          read_byte();
static Bit16u         read_word();
static Bit16u         read_word();
static void           write_byte();
static void           write_byte();
static void           write_word();
static void           write_word();
static void           bios_printf();
static void           bios_printf();
 
 
static void           int09_function();
static void           int09_function();
static void           int13_harddisk();
static void           int13_harddisk();
static void           transf_sect();
static void           transf_sect();
static void           int13_diskette_function();
static void           int13_diskette_function();
static void           int16_function();
static void           int16_function();
static void           int19_function();
static void           int19_function();
static void           int1a_function();
static void           int1a_function();
static Bit16u         get_CS();
static Bit16u         get_CS();
static Bit16u         get_SS();
static Bit16u         get_SS();
static unsigned int   enqueue_key();
static unsigned int   enqueue_key();
static unsigned int   dequeue_key();
static unsigned int   dequeue_key();
static void           set_diskette_ret_status();
static void           set_diskette_ret_status();
static void           set_diskette_current_cyl();
static void           set_diskette_current_cyl();
 
 
static void           print_bios_banner();
static void           print_bios_banner();
static void           print_boot_device();
static void           print_boot_device();
static void           print_boot_failure();
static void           print_boot_failure();
 
 
#if DEBUG_INT16
#if DEBUG_INT16
#  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
#  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
#else
#else
#  define BX_DEBUG_INT16(a...)
#  define BX_DEBUG_INT16(a...)
#endif
#endif
 
 
#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
 
 
#define GET_AL() ( AX & 0x00ff )
#define GET_AL() ( AX & 0x00ff )
#define GET_BL() ( BX & 0x00ff )
#define GET_BL() ( BX & 0x00ff )
#define GET_CL() ( CX & 0x00ff )
#define GET_CL() ( CX & 0x00ff )
#define GET_DL() ( DX & 0x00ff )
#define GET_DL() ( DX & 0x00ff )
#define GET_AH() ( AX >> 8 )
#define GET_AH() ( AX >> 8 )
#define GET_BH() ( BX >> 8 )
#define GET_BH() ( BX >> 8 )
#define GET_CH() ( CX >> 8 )
#define GET_CH() ( CX >> 8 )
#define GET_DH() ( DX >> 8 )
#define GET_DH() ( DX >> 8 )
 
 
#define GET_ELDL() ( ELDX & 0x00ff )
#define GET_ELDL() ( ELDX & 0x00ff )
#define GET_ELDH() ( ELDX >> 8 )
#define GET_ELDH() ( ELDX >> 8 )
 
 
#define SET_CF()     FLAGS |= 0x0001
#define SET_CF()     FLAGS |= 0x0001
#define CLEAR_CF()   FLAGS &= 0xfffe
#define CLEAR_CF()   FLAGS &= 0xfffe
#define GET_CF()     (FLAGS & 0x0001)
#define GET_CF()     (FLAGS & 0x0001)
 
 
#define SET_ZF()     FLAGS |= 0x0040
#define SET_ZF()     FLAGS |= 0x0040
#define CLEAR_ZF()   FLAGS &= 0xffbf
#define CLEAR_ZF()   FLAGS &= 0xffbf
#define GET_ZF()     (FLAGS & 0x0040)
#define GET_ZF()     (FLAGS & 0x0040)
 
 
#define UNSUPPORTED_FUNCTION 0x86
#define UNSUPPORTED_FUNCTION 0x86
 
 
#define none 0
#define none 0
#define MAX_SCAN_CODE 0x58
#define MAX_SCAN_CODE 0x58
 
 
static struct {
static struct {
  Bit16u normal;
  Bit16u normal;
  Bit16u shift;
  Bit16u shift;
  Bit16u control;
  Bit16u control;
  Bit16u alt;
  Bit16u alt;
  Bit8u lock_flags;
  Bit8u lock_flags;
  } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
  } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
      {   none,   none,   none,   none, none },
      {   none,   none,   none,   none, none },
      { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
      { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
      { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
      { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
      { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
      { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
      { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
      { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
      { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
      { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
      { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
      { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
      { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
      { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
      { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
      { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
      { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
      { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
      { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
      { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
      { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
      { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
      { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
      { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
      { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
      { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
      { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
      { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
      { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
      { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
      { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
      { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
      { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
      { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
      { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
      { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
      { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
      { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
      { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
      { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
      { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
      { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
      { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
      { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
      { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
      { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
      { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
      { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
      { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
      { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
      { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
      { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
      { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
      { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
      { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
      { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
      {   none,   none,   none,   none, none }, /* L Ctrl */
      {   none,   none,   none,   none, none }, /* L Ctrl */
      { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
      { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
      { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
      { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
      { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
      { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
      { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
      { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
      { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
      { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
      { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
      { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
      { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
      { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
      { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
      { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
      { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
      { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
      { 0x273b, 0x273a,   none,   none, none }, /* ;: */
      { 0x273b, 0x273a,   none,   none, none }, /* ;: */
      { 0x2827, 0x2822,   none,   none, none }, /* '" */
      { 0x2827, 0x2822,   none,   none, none }, /* '" */
      { 0x2960, 0x297e,   none,   none, none }, /* `~ */
      { 0x2960, 0x297e,   none,   none, none }, /* `~ */
      {   none,   none,   none,   none, none }, /* L shift */
      {   none,   none,   none,   none, none }, /* L shift */
      { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
      { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
      { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
      { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
      { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
      { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
      { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
      { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
      { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
      { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
      { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
      { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
      { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
      { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
      { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
      { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
      { 0x332c, 0x333c,   none,   none, none }, /* ,< */
      { 0x332c, 0x333c,   none,   none, none }, /* ,< */
      { 0x342e, 0x343e,   none,   none, none }, /* .> */
      { 0x342e, 0x343e,   none,   none, none }, /* .> */
      { 0x352f, 0x353f,   none,   none, none }, /* /? */
      { 0x352f, 0x353f,   none,   none, none }, /* /? */
      {   none,   none,   none,   none, none }, /* R Shift */
      {   none,   none,   none,   none, none }, /* R Shift */
      { 0x372a, 0x372a,   none,   none, none }, /* * */
      { 0x372a, 0x372a,   none,   none, none }, /* * */
      {   none,   none,   none,   none, none }, /* L Alt */
      {   none,   none,   none,   none, none }, /* L Alt */
      { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
      { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
      {   none,   none,   none,   none, none }, /* caps lock */
      {   none,   none,   none,   none, none }, /* caps lock */
      { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
      { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
      { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
      { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
      { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
      { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
      { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
      { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
      { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
      { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
      { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
      { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
      { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
      { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
      { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
      { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
      { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
      { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
      { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
      { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
      {   none,   none,   none,   none, none }, /* Num Lock */
      {   none,   none,   none,   none, none }, /* Num Lock */
      {   none,   none,   none,   none, none }, /* Scroll Lock */
      {   none,   none,   none,   none, none }, /* Scroll Lock */
      { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
      { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
      { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
      { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
      { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
      { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
      { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
      { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
      { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
      { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
      { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
      { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
      { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
      { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
      { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
      { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
      { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
      { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
      { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
      { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
      { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
      { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
      { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
      { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
      { 0x5300, 0x532e,   none,   none, 0x20 }, /* Del */
      { 0x5300, 0x532e,   none,   none, 0x20 }, /* Del */
      {   none,   none,   none,   none, none },
      {   none,   none,   none,   none, none },
      {   none,   none,   none,   none, none },
      {   none,   none,   none,   none, none },
      { 0x565c, 0x567c,   none,   none, none }, /* \| */
      { 0x565c, 0x567c,   none,   none, none }, /* \| */
      { 0x5700, 0x5700,   none,   none, none }, /* F11 */
      { 0x5700, 0x5700,   none,   none, none }, /* F11 */
      { 0x5800, 0x5800,   none,   none, none }  /* F12 */
      { 0x5800, 0x5800,   none,   none, none }  /* F12 */
      };
      };
 
 
  Bit16u
  Bit16u
inw(port)
inw(port)
  Bit16u port;
  Bit16u port;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push dx
    push dx
    mov  dx, 4[bp]
    mov  dx, 4[bp]
    in   ax, dx
    in   ax, dx
    pop  dx
    pop  dx
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  void
  void
outw(port, val)
outw(port, val)
  Bit16u port;
  Bit16u port;
  Bit16u  val;
  Bit16u  val;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push ax
    push ax
    push dx
    push dx
    mov  dx, 4[bp]
    mov  dx, 4[bp]
    mov  ax, 6[bp]
    mov  ax, 6[bp]
    out  dx, ax
    out  dx, ax
    pop  dx
    pop  dx
    pop  ax
    pop  ax
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  Bit8u
  Bit8u
read_byte(seg, offset)
read_byte(seg, offset)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  al, [bx]
    mov  al, [bx]
    ;; al = return value (byte)
    ;; al = return value (byte)
    pop  ds
    pop  ds
    pop  bx
    pop  bx
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  Bit16u
  Bit16u
read_word(seg, offset)
read_word(seg, offset)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  ax, [bx]
    mov  ax, [bx]
    ;; ax = return value (word)
    ;; ax = return value (word)
    pop  ds
    pop  ds
    pop  bx
    pop  bx
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  void
  void
write_byte(seg, offset, data)
write_byte(seg, offset, data)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
  Bit8u data;
  Bit8u data;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push ax
    push ax
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  al, 8[bp] ; data byte
    mov  al, 8[bp] ; data byte
    mov  [bx], al  ; write data byte
    mov  [bx], al  ; write data byte
    pop  ds
    pop  ds
    pop  bx
    pop  bx
    pop  ax
    pop  ax
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  void
  void
write_word(seg, offset, data)
write_word(seg, offset, data)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
  Bit16u data;
  Bit16u data;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push ax
    push ax
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  ax, 8[bp] ; data word
    mov  ax, 8[bp] ; data word
    mov  [bx], ax  ; write data word
    mov  [bx], ax  ; write data word
    pop  ds
    pop  ds
    pop  bx
    pop  bx
    pop  ax
    pop  ax
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  Bit16u
  Bit16u
get_CS()
get_CS()
{
{
ASM_START
ASM_START
  mov  ax, cs
  mov  ax, cs
ASM_END
ASM_END
}
}
 
 
  Bit16u
  Bit16u
get_SS()
get_SS()
{
{
ASM_START
ASM_START
  mov  ax, ss
  mov  ax, ss
ASM_END
ASM_END
}
}
 
 
  void
  void
wrch(c)
wrch(c)
  Bit8u  c;
  Bit8u  c;
{
{
  ASM_START
  ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
  push bx
  push bx
  mov  ah, #0x0e
  mov  ah, #0x0e
  mov  al, 4[bp]
  mov  al, 4[bp]
  xor  bx,bx
  xor  bx,bx
  int  #0x10
  int  #0x10
  pop  bx
  pop  bx
 
 
  pop  bp
  pop  bp
  ASM_END
  ASM_END
}
}
 
 
  void
  void
send(action, c)
send(action, c)
  Bit16u action;
  Bit16u action;
  Bit8u  c;
  Bit8u  c;
{
{
  if (action & BIOS_PRINTF_SCREEN) {
  if (action & BIOS_PRINTF_SCREEN) {
    if (c == '\n') wrch('\r');
    if (c == '\n') wrch('\r');
    wrch(c);
    wrch(c);
  }
  }
}
}
 
 
  void
  void
put_int(action, val, width, neg)
put_int(action, val, width, neg)
  Bit16u action;
  Bit16u action;
  short val, width;
  short val, width;
  bx_bool neg;
  bx_bool neg;
{
{
  short nval = val / 10;
  short nval = val / 10;
  if (nval)
  if (nval)
    put_int(action, nval, width - 1, neg);
    put_int(action, nval, width - 1, neg);
  else {
  else {
    while (--width > 0) send(action, ' ');
    while (--width > 0) send(action, ' ');
    if (neg) send(action, '-');
    if (neg) send(action, '-');
  }
  }
  send(action, val - (nval * 10) + '0');
  send(action, val - (nval * 10) + '0');
}
}
 
 
  void
  void
put_uint(action, val, width, neg)
put_uint(action, val, width, neg)
  Bit16u action;
  Bit16u action;
  unsigned short val;
  unsigned short val;
  short width;
  short width;
  bx_bool neg;
  bx_bool neg;
{
{
  unsigned short nval = val / 10;
  unsigned short nval = val / 10;
  if (nval)
  if (nval)
    put_uint(action, nval, width - 1, neg);
    put_uint(action, nval, width - 1, neg);
  else {
  else {
    while (--width > 0) send(action, ' ');
    while (--width > 0) send(action, ' ');
    if (neg) send(action, '-');
    if (neg) send(action, '-');
  }
  }
  send(action, val - (nval * 10) + '0');
  send(action, val - (nval * 10) + '0');
}
}
 
 
  void
  void
put_luint(action, val, width, neg)
put_luint(action, val, width, neg)
  Bit16u action;
  Bit16u action;
  unsigned long val;
  unsigned long val;
  short width;
  short width;
  bx_bool neg;
  bx_bool neg;
{
{
  unsigned long nval = val / 10;
  unsigned long nval = val / 10;
  if (nval)
  if (nval)
    put_luint(action, nval, width - 1, neg);
    put_luint(action, nval, width - 1, neg);
  else {
  else {
    while (--width > 0) send(action, ' ');
    while (--width > 0) send(action, ' ');
    if (neg) send(action, '-');
    if (neg) send(action, '-');
  }
  }
  send(action, val - (nval * 10) + '0');
  send(action, val - (nval * 10) + '0');
}
}
 
 
void put_str(action, segment, offset)
void put_str(action, segment, offset)
  Bit16u action;
  Bit16u action;
  Bit16u segment;
  Bit16u segment;
  Bit16u offset;
  Bit16u offset;
{
{
  Bit8u c;
  Bit8u c;
 
 
  while (c = read_byte(segment, offset)) {
  while (c = read_byte(segment, offset)) {
    send(action, c);
    send(action, c);
    offset++;
    offset++;
  }
  }
}
}
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// bios_printf()
// bios_printf()
//   A compact variable argument printf function.
//   A compact variable argument printf function.
//
//
//   Supports %[format_width][length]format
//   Supports %[format_width][length]format
//   where format can be x,X,u,d,s,S,c
//   where format can be x,X,u,d,s,S,c
//   and the optional length modifier is l (ell)
//   and the optional length modifier is l (ell)
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
  void
  void
bios_printf(action, s)
bios_printf(action, s)
  Bit16u action;
  Bit16u action;
  Bit8u *s;
  Bit8u *s;
{
{
  Bit8u c, format_char;
  Bit8u c, format_char;
  bx_bool  in_format;
  bx_bool  in_format;
  short i;
  short i;
  Bit16u  *arg_ptr;
  Bit16u  *arg_ptr;
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
 
 
  arg_ptr = &s;
  arg_ptr = &s;
  arg_seg = get_SS();
  arg_seg = get_SS();
 
 
  in_format = 0;
  in_format = 0;
  format_width = 0;
  format_width = 0;
 
 
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
 
 
  while (c = read_byte(get_CS(), s)) {
  while (c = read_byte(get_CS(), s)) {
    if ( c == '%' ) {
    if ( c == '%' ) {
      in_format = 1;
      in_format = 1;
      format_width = 0;
      format_width = 0;
      }
      }
    else if (in_format) {
    else if (in_format) {
      if ( (c>='0') && (c<='9') ) {
      if ( (c>='0') && (c<='9') ) {
        format_width = (format_width * 10) + (c - '0');
        format_width = (format_width * 10) + (c - '0');
        }
        }
      else {
      else {
        arg_ptr++; // increment to next arg
        arg_ptr++; // increment to next arg
        arg = read_word(arg_seg, arg_ptr);
        arg = read_word(arg_seg, arg_ptr);
        if (c == 'x' || c == 'X') {
        if (c == 'x' || c == 'X') {
          if (format_width == 0)
          if (format_width == 0)
            format_width = 4;
            format_width = 4;
          if (c == 'x')
          if (c == 'x')
            hexadd = 'a';
            hexadd = 'a';
          else
          else
            hexadd = 'A';
            hexadd = 'A';
          for (i=format_width-1; i>=0; i--) {
          for (i=format_width-1; i>=0; i--) {
            nibble = (arg >> (4 * i)) & 0x000f;
            nibble = (arg >> (4 * i)) & 0x000f;
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
            }
            }
          }
          }
        else if (c == 'u') {
        else if (c == 'u') {
          put_uint(action, arg, format_width, 0);
          put_uint(action, arg, format_width, 0);
          }
          }
        else if (c == 'l') {
        else if (c == 'l') {
          s++;
          s++;
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
          arg_ptr++; /* increment to next arg */
          arg_ptr++; /* increment to next arg */
          hibyte = read_word(arg_seg, arg_ptr);
          hibyte = read_word(arg_seg, arg_ptr);
          if (c == 'd') {
          if (c == 'd') {
            if (hibyte & 0x8000)
            if (hibyte & 0x8000)
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
            else
            else
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
           }
           }
          else if (c == 'u') {
          else if (c == 'u') {
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
           }
           }
          else if (c == 'x' || c == 'X')
          else if (c == 'x' || c == 'X')
           {
           {
            if (format_width == 0)
            if (format_width == 0)
              format_width = 8;
              format_width = 8;
            if (c == 'x')
            if (c == 'x')
              hexadd = 'a';
              hexadd = 'a';
            else
            else
              hexadd = 'A';
              hexadd = 'A';
            for (i=format_width-1; i>=0; i--) {
            for (i=format_width-1; i>=0; i--) {
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
              }
              }
           }
           }
          }
          }
        else if (c == 'd') {
        else if (c == 'd') {
          if (arg & 0x8000)
          if (arg & 0x8000)
            put_int(action, -arg, format_width - 1, 1);
            put_int(action, -arg, format_width - 1, 1);
          else
          else
            put_int(action, arg, format_width, 0);
            put_int(action, arg, format_width, 0);
          }
          }
        else if (c == 's') {
        else if (c == 's') {
          put_str(action, get_CS(), arg);
          put_str(action, get_CS(), arg);
          }
          }
        else if (c == 'S') {
        else if (c == 'S') {
          hibyte = arg;
          hibyte = arg;
          arg_ptr++;
          arg_ptr++;
          arg = read_word(arg_seg, arg_ptr);
          arg = read_word(arg_seg, arg_ptr);
          put_str(action, hibyte, arg);
          put_str(action, hibyte, arg);
          }
          }
        else if (c == 'c') {
        else if (c == 'c') {
          send(action, arg);
          send(action, arg);
          }
          }
        else
        else
          BX_PANIC("bios_printf: unknown format\n");
          BX_PANIC("bios_printf: unknown format\n");
          in_format = 0;
          in_format = 0;
        }
        }
      }
      }
    else {
    else {
      send(action, c);
      send(action, c);
      }
      }
    s ++;
    s ++;
    }
    }
 
 
  if (action & BIOS_PRINTF_HALT) {
  if (action & BIOS_PRINTF_HALT) {
    // freeze in a busy loop.
    // freeze in a busy loop.
ASM_START
ASM_START
    cli
    cli
 halt2_loop:
 halt2_loop:
    hlt
    hlt
    jmp halt2_loop
    jmp halt2_loop
ASM_END
ASM_END
    }
    }
}
}
 
 
static char bios_svn_version_string[] = "$Revision: 1.13 $ $Date: 2009-03-05 00:26:53 $";
static char bios_svn_version_string[] = "$Revision: 1.13 $ $Date: 2009-03-05 00:26:53 $";
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// print_bios_banner
// print_bios_banner
//   displays a the bios version
//   displays a the bios version
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
void
void
print_bios_banner()
print_bios_banner()
{
{
  printf("Zet ROMBIOS - build: %s\n%s\n\n",
  printf("Zet ROMBIOS - build: %s\n%s\n\n",
    BIOS_BUILD_DATE, bios_svn_version_string);
    BIOS_BUILD_DATE, bios_svn_version_string);
}
}
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// BIOS Boot Specification 1.0.1 compatibility
// BIOS Boot Specification 1.0.1 compatibility
//
//
// Very basic support for the BIOS Boot Specification, which allows expansion
// Very basic support for the BIOS Boot Specification, which allows expansion
// ROMs to register themselves as boot devices, instead of just stealing the
// ROMs to register themselves as boot devices, instead of just stealing the
// INT 19h boot vector.
// INT 19h boot vector.
//
//
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
// one; we just lie to the option ROMs to make them behave correctly.
// one; we just lie to the option ROMs to make them behave correctly.
// We also don't support letting option ROMs register as bootable disk
// We also don't support letting option ROMs register as bootable disk
// drives (BCVs), only as bootable devices (BEVs).
// drives (BCVs), only as bootable devices (BEVs).
//
//
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
 
 
static char drivetypes[][20]={"", "Floppy flash image" };
static char drivetypes[][20]={"", "Floppy flash image" };
 
 
static void
static void
init_boot_vectors()
init_boot_vectors()
{
{
  ipl_entry_t e;
  ipl_entry_t e;
  Bit16u count = 0;
  Bit16u count = 0;
  Bit16u ss = get_SS();
  Bit16u ss = get_SS();
 
 
  /* Clear out the IPL table. */
  /* Clear out the IPL table. */
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
 
 
  /* User selected device not set */
  /* User selected device not set */
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
 
 
  /* Floppy drive */
  /* Floppy drive */
  e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
  e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
  count++;
  count++;
 
 
  /* Remember how many devices we have */
  /* Remember how many devices we have */
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
  /* Not tried booting anything yet */
  /* Not tried booting anything yet */
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
}
}
 
 
static Bit8u
static Bit8u
get_boot_vector(i, e)
get_boot_vector(i, e)
Bit16u i; ipl_entry_t *e;
Bit16u i; ipl_entry_t *e;
{
{
  Bit16u count;
  Bit16u count;
  Bit16u ss = get_SS();
  Bit16u ss = get_SS();
  /* Get the count of boot devices, and refuse to overrun the array */
  /* Get the count of boot devices, and refuse to overrun the array */
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
  if (i >= count) return 0;
  if (i >= count) return 0;
  /* OK to read this device */
  /* OK to read this device */
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
  return 1;
  return 1;
}
}
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// print_boot_device
// print_boot_device
//   displays the boot device
//   displays the boot device
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
 
 
void
void
print_boot_device(e)
print_boot_device(e)
  ipl_entry_t *e;
  ipl_entry_t *e;
{
{
  Bit16u type;
  Bit16u type;
  char description[33];
  char description[33];
  Bit16u ss = get_SS();
  Bit16u ss = get_SS();
  type = e->type;
  type = e->type;
  /* NIC appears as type 0x80 */
  /* NIC appears as type 0x80 */
  if (type == IPL_TYPE_BEV) type = 0x4;
  if (type == IPL_TYPE_BEV) type = 0x4;
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
  printf("Booting from %s", drivetypes[type]);
  printf("Booting from %s", drivetypes[type]);
  /* print product string if BEV */
  /* print product string if BEV */
  if (type == 4 && e->description != 0) {
  if (type == 4 && e->description != 0) {
    /* first 32 bytes are significant */
    /* first 32 bytes are significant */
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
    /* terminate string */
    /* terminate string */
    description[32] = 0;
    description[32] = 0;
    printf(" [%S]", ss, description);
    printf(" [%S]", ss, description);
  }
  }
  printf("...\n\n");
  printf("...\n\n");
}
}
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// print_boot_failure
// print_boot_failure
//   displays the reason why boot failed
//   displays the reason why boot failed
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
  void
  void
print_boot_failure(type, reason)
print_boot_failure(type, reason)
  Bit16u type; Bit8u reason;
  Bit16u type; Bit8u reason;
{
{
  if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
  if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
 
 
  printf("Boot failed");
  printf("Boot failed");
  if (type < 4) {
  if (type < 4) {
    /* Report the reason too */
    /* Report the reason too */
    if (reason==0)
    if (reason==0)
      printf(": not a bootable disk");
      printf(": not a bootable disk");
    else
    else
      printf(": could not read the boot disk");
      printf(": could not read the boot disk");
  }
  }
  printf("\n\n");
  printf("\n\n");
}
}
 
 
 
 
  void
  void
int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
{
{
  Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
  Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
  Bit16u kbd_code, max;
  Bit16u kbd_code, max;
 
 
  shift_flags = read_byte(0x0040, 0x17);
  shift_flags = read_byte(0x0040, 0x17);
  led_flags = read_byte(0x0040, 0x97);
  led_flags = read_byte(0x0040, 0x97);
 
 
  switch (GET_AH()) {
  switch (GET_AH()) {
    case 0x00: /* read keyboard input */
    case 0x00: /* read keyboard input */
 
 
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
        BX_PANIC("KBD: int16h: out of keyboard input\n");
        BX_PANIC("KBD: int16h: out of keyboard input\n");
        }
        }
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      else if (ascii_code == 0xE0) ascii_code = 0;
      else if (ascii_code == 0xE0) ascii_code = 0;
      AX = (scan_code << 8) | ascii_code;
      AX = (scan_code << 8) | ascii_code;
      break;
      break;
 
 
    case 0x01: /* check keyboard status */
    case 0x01: /* check keyboard status */
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
        SET_ZF();
        SET_ZF();
        return;
        return;
        }
        }
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      else if (ascii_code == 0xE0) ascii_code = 0;
      else if (ascii_code == 0xE0) ascii_code = 0;
      AX = (scan_code << 8) | ascii_code;
      AX = (scan_code << 8) | ascii_code;
      CLEAR_ZF();
      CLEAR_ZF();
      break;
      break;
 
 
    case 0x02: /* get shift flag status */
    case 0x02: /* get shift flag status */
      shift_flags = read_byte(0x0040, 0x17);
      shift_flags = read_byte(0x0040, 0x17);
      SET_AL(shift_flags);
      SET_AL(shift_flags);
      break;
      break;
 
 
    case 0x05: /* store key-stroke into buffer */
    case 0x05: /* store key-stroke into buffer */
      if ( !enqueue_key(GET_CH(), GET_CL()) ) {
      if ( !enqueue_key(GET_CH(), GET_CL()) ) {
        SET_AL(1);
        SET_AL(1);
        }
        }
      else {
      else {
        SET_AL(0);
        SET_AL(0);
        }
        }
      break;
      break;
 
 
    case 0x09: /* GET KEYBOARD FUNCTIONALITY */
    case 0x09: /* GET KEYBOARD FUNCTIONALITY */
      // bit Bochs Description
      // bit Bochs Description
      //  7    0   reserved
      //  7    0   reserved
      //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
      //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
      //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
      //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
      //  4    1   INT 16/AH=0Ah supported
      //  4    1   INT 16/AH=0Ah supported
      //  3    0   INT 16/AX=0306h supported
      //  3    0   INT 16/AX=0306h supported
      //  2    0   INT 16/AX=0305h supported
      //  2    0   INT 16/AX=0305h supported
      //  1    0   INT 16/AX=0304h supported
      //  1    0   INT 16/AX=0304h supported
      //  0    0   INT 16/AX=0300h supported
      //  0    0   INT 16/AX=0300h supported
      //
      //
      SET_AL(0x30);
      SET_AL(0x30);
      break;
      break;
 
 
    case 0x10: /* read MF-II keyboard input */
    case 0x10: /* read MF-II keyboard input */
 
 
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
        BX_PANIC("KBD: int16h: out of keyboard input\n");
        BX_PANIC("KBD: int16h: out of keyboard input\n");
        }
        }
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      AX = (scan_code << 8) | ascii_code;
      AX = (scan_code << 8) | ascii_code;
      break;
      break;
 
 
    case 0x11: /* check MF-II keyboard status */
    case 0x11: /* check MF-II keyboard status */
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
        SET_ZF();
        SET_ZF();
        return;
        return;
        }
        }
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
      AX = (scan_code << 8) | ascii_code;
      AX = (scan_code << 8) | ascii_code;
      CLEAR_ZF();
      CLEAR_ZF();
      break;
      break;
 
 
    case 0x12: /* get extended keyboard status */
    case 0x12: /* get extended keyboard status */
      shift_flags = read_byte(0x0040, 0x17);
      shift_flags = read_byte(0x0040, 0x17);
      SET_AL(shift_flags);
      SET_AL(shift_flags);
      shift_flags = read_byte(0x0040, 0x18) & 0x73;
      shift_flags = read_byte(0x0040, 0x18) & 0x73;
      shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
      shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
      SET_AH(shift_flags);
      SET_AH(shift_flags);
      BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
      BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
      break;
      break;
 
 
    case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
    case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
      SET_AH(0x80); // function int16 ah=0x10-0x12 supported
      SET_AH(0x80); // function int16 ah=0x10-0x12 supported
      break;
      break;
 
 
    case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
    case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
      // don't change AH : function int16 ah=0x20-0x22 NOT supported
      // don't change AH : function int16 ah=0x20-0x22 NOT supported
      break;
      break;
 
 
    case 0x6F:
    case 0x6F:
      if (GET_AL() == 0x08)
      if (GET_AL() == 0x08)
        SET_AH(0x02); // unsupported, aka normal keyboard
        SET_AH(0x02); // unsupported, aka normal keyboard
 
 
    default:
    default:
      BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
      BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
    }
    }
}
}
 
 
  unsigned int
  unsigned int
dequeue_key(scan_code, ascii_code, incr)
dequeue_key(scan_code, ascii_code, incr)
  Bit8u *scan_code;
  Bit8u *scan_code;
  Bit8u *ascii_code;
  Bit8u *ascii_code;
  unsigned int incr;
  unsigned int incr;
{
{
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
  Bit16u ss;
  Bit16u ss;
  Bit8u  acode, scode;
  Bit8u  acode, scode;
 
 
#if BX_CPU < 2
#if BX_CPU < 2
  buffer_start = 0x001E;
  buffer_start = 0x001E;
  buffer_end   = 0x003E;
  buffer_end   = 0x003E;
#else
#else
  buffer_start = read_word(0x0040, 0x0080);
  buffer_start = read_word(0x0040, 0x0080);
  buffer_end   = read_word(0x0040, 0x0082);
  buffer_end   = read_word(0x0040, 0x0082);
#endif
#endif
 
 
  buffer_head = read_word(0x0040, 0x001a);
  buffer_head = read_word(0x0040, 0x001a);
  buffer_tail = read_word(0x0040, 0x001c);
  buffer_tail = read_word(0x0040, 0x001c);
 
 
  if (buffer_head != buffer_tail) {
  if (buffer_head != buffer_tail) {
    ss = get_SS();
    ss = get_SS();
    acode = read_byte(0x0040, buffer_head);
    acode = read_byte(0x0040, buffer_head);
    scode = read_byte(0x0040, buffer_head+1);
    scode = read_byte(0x0040, buffer_head+1);
    write_byte(ss, ascii_code, acode);
    write_byte(ss, ascii_code, acode);
    write_byte(ss, scan_code, scode);
    write_byte(ss, scan_code, scode);
 
 
    if (incr) {
    if (incr) {
      buffer_head += 2;
      buffer_head += 2;
      if (buffer_head >= buffer_end)
      if (buffer_head >= buffer_end)
        buffer_head = buffer_start;
        buffer_head = buffer_start;
      write_word(0x0040, 0x001a, buffer_head);
      write_word(0x0040, 0x001a, buffer_head);
      }
      }
    return(1);
    return(1);
    }
    }
  else {
  else {
    return(0);
    return(0);
    }
    }
}
}
 
 
  void
  void
int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
{
{
  Bit8u scancode, asciicode, shift_flags;
  Bit8u scancode, asciicode, shift_flags;
  Bit8u mf2_flags, mf2_state;
  Bit8u mf2_flags, mf2_state;
 
 
  //
  //
  // DS has been set to F000 before call
  // DS has been set to F000 before call
  //
  //
 
 
 
 
  scancode = GET_AL();
  scancode = GET_AL();
 
 
  if (scancode == 0) {
  if (scancode == 0) {
    BX_INFO("KBD: int09 handler: AL=0\n");
    BX_INFO("KBD: int09 handler: AL=0\n");
    return;
    return;
    }
    }
 
 
 
 
  shift_flags = read_byte(0x0040, 0x17);
  shift_flags = read_byte(0x0040, 0x17);
  mf2_flags = read_byte(0x0040, 0x18);
  mf2_flags = read_byte(0x0040, 0x18);
  mf2_state = read_byte(0x0040, 0x96);
  mf2_state = read_byte(0x0040, 0x96);
  asciicode = 0;
  asciicode = 0;
 
 
  switch (scancode) {
  switch (scancode) {
    case 0x3a: /* Caps Lock press */
    case 0x3a: /* Caps Lock press */
      shift_flags ^= 0x40;
      shift_flags ^= 0x40;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      mf2_flags |= 0x40;
      mf2_flags |= 0x40;
      write_byte(0x0040, 0x18, mf2_flags);
      write_byte(0x0040, 0x18, mf2_flags);
      break;
      break;
    case 0xba: /* Caps Lock release */
    case 0xba: /* Caps Lock release */
      mf2_flags &= ~0x40;
      mf2_flags &= ~0x40;
      write_byte(0x0040, 0x18, mf2_flags);
      write_byte(0x0040, 0x18, mf2_flags);
      break;
      break;
 
 
    case 0x2a: /* L Shift press */
    case 0x2a: /* L Shift press */
      shift_flags |= 0x02;
      shift_flags |= 0x02;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      break;
      break;
    case 0xaa: /* L Shift release */
    case 0xaa: /* L Shift release */
      shift_flags &= ~0x02;
      shift_flags &= ~0x02;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      break;
      break;
 
 
    case 0x36: /* R Shift press */
    case 0x36: /* R Shift press */
      shift_flags |= 0x01;
      shift_flags |= 0x01;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      break;
      break;
    case 0xb6: /* R Shift release */
    case 0xb6: /* R Shift release */
      shift_flags &= ~0x01;
      shift_flags &= ~0x01;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      break;
      break;
 
 
    case 0x1d: /* Ctrl press */
    case 0x1d: /* Ctrl press */
      if ((mf2_state & 0x01) == 0) {
      if ((mf2_state & 0x01) == 0) {
        shift_flags |= 0x04;
        shift_flags |= 0x04;
        write_byte(0x0040, 0x17, shift_flags);
        write_byte(0x0040, 0x17, shift_flags);
        if (mf2_state & 0x02) {
        if (mf2_state & 0x02) {
          mf2_state |= 0x04;
          mf2_state |= 0x04;
          write_byte(0x0040, 0x96, mf2_state);
          write_byte(0x0040, 0x96, mf2_state);
        } else {
        } else {
          mf2_flags |= 0x01;
          mf2_flags |= 0x01;
          write_byte(0x0040, 0x18, mf2_flags);
          write_byte(0x0040, 0x18, mf2_flags);
        }
        }
      }
      }
      break;
      break;
    case 0x9d: /* Ctrl release */
    case 0x9d: /* Ctrl release */
      if ((mf2_state & 0x01) == 0) {
      if ((mf2_state & 0x01) == 0) {
        shift_flags &= ~0x04;
        shift_flags &= ~0x04;
        write_byte(0x0040, 0x17, shift_flags);
        write_byte(0x0040, 0x17, shift_flags);
        if (mf2_state & 0x02) {
        if (mf2_state & 0x02) {
          mf2_state &= ~0x04;
          mf2_state &= ~0x04;
          write_byte(0x0040, 0x96, mf2_state);
          write_byte(0x0040, 0x96, mf2_state);
        } else {
        } else {
          mf2_flags &= ~0x01;
          mf2_flags &= ~0x01;
          write_byte(0x0040, 0x18, mf2_flags);
          write_byte(0x0040, 0x18, mf2_flags);
        }
        }
      }
      }
      break;
      break;
 
 
    case 0x38: /* Alt press */
    case 0x38: /* Alt press */
      shift_flags |= 0x08;
      shift_flags |= 0x08;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      if (mf2_state & 0x02) {
      if (mf2_state & 0x02) {
        mf2_state |= 0x08;
        mf2_state |= 0x08;
        write_byte(0x0040, 0x96, mf2_state);
        write_byte(0x0040, 0x96, mf2_state);
      } else {
      } else {
        mf2_flags |= 0x02;
        mf2_flags |= 0x02;
        write_byte(0x0040, 0x18, mf2_flags);
        write_byte(0x0040, 0x18, mf2_flags);
      }
      }
      break;
      break;
    case 0xb8: /* Alt release */
    case 0xb8: /* Alt release */
      shift_flags &= ~0x08;
      shift_flags &= ~0x08;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      if (mf2_state & 0x02) {
      if (mf2_state & 0x02) {
        mf2_state &= ~0x08;
        mf2_state &= ~0x08;
        write_byte(0x0040, 0x96, mf2_state);
        write_byte(0x0040, 0x96, mf2_state);
      } else {
      } else {
        mf2_flags &= ~0x02;
        mf2_flags &= ~0x02;
        write_byte(0x0040, 0x18, mf2_flags);
        write_byte(0x0040, 0x18, mf2_flags);
      }
      }
      break;
      break;
 
 
    case 0x45: /* Num Lock press */
    case 0x45: /* Num Lock press */
      if ((mf2_state & 0x03) == 0) {
      if ((mf2_state & 0x03) == 0) {
        mf2_flags |= 0x20;
        mf2_flags |= 0x20;
        write_byte(0x0040, 0x18, mf2_flags);
        write_byte(0x0040, 0x18, mf2_flags);
        shift_flags ^= 0x20;
        shift_flags ^= 0x20;
        write_byte(0x0040, 0x17, shift_flags);
        write_byte(0x0040, 0x17, shift_flags);
      }
      }
      break;
      break;
    case 0xc5: /* Num Lock release */
    case 0xc5: /* Num Lock release */
      if ((mf2_state & 0x03) == 0) {
      if ((mf2_state & 0x03) == 0) {
        mf2_flags &= ~0x20;
        mf2_flags &= ~0x20;
        write_byte(0x0040, 0x18, mf2_flags);
        write_byte(0x0040, 0x18, mf2_flags);
      }
      }
      break;
      break;
 
 
    case 0x46: /* Scroll Lock press */
    case 0x46: /* Scroll Lock press */
      mf2_flags |= 0x10;
      mf2_flags |= 0x10;
      write_byte(0x0040, 0x18, mf2_flags);
      write_byte(0x0040, 0x18, mf2_flags);
      shift_flags ^= 0x10;
      shift_flags ^= 0x10;
      write_byte(0x0040, 0x17, shift_flags);
      write_byte(0x0040, 0x17, shift_flags);
      break;
      break;
 
 
    case 0xc6: /* Scroll Lock release */
    case 0xc6: /* Scroll Lock release */
      mf2_flags &= ~0x10;
      mf2_flags &= ~0x10;
      write_byte(0x0040, 0x18, mf2_flags);
      write_byte(0x0040, 0x18, mf2_flags);
      break;
      break;
 
 
    default:
    default:
      if (scancode & 0x80) {
      if (scancode & 0x80) {
        break; /* toss key releases ... */
        break; /* toss key releases ... */
      }
      }
      if (scancode > MAX_SCAN_CODE) {
      if (scancode > MAX_SCAN_CODE) {
        BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
        BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
        return;
        return;
      }
      }
      if (shift_flags & 0x08) { /* ALT */
      if (shift_flags & 0x08) { /* ALT */
        asciicode = scan_to_scanascii[scancode].alt;
        asciicode = scan_to_scanascii[scancode].alt;
        scancode = scan_to_scanascii[scancode].alt >> 8;
        scancode = scan_to_scanascii[scancode].alt >> 8;
      } else if (shift_flags & 0x04) { /* CONTROL */
      } else if (shift_flags & 0x04) { /* CONTROL */
        asciicode = scan_to_scanascii[scancode].control;
        asciicode = scan_to_scanascii[scancode].control;
        scancode = scan_to_scanascii[scancode].control >> 8;
        scancode = scan_to_scanascii[scancode].control >> 8;
      } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
      } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
        /* extended keys handling */
        /* extended keys handling */
        asciicode = 0xe0;
        asciicode = 0xe0;
        scancode = scan_to_scanascii[scancode].normal >> 8;
        scancode = scan_to_scanascii[scancode].normal >> 8;
      } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
      } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
        /* check if lock state should be ignored
        /* check if lock state should be ignored
         * because a SHIFT key are pressed */
         * because a SHIFT key are pressed */
 
 
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
          asciicode = scan_to_scanascii[scancode].normal;
          asciicode = scan_to_scanascii[scancode].normal;
          scancode = scan_to_scanascii[scancode].normal >> 8;
          scancode = scan_to_scanascii[scancode].normal >> 8;
        } else {
        } else {
          asciicode = scan_to_scanascii[scancode].shift;
          asciicode = scan_to_scanascii[scancode].shift;
          scancode = scan_to_scanascii[scancode].shift >> 8;
          scancode = scan_to_scanascii[scancode].shift >> 8;
        }
        }
      } else {
      } else {
        /* check if lock is on */
        /* check if lock is on */
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
          asciicode = scan_to_scanascii[scancode].shift;
          asciicode = scan_to_scanascii[scancode].shift;
          scancode = scan_to_scanascii[scancode].shift >> 8;
          scancode = scan_to_scanascii[scancode].shift >> 8;
        } else {
        } else {
          asciicode = scan_to_scanascii[scancode].normal;
          asciicode = scan_to_scanascii[scancode].normal;
          scancode = scan_to_scanascii[scancode].normal >> 8;
          scancode = scan_to_scanascii[scancode].normal >> 8;
        }
        }
      }
      }
      if (scancode==0 && asciicode==0) {
      if (scancode==0 && asciicode==0) {
        BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
        BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
      }
      }
      enqueue_key(scancode, asciicode);
      enqueue_key(scancode, asciicode);
      break;
      break;
  }
  }
  if ((scancode & 0x7f) != 0x1d) {
  if ((scancode & 0x7f) != 0x1d) {
    mf2_state &= ~0x01;
    mf2_state &= ~0x01;
  }
  }
  mf2_state &= ~0x02;
  mf2_state &= ~0x02;
  write_byte(0x0040, 0x96, mf2_state);
  write_byte(0x0040, 0x96, mf2_state);
}
}
 
 
  unsigned int
  unsigned int
enqueue_key(scan_code, ascii_code)
enqueue_key(scan_code, ascii_code)
  Bit8u scan_code, ascii_code;
  Bit8u scan_code, ascii_code;
{
{
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
 
 
#if BX_CPU < 2
#if BX_CPU < 2
  buffer_start = 0x001E;
  buffer_start = 0x001E;
  buffer_end   = 0x003E;
  buffer_end   = 0x003E;
#else
#else
  buffer_start = read_word(0x0040, 0x0080);
  buffer_start = read_word(0x0040, 0x0080);
  buffer_end   = read_word(0x0040, 0x0082);
  buffer_end   = read_word(0x0040, 0x0082);
#endif
#endif
 
 
  buffer_head = read_word(0x0040, 0x001A);
  buffer_head = read_word(0x0040, 0x001A);
  buffer_tail = read_word(0x0040, 0x001C);
  buffer_tail = read_word(0x0040, 0x001C);
 
 
  temp_tail = buffer_tail;
  temp_tail = buffer_tail;
  buffer_tail += 2;
  buffer_tail += 2;
  if (buffer_tail >= buffer_end)
  if (buffer_tail >= buffer_end)
    buffer_tail = buffer_start;
    buffer_tail = buffer_start;
 
 
  if (buffer_tail == buffer_head) {
  if (buffer_tail == buffer_head) {
    return(0);
    return(0);
    }
    }
 
 
   write_byte(0x0040, temp_tail, ascii_code);
   write_byte(0x0040, temp_tail, ascii_code);
   write_byte(0x0040, temp_tail+1, scan_code);
   write_byte(0x0040, temp_tail+1, scan_code);
   write_word(0x0040, 0x001C, buffer_tail);
   write_word(0x0040, 0x001C, buffer_tail);
   return(1);
   return(1);
}
}
 
 
 
 
#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
 
 
  void
  void
int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
{
{
  write_byte(0x0040, 0x008e, 0);  // clear completion flag
  write_byte(0x0040, 0x008e, 0);  // clear completion flag
 
 
  switch (GET_AH()) {
  switch (GET_AH()) {
    case 0x08:
    case 0x08:
      SET_AL(0);
      SET_AL(0);
      SET_CH(0);
      SET_CH(0);
      SET_CL(0);
      SET_CL(0);
      SET_DH(0);
      SET_DH(0);
      SET_DL(0); /* FIXME returns 0, 1, or n hard drives */
      SET_DL(0); /* FIXME returns 0, 1, or n hard drives */
 
 
      // FIXME should set ES & DI
      // FIXME should set ES & DI
 
 
      goto int13_fail;
      goto int13_fail;
      break;
      break;
 
 
    default:
    default:
      BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
      BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
      goto int13_fail;
      goto int13_fail;
      break;
      break;
    }
    }
 
 
int13_fail:
int13_fail:
    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
int13_fail_noah:
int13_fail_noah:
    SET_DISK_RET_STATUS(GET_AH());
    SET_DISK_RET_STATUS(GET_AH());
int13_fail_nostatus:
int13_fail_nostatus:
    SET_CF();     // error occurred
    SET_CF();     // error occurred
    return;
    return;
 
 
int13_success:
int13_success:
    SET_AH(0x00); // no error
    SET_AH(0x00); // no error
int13_success_noah:
int13_success_noah:
    SET_DISK_RET_STATUS(0x00);
    SET_DISK_RET_STATUS(0x00);
    CLEAR_CF();   // no error
    CLEAR_CF();   // no error
    return;
    return;
}
}
 
 
  void
  void
transf_sect(seg, offset)
transf_sect(seg, offset)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push ax
    push ax
    push bx
    push bx
    push cx
    push cx
    push dx
    push dx
    push di
    push di
    push ds
    push ds
 
 
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  dx, #0xe000
    mov  dx, #0xe000
    mov  cx, #256
    mov  cx, #256
    xor  di, di
    xor  di, di
 
 
one_sect:
one_sect:
    in   ax, dx    ; read word from flash
    in   ax, dx    ; read word from flash
    mov  [bx+di], ax ; write word
    mov  [bx+di], ax ; write word
    inc  dx
    inc  dx
    inc  dx
    inc  dx
    inc  di
    inc  di
    inc  di
    inc  di
    loop one_sect
    loop one_sect
 
 
    pop  ds
    pop  ds
    pop  di
    pop  di
    pop  dx
    pop  dx
    pop  cx
    pop  cx
    pop  bx
    pop  bx
    pop  ax
    pop  ax
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  void
  void
int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
{
{
  Bit8u  drive, num_sectors, track, sector, head, status;
  Bit8u  drive, num_sectors, track, sector, head, status;
  Bit16u base_address, base_count, base_es;
  Bit16u base_address, base_count, base_es;
  Bit8u  page, mode_register, val8, dor;
  Bit8u  page, mode_register, val8, dor;
  Bit8u  return_status[7];
  Bit8u  return_status[7];
  Bit8u  drive_type, num_floppies, ah;
  Bit8u  drive_type, num_floppies, ah;
  Bit16u es, last_addr;
  Bit16u es, last_addr;
  Bit16u log_sector, tmp, i, j;
  Bit16u log_sector, tmp, i, j;
 
 
  ah = GET_AH();
  ah = GET_AH();
 
 
  switch ( ah ) {
  switch ( ah ) {
    case 0x00: // diskette controller reset
    case 0x00: // diskette controller reset
      SET_AH(0);
      SET_AH(0);
      set_diskette_ret_status(0);
      set_diskette_ret_status(0);
      CLEAR_CF(); // successful
      CLEAR_CF(); // successful
      set_diskette_current_cyl(drive, 0); // current cylinder
      set_diskette_current_cyl(drive, 0); // current cylinder
      return;
      return;
 
 
    case 0x02: // Read Diskette Sectors
    case 0x02: // Read Diskette Sectors
      num_sectors = GET_AL();
      num_sectors = GET_AL();
      track       = GET_CH();
      track       = GET_CH();
      sector      = GET_CL();
      sector      = GET_CL();
      head        = GET_DH();
      head        = GET_DH();
      drive       = GET_ELDL();
      drive       = GET_ELDL();
 
 
      if ((drive > 1) || (head > 1) || (sector == 0) ||
      if ((drive > 1) || (head > 1) || (sector == 0) ||
          (num_sectors == 0) || (num_sectors > 72)) {
          (num_sectors == 0) || (num_sectors > 72)) {
        BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
        BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
        SET_AH(1);
        SET_AH(1);
        set_diskette_ret_status(1);
        set_diskette_ret_status(1);
        SET_AL(0); // no sectors read
        SET_AL(0); // no sectors read
        SET_CF(); // error occurred
        SET_CF(); // error occurred
        return;
        return;
      }
      }
 
 
        page = (ES >> 12);   // upper 4 bits
        page = (ES >> 12);   // upper 4 bits
        base_es = (ES << 4); // lower 16bits contributed by ES
        base_es = (ES << 4); // lower 16bits contributed by ES
        base_address = base_es + BX; // lower 16 bits of address
        base_address = base_es + BX; // lower 16 bits of address
                                     // contributed by ES:BX
                                     // contributed by ES:BX
        if ( base_address < base_es ) {
        if ( base_address < base_es ) {
          // in case of carry, adjust page by 1
          // in case of carry, adjust page by 1
          page++;
          page++;
        }
        }
        base_count = (num_sectors * 512) - 1;
        base_count = (num_sectors * 512) - 1;
 
 
        // check for 64K boundary overrun
        // check for 64K boundary overrun
        last_addr = base_address + base_count;
        last_addr = base_address + base_count;
        if (last_addr < base_address) {
        if (last_addr < base_address) {
          SET_AH(0x09);
          SET_AH(0x09);
          set_diskette_ret_status(0x09);
          set_diskette_ret_status(0x09);
          SET_AL(0); // no sectors read
          SET_AL(0); // no sectors read
          SET_CF(); // error occurred
          SET_CF(); // error occurred
          return;
          return;
        }
        }
 
 
        log_sector = track * 36 + head * 18 + sector - 1;
        log_sector = track * 36 + head * 18 + sector - 1;
        last_addr = page << 12;
        last_addr = page << 12;
 
 
        // Configure the sector address
        // Configure the sector address
        for (j=0; j<num_sectors; j++)
        for (j=0; j<num_sectors; j++)
          {
          {
            outw(0xe000, log_sector+j);
            outw(0xe000, log_sector+j);
            base_count = base_address + (j << 9);
            base_count = base_address + (j << 9);
            transf_sect (last_addr, base_count);
            transf_sect (last_addr, base_count);
          }
          }
 
 
        // ??? should track be new val from return_status[3] ?
        // ??? should track be new val from return_status[3] ?
        set_diskette_current_cyl(drive, track);
        set_diskette_current_cyl(drive, track);
        // AL = number of sectors read (same value as passed)
        // AL = number of sectors read (same value as passed)
        SET_AH(0x00); // success
        SET_AH(0x00); // success
        CLEAR_CF();   // success
        CLEAR_CF();   // success
        return;
        return;
    default:
    default:
        BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
        BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
 
 
      // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
      // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
        SET_AH(0x01); // ???
        SET_AH(0x01); // ???
        set_diskette_ret_status(1);
        set_diskette_ret_status(1);
        SET_CF();
        SET_CF();
        return;
        return;
      //   }
      //   }
    }
    }
}
}
 
 
 void
 void
set_diskette_ret_status(value)
set_diskette_ret_status(value)
  Bit8u value;
  Bit8u value;
{
{
  write_byte(0x0040, 0x0041, value);
  write_byte(0x0040, 0x0041, value);
}
}
 
 
  void
  void
set_diskette_current_cyl(drive, cyl)
set_diskette_current_cyl(drive, cyl)
  Bit8u drive;
  Bit8u drive;
  Bit8u cyl;
  Bit8u cyl;
{
{
/* TEMP HACK: FOR MSDOS */
/* TEMP HACK: FOR MSDOS */
  if (drive > 1)
  if (drive > 1)
    drive = 1;
    drive = 1;
  /*  BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); */
  /*  BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); */
  write_byte(0x0040, 0x0094+drive, cyl);
  write_byte(0x0040, 0x0094+drive, cyl);
}
}
 
 
void
void
int19_function(seq_nr)
int19_function(seq_nr)
Bit16u seq_nr;
Bit16u seq_nr;
{
{
  Bit16u ebda_seg=read_word(0x0040,0x000E);
  Bit16u ebda_seg=read_word(0x0040,0x000E);
  Bit16u bootdev;
  Bit16u bootdev;
  Bit8u  bootdrv;
  Bit8u  bootdrv;
  Bit8u  bootchk;
  Bit8u  bootchk;
  Bit16u bootseg;
  Bit16u bootseg;
  Bit16u bootip;
  Bit16u bootip;
  Bit16u status;
  Bit16u status;
  Bit16u bootfirst;
  Bit16u bootfirst;
 
 
  ipl_entry_t e;
  ipl_entry_t e;
 
 
  // Here we assume that BX_ELTORITO_BOOT is defined, so
  // Here we assume that BX_ELTORITO_BOOT is defined, so
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
  //     CMOS reg 0x3D & 0x0f : 1st boot device
  //     CMOS reg 0x3D & 0x0f : 1st boot device
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
  //   boot device codes:
  //   boot device codes:
  //     0x00 : not defined
  //     0x00 : not defined
  //     0x01 : first floppy
  //     0x01 : first floppy
  //     0x02 : first harddrive
  //     0x02 : first harddrive
  //     0x03 : first cdrom
  //     0x03 : first cdrom
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
  //     else : boot failure
  //     else : boot failure
 
 
  // Get the boot sequence
  // Get the boot sequence
/*
/*
 * Zet: we don't have a CMOS device
 * Zet: we don't have a CMOS device
 *
 *
  bootdev = inb_cmos(0x3d);
  bootdev = inb_cmos(0x3d);
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
  bootdev >>= 4 * seq_nr;
  bootdev >>= 4 * seq_nr;
  bootdev &= 0xf;
  bootdev &= 0xf;
*/
*/
  bootdev = 0x1;
  bootdev = 0x1;
 
 
  /* Read user selected device */
  /* Read user selected device */
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
  if (bootfirst != 0xFFFF) {
  if (bootfirst != 0xFFFF) {
    bootdev = bootfirst;
    bootdev = bootfirst;
    /* User selected device not set */
    /* User selected device not set */
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
    /* Reset boot sequence */
    /* Reset boot sequence */
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
 
 
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
  bootdev -= 1;
  bootdev -= 1;
 
 
  /* Read the boot device from the IPL table */
  /* Read the boot device from the IPL table */
  if (get_boot_vector(bootdev, &e) == 0) {
  if (get_boot_vector(bootdev, &e) == 0) {
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
    return;
    return;
  }
  }
 
 
  /* Do the loading, and set up vector as a far pointer to the boot
  /* Do the loading, and set up vector as a far pointer to the boot
   * address, and bootdrv as the boot drive */
   * address, and bootdrv as the boot drive */
  print_boot_device(&e);
  print_boot_device(&e);
 
 
  switch(e.type) {
  switch(e.type) {
  case IPL_TYPE_FLOPPY: /* FDD */
  case IPL_TYPE_FLOPPY: /* FDD */
  case IPL_TYPE_HARDDISK: /* HDD */
  case IPL_TYPE_HARDDISK: /* HDD */
 
 
    bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
    bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
    bootseg = 0x07c0;
    bootseg = 0x07c0;
    status = 0;
    status = 0;
 
 
ASM_START
ASM_START
    push bp
    push bp
    mov  bp, sp
    mov  bp, sp
    push ax
    push ax
    push bx
    push bx
    push cx
    push cx
    push dx
    push dx
 
 
    mov  dl, _int19_function.bootdrv + 2[bp]
    mov  dl, _int19_function.bootdrv + 2[bp]
    mov  ax, _int19_function.bootseg + 2[bp]
    mov  ax, _int19_function.bootseg + 2[bp]
    mov  es, ax         ;; segment
    mov  es, ax         ;; segment
    xor  bx, bx         ;; offset
    xor  bx, bx         ;; offset
    mov  ah, #0x02      ;; function 2, read diskette sector
    mov  ah, #0x02      ;; function 2, read diskette sector
    mov  al, #0x01      ;; read 1 sector
    mov  al, #0x01      ;; read 1 sector
    mov  ch, #0x00      ;; track 0
    mov  ch, #0x00      ;; track 0
    mov  cl, #0x01      ;; sector 1
    mov  cl, #0x01      ;; sector 1
    mov  dh, #0x00      ;; head 0
    mov  dh, #0x00      ;; head 0
    int  #0x13          ;; read sector
    int  #0x13          ;; read sector
    jnc  int19_load_done
    jnc  int19_load_done
    mov  ax, #0x0001
    mov  ax, #0x0001
    mov  _int19_function.status + 2[bp], ax
    mov  _int19_function.status + 2[bp], ax
 
 
int19_load_done:
int19_load_done:
    pop  dx
    pop  dx
    pop  cx
    pop  cx
    pop  bx
    pop  bx
    pop  ax
    pop  ax
    pop  bp
    pop  bp
ASM_END
ASM_END
 
 
    if (status != 0) {
    if (status != 0) {
      print_boot_failure(e.type, 1);
      print_boot_failure(e.type, 1);
      return;
      return;
    }
    }
 
 
    /* Canonicalize bootseg:bootip */
    /* Canonicalize bootseg:bootip */
    bootip = (bootseg & 0x0fff) << 4;
    bootip = (bootseg & 0x0fff) << 4;
    bootseg &= 0xf000;
    bootseg &= 0xf000;
  break;
  break;
 
 
  default: return;
  default: return;
  }
  }
 
 
  /* Debugging info */
  /* Debugging info */
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
 
 
  /* Jump to the boot vector */
  /* Jump to the boot vector */
ASM_START
ASM_START
    mov  bp, sp
    mov  bp, sp
    ;; Build an iret stack frame that will take us to the boot vector.
    ;; Build an iret stack frame that will take us to the boot vector.
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
    pushf
    pushf
    mov  ax, _int19_function.bootseg + 0[bp]
    mov  ax, _int19_function.bootseg + 0[bp]
    push ax
    push ax
    mov  ax, _int19_function.bootip + 0[bp]
    mov  ax, _int19_function.bootip + 0[bp]
    push ax
    push ax
    ;; Set the magic number in ax and the boot drive in dl.
    ;; Set the magic number in ax and the boot drive in dl.
    mov  ax, #0xaa55
    mov  ax, #0xaa55
    mov  dl, _int19_function.bootdrv + 0[bp]
    mov  dl, _int19_function.bootdrv + 0[bp]
    ;; Zero some of the other registers.
    ;; Zero some of the other registers.
    xor  bx, bx
    xor  bx, bx
    mov  ds, bx
    mov  ds, bx
    mov  es, bx
    mov  es, bx
    mov  bp, bx
    mov  bp, bx
    ;; Go!
    ;; Go!
    iret
    iret
ASM_END
ASM_END
}
}
 
 
  void
  void
int1a_function(regs, ds, iret_addr)
int1a_function(regs, ds, iret_addr)
  pusha_regs_t regs; // regs pushed from PUSHA instruction
  pusha_regs_t regs; // regs pushed from PUSHA instruction
  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
{
{
  Bit8u val8;
  Bit8u val8;
 
 
  ASM_START
  ASM_START
  sti
  sti
  ASM_END
  ASM_END
 
 
  switch (regs.u.r8.ah) {
  switch (regs.u.r8.ah) {
    case 0: // get current clock count
    case 0: // get current clock count
      ASM_START
      ASM_START
      cli
      cli
      ASM_END
      ASM_END
      regs.u.r16.cx = BiosData->ticks_high;
      regs.u.r16.cx = BiosData->ticks_high;
      regs.u.r16.dx = BiosData->ticks_low;
      regs.u.r16.dx = BiosData->ticks_low;
      regs.u.r8.al  = BiosData->midnight_flag;
      regs.u.r8.al  = BiosData->midnight_flag;
      BiosData->midnight_flag = 0; // reset flag
      BiosData->midnight_flag = 0; // reset flag
      ASM_START
      ASM_START
      sti
      sti
      ASM_END
      ASM_END
      // AH already 0
      // AH already 0
      ClearCF(iret_addr.flags); // OK
      ClearCF(iret_addr.flags); // OK
      break;
      break;
 
 
    default:
    default:
      SetCF(iret_addr.flags); // Unsupported
      SetCF(iret_addr.flags); // Unsupported
    }
    }
}
}
 
 
ASM_START
ASM_START
;----------------------
;----------------------
;- INT13h (relocated) -
;- INT13h (relocated) -
;----------------------
;----------------------
;
;
; int13_relocated is a little bit messed up since I played with it
; int13_relocated is a little bit messed up since I played with it
; I have to rewrite it:
; I have to rewrite it:
;   - call a function that detect which function to call
;   - call a function that detect which function to call
;   - make all called C function get the same parameters list
;   - make all called C function get the same parameters list
;
;
int13_relocated:
int13_relocated:
  push  ax
  push  ax
  push  cx
  push  cx
  push  dx
  push  dx
  push  bx
  push  bx
 
 
int13_legacy:
int13_legacy:
 
 
  push  dx                   ;; push eltorito value of dx instead of sp
  push  dx                   ;; push eltorito value of dx instead of sp
 
 
  push  bp
  push  bp
  push  si
  push  si
  push  di
  push  di
 
 
  push  es
  push  es
  push  ds
  push  ds
  push  ss
  push  ss
  pop   ds
  pop   ds
 
 
  ;; now the 16-bit registers can be restored with:
  ;; now the 16-bit registers can be restored with:
  ;; pop ds; pop es; popa; iret
  ;; pop ds; pop es; popa; iret
  ;; arguments passed to functions should be
  ;; arguments passed to functions should be
  ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
  ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
 
 
  test  dl, #0x80
  test  dl, #0x80
  jnz   int13_notfloppy
  jnz   int13_notfloppy
 
 
  mov  ax, #int13_out
  mov  ax, #int13_out
  push ax
  push ax
  jmp _int13_diskette_function
  jmp _int13_diskette_function
 
 
int13_notfloppy:
int13_notfloppy:
 
 
int13_disk:
int13_disk:
  ;; int13_harddisk modifies high word of EAX
  ;; int13_harddisk modifies high word of EAX
;  shr   eax, #16
;  shr   eax, #16
;  push  ax
;  push  ax
  call  _int13_harddisk
  call  _int13_harddisk
;  pop   ax
;  pop   ax
;  shl   eax, #16
;  shl   eax, #16
 
 
int13_out:
int13_out:
  pop ds
  pop ds
  pop es
  pop es
  ; popa ; we do this instead:
  ; popa ; we do this instead:
  pop di
  pop di
  pop si
  pop si
  pop bp
  pop bp
  add sp, #2
  add sp, #2
  pop bx
  pop bx
  pop dx
  pop dx
  pop cx
  pop cx
  pop ax
  pop ax
 
 
  iret
  iret
 
 
;----------
;----------
;- INT18h -
;- INT18h -
;----------
;----------
int18_handler: ;; Boot Failure recovery: try the next device.
int18_handler: ;; Boot Failure recovery: try the next device.
 
 
  ;; Reset SP and SS
  ;; Reset SP and SS
  mov  ax, #0xfffe
  mov  ax, #0xfffe
  mov  sp, ax
  mov  sp, ax
  xor  ax, ax
  xor  ax, ax
  mov  ss, ax
  mov  ss, ax
 
 
  ;; Get the boot sequence number out of the IPL memory
  ;; Get the boot sequence number out of the IPL memory
  mov  bx, #IPL_SEG
  mov  bx, #IPL_SEG
  mov  ds, bx                     ;; Set segment
  mov  ds, bx                     ;; Set segment
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
  inc  bx                         ;; ++
  inc  bx                         ;; ++
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
  mov  ds, ax                     ;; and reset the segment to zero.
  mov  ds, ax                     ;; and reset the segment to zero.
 
 
  ;; Carry on in the INT 19h handler, using the new sequence number
  ;; Carry on in the INT 19h handler, using the new sequence number
  push bx
  push bx
 
 
  jmp  int19_next_boot
  jmp  int19_next_boot
 
 
;----------
;----------
;- INT19h -
;- INT19h -
;----------
;----------
int19_relocated: ;; Boot function, relocated
int19_relocated: ;; Boot function, relocated
 
 
  ;; int19 was beginning to be really complex, so now it
  ;; int19 was beginning to be really complex, so now it
  ;; just calls a C function that does the work
  ;; just calls a C function that does the work
 
 
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
  ;; Reset SS and SP
  ;; Reset SS and SP
  mov  ax, #0xfffe
  mov  ax, #0xfffe
  mov  sp, ax
  mov  sp, ax
  xor  ax, ax
  xor  ax, ax
  mov  ss, ax
  mov  ss, ax
 
 
  ;; Start from the first boot device (0, in AX)
  ;; Start from the first boot device (0, in AX)
  mov  bx, #IPL_SEG
  mov  bx, #IPL_SEG
  mov  ds, bx                     ;; Set segment to write to the IPL memory
  mov  ds, bx                     ;; Set segment to write to the IPL memory
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
  mov  ds, ax                     ;; and reset the segment.
  mov  ds, ax                     ;; and reset the segment.
 
 
  push ax
  push ax
 
 
int19_next_boot:
int19_next_boot:
 
 
  ;; Call the C code for the next boot device
  ;; Call the C code for the next boot device
  call _int19_function
  call _int19_function
 
 
  ;; Boot failed: invoke the boot recovery function
  ;; Boot failed: invoke the boot recovery function
  int  #0x18
  int  #0x18
 
 
;----------
;----------
;- INT1Ch -
;- INT1Ch -
;----------
;----------
int1c_handler: ;; User Timer Tick
int1c_handler: ;; User Timer Tick
  iret
  iret
 
 
 
 
;--------------------
;--------------------
;- POST: EBDA segment
;- POST: EBDA segment
;--------------------
;--------------------
; relocated here because the primary POST area isnt big enough.
; relocated here because the primary POST area isnt big enough.
ebda_post:
ebda_post:
  xor ax, ax            ; mov EBDA seg into 40E
  xor ax, ax            ; mov EBDA seg into 40E
  mov ds, ax
  mov ds, ax
  mov word ptr [0x40E], #EBDA_SEG
  mov word ptr [0x40E], #EBDA_SEG
  ret;;
  ret;;
 
 
rom_checksum:
rom_checksum:
  push ax
  push ax
  push bx
  push bx
  push cx
  push cx
  xor  ax, ax
  xor  ax, ax
  xor  bx, bx
  xor  bx, bx
  xor  cx, cx
  xor  cx, cx
  mov  ch, [2]
  mov  ch, [2]
  shl  cx, #1
  shl  cx, #1
checksum_loop:
checksum_loop:
  add  al, [bx]
  add  al, [bx]
  inc  bx
  inc  bx
  loop checksum_loop
  loop checksum_loop
  and  al, #0xff
  and  al, #0xff
  pop  cx
  pop  cx
  pop  bx
  pop  bx
  pop  ax
  pop  ax
  ret
  ret
 
 
 
 
;; We need a copy of this string, but we are not actually a PnP BIOS,
;; We need a copy of this string, but we are not actually a PnP BIOS,
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
.align 16
.align 16
  db 0
  db 0
pnp_string:
pnp_string:
  .ascii "$PnP"
  .ascii "$PnP"
 
 
 
 
rom_scan:
rom_scan:
  ;; Scan for existence of valid expansion ROMS.
  ;; Scan for existence of valid expansion ROMS.
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
  ;;   System  ROM: only 0xE0000
  ;;   System  ROM: only 0xE0000
  ;;
  ;;
  ;; Header:
  ;; Header:
  ;;   Offset    Value
  ;;   Offset    Value
  ;;   0         0x55
  ;;   0         0x55
  ;;   1         0xAA
  ;;   1         0xAA
  ;;   2         ROM length in 512-byte blocks
  ;;   2         ROM length in 512-byte blocks
  ;;   3         ROM initialization entry point (FAR CALL)
  ;;   3         ROM initialization entry point (FAR CALL)
 
 
rom_scan_loop:
rom_scan_loop:
  push ax       ;; Save AX
  push ax       ;; Save AX
  mov  ds, cx
  mov  ds, cx
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
  cmp [0], #0xAA55 ;; look for signature
  cmp [0], #0xAA55 ;; look for signature
  jne  rom_scan_increment
  jne  rom_scan_increment
  call rom_checksum
  call rom_checksum
  jnz  rom_scan_increment
  jnz  rom_scan_increment
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
 
 
  ;; We want our increment in 512-byte quantities, rounded to
  ;; We want our increment in 512-byte quantities, rounded to
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
  test al, #0x03
  test al, #0x03
  jz   block_count_rounded
  jz   block_count_rounded
  and  al, #0xfc ;; needs rounding up
  and  al, #0xfc ;; needs rounding up
  add  al, #0x04
  add  al, #0x04
block_count_rounded:
block_count_rounded:
 
 
  xor  bx, bx   ;; Restore DS back to 0000:
  xor  bx, bx   ;; Restore DS back to 0000:
  mov  ds, bx
  mov  ds, bx
  push ax       ;; Save AX
  push ax       ;; Save AX
  push di       ;; Save DI
  push di       ;; Save DI
  ;; Push addr of ROM entry point
  ;; Push addr of ROM entry point
  push cx       ;; Push seg
  push cx       ;; Push seg
  ;; push #0x0003  ;; Push offset - not an 8086 valid operand
  ;; push #0x0003  ;; Push offset - not an 8086 valid operand
  mov ax, #0x0003
  mov ax, #0x0003
  push ax
  push ax
 
 
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
  mov  ax, #0xf000
  mov  ax, #0xf000
  mov  es, ax
  mov  es, ax
  lea  di, pnp_string
  lea  di, pnp_string
 
 
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
  db   0xff     ;; call_far ss:[bp+0]
  db   0xff     ;; call_far ss:[bp+0]
  db   0x5e
  db   0x5e
  db   0
  db   0
  cli           ;; In case expansion ROM BIOS turns IF on
  cli           ;; In case expansion ROM BIOS turns IF on
  add  sp, #2   ;; Pop offset value
  add  sp, #2   ;; Pop offset value
  pop  cx       ;; Pop seg value (restore CX)
  pop  cx       ;; Pop seg value (restore CX)
 
 
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
  ;; to init all the ROMs and then go back and build an IPL table of
  ;; to init all the ROMs and then go back and build an IPL table of
  ;; all the bootable devices, but we can get away with one pass.
  ;; all the bootable devices, but we can get away with one pass.
  mov  ds, cx       ;; ROM base
  mov  ds, cx       ;; ROM base
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
  jne  no_bev
  jne  no_bev
  mov  ax, 2[bx]
  mov  ax, 2[bx]
  cmp  ax, #0x506e
  cmp  ax, #0x506e
  jne  no_bev
  jne  no_bev
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
  je   no_bev
  je   no_bev
 
 
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
  mov  ds, bx
  mov  ds, bx
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
  cmp  bx, #IPL_TABLE_ENTRIES
  cmp  bx, #IPL_TABLE_ENTRIES
  je   no_bev                  ;; Get out if the table is full
  je   no_bev                  ;; Get out if the table is full
  push cx
  push cx
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
  pop  cx
  pop  cx
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
  mov  6[bx], cx               ;; Build a far pointer from the segment...
  mov  6[bx], cx               ;; Build a far pointer from the segment...
  mov  4[bx], ax               ;; and the offset
  mov  4[bx], ax               ;; and the offset
  cmp  di, #0x0000
  cmp  di, #0x0000
  je   no_prod_str
  je   no_prod_str
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
  mov  8[bx], di               ;; and the offset
  mov  8[bx], di               ;; and the offset
no_prod_str:
no_prod_str:
  push cx
  push cx
  mov  cx, #0x4
  mov  cx, #0x4
  shr  bx, cl                  ;; Turn the offset back into a count
  shr  bx, cl                  ;; Turn the offset back into a count
  pop  cx
  pop  cx
  inc  bx                      ;; We have one more entry now
  inc  bx                      ;; We have one more entry now
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
 
 
no_bev:
no_bev:
  pop  di       ;; Restore DI
  pop  di       ;; Restore DI
  pop  ax       ;; Restore AX
  pop  ax       ;; Restore AX
rom_scan_increment:
rom_scan_increment:
  push cx
  push cx
  mov  cx, #5
  mov  cx, #5
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
                ;; because the segment selector is shifted left 4 bits.
                ;; because the segment selector is shifted left 4 bits.
  pop  cx
  pop  cx
  add  cx, ax
  add  cx, ax
  pop  ax       ;; Restore AX
  pop  ax       ;; Restore AX
  cmp  cx, ax
  cmp  cx, ax
  jbe  rom_scan_loop
  jbe  rom_scan_loop
 
 
  xor  ax, ax   ;; Restore DS back to 0000:
  xor  ax, ax   ;; Restore DS back to 0000:
  mov  ds, ax
  mov  ds, ax
  ret
  ret
 
 
;; for 'C' strings and other data, insert them here with
;; for 'C' strings and other data, insert them here with
;; a the following hack:
;; a the following hack:
;; DATA_SEG_DEFS_HERE
;; DATA_SEG_DEFS_HERE
 
 
 
 
;; the following area can be used to write dynamically generated tables
;; the following area can be used to write dynamically generated tables
  .align 16
  .align 16
bios_table_area_start:
bios_table_area_start:
  dd 0xaafb4442
  dd 0xaafb4442
  dd bios_table_area_end - bios_table_area_start - 8;
  dd bios_table_area_end - bios_table_area_start - 8;
 
 
;--------
;--------
;- POST -
;- POST -
;--------
;--------
.org 0xe05b ; POST Entry Point
.org 0xe05b ; POST Entry Point
post:
post:
  xor ax, ax
  xor ax, ax
 
 
normal_post:
normal_post:
  ; case 0: normal startup
  ; case 0: normal startup
 
 
  cli
  cli
  mov  ax, #0xfffe
  mov  ax, #0xfffe
  mov  sp, ax
  mov  sp, ax
  xor  ax, ax
  xor  ax, ax
  mov  ds, ax
  mov  ds, ax
  mov  ss, ax
  mov  ss, ax
 
 
  ;; zero out BIOS data area (40:00..40:ff)
  ;; zero out BIOS data area (40:00..40:ff)
  mov  es, ax
  mov  es, ax
  mov  cx, #0x0080 ;; 128 words
  mov  cx, #0x0080 ;; 128 words
  mov  di, #0x0400
  mov  di, #0x0400
  cld
  cld
  rep
  rep
    stosw
    stosw
 
 
  ;; set all interrupts to default handler
  ;; set all interrupts to default handler
  xor  bx, bx         ;; offset index
  xor  bx, bx         ;; offset index
  mov  cx, #0x0100    ;; counter (256 interrupts)
  mov  cx, #0x0100    ;; counter (256 interrupts)
  mov  ax, #dummy_iret_handler
  mov  ax, #dummy_iret_handler
  mov  dx, #0xF000
  mov  dx, #0xF000
 
 
post_default_ints:
post_default_ints:
  mov  [bx], ax
  mov  [bx], ax
  add  bx, #2
  add  bx, #2
  mov  [bx], dx
  mov  [bx], dx
  add  bx, #2
  add  bx, #2
  loop post_default_ints
  loop post_default_ints
 
 
  ;; set vector 0x79 to zero
  ;; set vector 0x79 to zero
  ;; this is used by 'gardian angel' protection system
  ;; this is used by 'gardian angel' protection system
  SET_INT_VECTOR(0x79, #0, #0)
  SET_INT_VECTOR(0x79, #0, #0)
 
 
  ;; base memory in K 40:13 (word)
  ;; base memory in K 40:13 (word)
  mov  ax, #BASE_MEM_IN_K
  mov  ax, #BASE_MEM_IN_K
  mov  0x0413, ax
  mov  0x0413, ax
 
 
 
 
  ;; Manufacturing Test 40:12
  ;; Manufacturing Test 40:12
  ;;   zerod out above
  ;;   zerod out above
 
 
  ;; Warm Boot Flag 0040:0072
  ;; Warm Boot Flag 0040:0072
  ;;   value of 1234h = skip memory checks
  ;;   value of 1234h = skip memory checks
  ;;   zerod out above
  ;;   zerod out above
 
 
  ;; Bootstrap failure vector
  ;; Bootstrap failure vector
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
 
 
  ;; Bootstrap Loader vector
  ;; Bootstrap Loader vector
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
 
 
  ;; User Timer Tick vector
  ;; User Timer Tick vector
  SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
  SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
 
 
  ;; Memory Size Check vector
  ;; Memory Size Check vector
  SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
  SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
 
 
  ;; Equipment Configuration Check vector
  ;; Equipment Configuration Check vector
  SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
  SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
 
 
  ;; EBDA setup
  ;; EBDA setup
  call ebda_post
  call ebda_post
 
 
  ;; Keyboard
  ;; Keyboard
  SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
  SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
  SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
  SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
 
 
  xor  ax, ax
  xor  ax, ax
  mov  ds, ax
  mov  ds, ax
  mov  0x0417, al /* keyboard shift flags, set 1 */
  mov  0x0417, al /* keyboard shift flags, set 1 */
  mov  0x0418, al /* keyboard shift flags, set 2 */
  mov  0x0418, al /* keyboard shift flags, set 2 */
  mov  0x0419, al /* keyboard alt-numpad work area */
  mov  0x0419, al /* keyboard alt-numpad work area */
  mov  0x0471, al /* keyboard ctrl-break flag */
  mov  0x0471, al /* keyboard ctrl-break flag */
  mov  0x0497, al /* keyboard status flags 4 */
  mov  0x0497, al /* keyboard status flags 4 */
  mov  al, #0x10
  mov  al, #0x10
  mov  0x0496, al /* keyboard status flags 3 */
  mov  0x0496, al /* keyboard status flags 3 */
 
 
  /* keyboard head of buffer pointer */
  /* keyboard head of buffer pointer */
  mov  bx, #0x001E
  mov  bx, #0x001E
  mov  0x041A, bx
  mov  0x041A, bx
 
 
  /* keyboard end of buffer pointer */
  /* keyboard end of buffer pointer */
  mov  0x041C, bx
  mov  0x041C, bx
 
 
  /* keyboard pointer to start of buffer */
  /* keyboard pointer to start of buffer */
  mov  bx, #0x001E
  mov  bx, #0x001E
  mov  0x0480, bx
  mov  0x0480, bx
 
 
  /* keyboard pointer to end of buffer */
  /* keyboard pointer to end of buffer */
  mov  bx, #0x003E
  mov  bx, #0x003E
  mov  0x0482, bx
  mov  0x0482, bx
 
 
  ;; CMOS RTC
  ;; CMOS RTC
  SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
  SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
 
 
  ;; Video setup
  ;; Video setup
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
 
 
  mov  cx, #0xc000  ;; init vga bios
  mov  cx, #0xc000  ;; init vga bios
  mov  ax, #0xc780
  mov  ax, #0xc780
 
 
  call rom_scan
  call rom_scan
 
 
  call _print_bios_banner
  call _print_bios_banner
 
 
  ;; Floppy setup
  ;; Floppy setup
  SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
  SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
 
 
  call _init_boot_vectors
  call _init_boot_vectors
 
 
  mov  cx, #0xc800  ;; init option roms
  mov  cx, #0xc800  ;; init option roms
  mov  ax, #0xe000
  mov  ax, #0xe000
  call rom_scan
  call rom_scan
 
 
  sti        ;; enable interrupts
  sti        ;; enable interrupts
  int  #0x19
  int  #0x19
 
 
;-------------------------------------------
;-------------------------------------------
;- INT 13h Fixed Disk Services Entry Point -
;- INT 13h Fixed Disk Services Entry Point -
;-------------------------------------------
;-------------------------------------------
.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
int13_handler:
int13_handler:
  //JMPL(int13_relocated)
  //JMPL(int13_relocated)
  jmp int13_relocated
  jmp int13_relocated
 
 
.org 0xe401 ; Fixed Disk Parameter Table
.org 0xe401 ; Fixed Disk Parameter Table
 
 
;----------
;----------
;- INT19h -
;- INT19h -
;----------
;----------
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
int19_handler:
int19_handler:
 
 
  jmp int19_relocated
  jmp int19_relocated
 
 
 
 
;----------------------------------------
;----------------------------------------
;- INT 16h Keyboard Service Entry Point -
;- INT 16h Keyboard Service Entry Point -
;----------------------------------------
;----------------------------------------
.org 0xe82e
.org 0xe82e
int16_handler:
int16_handler:
 
 
  sti
  sti
  push  ds
  push  ds
  pushf
  pushf
  ;pusha ; we do this instead:
  ;pusha ; we do this instead:
  push ax
  push ax
  push cx
  push cx
  push dx
  push dx
  push bx
  push bx
  push sp
  push sp
  mov  bx, sp
  mov  bx, sp
  sseg
  sseg
    add  [bx], #10
    add  [bx], #10
  sseg
  sseg
    mov  bx, [bx+2]
    mov  bx, [bx+2]
  push bp
  push bp
  push si
  push si
  push di
  push di
 
 
  cmp   ah, #0x00
  cmp   ah, #0x00
  je    int16_F00
  je    int16_F00
  cmp   ah, #0x10
  cmp   ah, #0x10
  je    int16_F00
  je    int16_F00
 
 
  mov  bx, #0xf000
  mov  bx, #0xf000
  mov  ds, bx
  mov  ds, bx
  call _int16_function
  call _int16_function
  ; popa ; we do this instead:
  ; popa ; we do this instead:
  pop di
  pop di
  pop si
  pop si
  pop bp
  pop bp
  add sp, #2
  add sp, #2
  pop bx
  pop bx
  pop dx
  pop dx
  pop cx
  pop cx
  pop ax
  pop ax
  popf
  popf
  pop  ds
  pop  ds
  jz   int16_zero_set
  jz   int16_zero_set
 
 
int16_zero_clear:
int16_zero_clear:
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
  //SEG SS
  //SEG SS
  and  BYTE [bp + 0x06], #0xbf
  and  BYTE [bp + 0x06], #0xbf
  pop  bp
  pop  bp
  iret
  iret
 
 
int16_zero_set:
int16_zero_set:
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
  //SEG SS
  //SEG SS
  or   BYTE [bp + 0x06], #0x40
  or   BYTE [bp + 0x06], #0x40
  pop  bp
  pop  bp
  iret
  iret
 
 
int16_F00:
int16_F00:
  mov  bx, #0x0040
  mov  bx, #0x0040
  mov  ds, bx
  mov  ds, bx
 
 
int16_wait_for_key:
int16_wait_for_key:
  cli
  cli
  mov  bx, 0x001a
  mov  bx, 0x001a
  cmp  bx, 0x001c
  cmp  bx, 0x001c
  jne  int16_key_found
  jne  int16_key_found
  sti
  sti
  nop
  nop
#if 0
#if 0
                           /* no key yet, call int 15h, function AX=9002 */
                           /* no key yet, call int 15h, function AX=9002 */
  0x50,                    /* push AX */
  0x50,                    /* push AX */
  0xb8, 0x02, 0x90,        /* mov AX, #0x9002 */
  0xb8, 0x02, 0x90,        /* mov AX, #0x9002 */
  0xcd, 0x15,              /* int 15h */
  0xcd, 0x15,              /* int 15h */
  0x58,                    /* pop  AX */
  0x58,                    /* pop  AX */
  0xeb, 0xea,              /* jmp   WAIT_FOR_KEY */
  0xeb, 0xea,              /* jmp   WAIT_FOR_KEY */
#endif
#endif
  jmp  int16_wait_for_key
  jmp  int16_wait_for_key
 
 
int16_key_found:
int16_key_found:
  mov  bx, #0xf000
  mov  bx, #0xf000
  mov  ds, bx
  mov  ds, bx
  call _int16_function
  call _int16_function
  ; popa ; we do this instead:
  ; popa ; we do this instead:
  pop di
  pop di
  pop si
  pop si
  pop bp
  pop bp
  add sp, #2
  add sp, #2
  pop bx
  pop bx
  pop dx
  pop dx
  pop cx
  pop cx
  pop ax
  pop ax
  popf
  popf
  pop  ds
  pop  ds
#if 0
#if 0
                           /* notify int16 complete w/ int 15h, function AX=9102 */
                           /* notify int16 complete w/ int 15h, function AX=9102 */
  0x50,                    /* push AX */
  0x50,                    /* push AX */
  0xb8, 0x02, 0x91,        /* mov AX, #0x9102 */
  0xb8, 0x02, 0x91,        /* mov AX, #0x9102 */
  0xcd, 0x15,              /* int 15h */
  0xcd, 0x15,              /* int 15h */
  0x58,                    /* pop  AX */
  0x58,                    /* pop  AX */
#endif
#endif
  iret
  iret
 
 
 
 
 
 
;-------------------------------------------------
;-------------------------------------------------
;- INT09h : Keyboard Hardware Service Entry Point -
;- INT09h : Keyboard Hardware Service Entry Point -
;-------------------------------------------------
;-------------------------------------------------
.org 0xe987
.org 0xe987
int09_handler:
int09_handler:
  cli
  cli
  push ax
  push ax
  in  al, #0x60             ;;read key from keyboard controller
  in  al, #0x60             ;;read key from keyboard controller
  sti
  sti
 
 
  push  ds
  push  ds
  ;pusha ; we do this instead:
  ;pusha ; we do this instead:
 
 
  push ax
  push ax
  push cx
  push cx
  push dx
  push dx
  push bx
  push bx
  push sp
  push sp
  mov  bx, sp
  mov  bx, sp
  sseg
  sseg
    add  [bx], #10
    add  [bx], #10
  sseg
  sseg
    mov  bx, [bx+2]
    mov  bx, [bx+2]
  push bp
  push bp
  push si
  push si
  push di
  push di
 
 
  ;; check for extended key
  ;; check for extended key
  cmp  al, #0xe0
  cmp  al, #0xe0
  jne int09_check_pause
  jne int09_check_pause
  xor  ax, ax
  xor  ax, ax
  mov  ds, ax
  mov  ds, ax
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x02
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x02
  or   al, #0x02
  or   al, #0x02
  mov  BYTE [0x496], al
  mov  BYTE [0x496], al
  jmp int09_done
  jmp int09_done
 
 
int09_check_pause: ;; check for pause key
int09_check_pause: ;; check for pause key
  cmp  al, #0xe1
  cmp  al, #0xe1
  jne int09_process_key
  jne int09_process_key
  xor  ax, ax
  xor  ax, ax
  mov  ds, ax
  mov  ds, ax
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x01
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x01
  or   al, #0x01
  or   al, #0x01
  mov  BYTE [0x496], al
  mov  BYTE [0x496], al
  jmp int09_done
  jmp int09_done
 
 
int09_process_key:
int09_process_key:
  mov   bx, #0xf000
  mov   bx, #0xf000
  mov   ds, bx
  mov   ds, bx
  call  _int09_function
  call  _int09_function
int09_done:
int09_done:
  ; popa ; we do this instead:
  ; popa ; we do this instead:
  pop di
  pop di
  pop si
  pop si
  pop bp
  pop bp
  add sp, #2
  add sp, #2
  pop bx
  pop bx
  pop dx
  pop dx
  pop cx
  pop cx
  pop ax
  pop ax
 
 
  pop   ds
  pop   ds
 
 
  cli
  cli
  pop ax
  pop ax
  iret
  iret
 
 
 
 
;----------
;----------
;- INT10h -
;- INT10h -
;----------
;----------
.org 0xf065 ; INT 10h Video Support Service Entry Point
.org 0xf065 ; INT 10h Video Support Service Entry Point
int10_handler:
int10_handler:
  ;; dont do anything, since the VGA BIOS handles int10h requests
  ;; dont do anything, since the VGA BIOS handles int10h requests
  iret
  iret
 
 
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
 
 
;----------
;----------
;- INT12h -
;- INT12h -
;----------
;----------
.org 0xf841 ; INT 12h Memory Size Service Entry Point
.org 0xf841 ; INT 12h Memory Size Service Entry Point
; ??? different for Pentium (machine check)?
; ??? different for Pentium (machine check)?
int12_handler:
int12_handler:
  push ds
  push ds
  mov  ax, #0x0040
  mov  ax, #0x0040
  mov  ds, ax
  mov  ds, ax
  mov  ax, 0x0013
  mov  ax, 0x0013
  pop  ds
  pop  ds
  iret
  iret
 
 
;----------
;----------
;- INT11h -
;- INT11h -
;----------
;----------
.org 0xf84d ; INT 11h Equipment List Service Entry Point
.org 0xf84d ; INT 11h Equipment List Service Entry Point
int11_handler:
int11_handler:
  push ds
  push ds
  mov  ax, #0x0040
  mov  ax, #0x0040
  mov  ds, ax
  mov  ds, ax
  mov  ax, 0x0010
  mov  ax, 0x0010
  pop  ds
  pop  ds
  iret
  iret
 
 
;----------
;----------
;- INT1Ah -
;- INT1Ah -
;----------
;----------
.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
int1a_handler:
int1a_handler:
  push ds
  push ds
  ;pusha ; we do this instead:
  ;pusha ; we do this instead:
  push ax
  push ax
  push cx
  push cx
  push dx
  push dx
  push bx
  push bx
  push sp
  push sp
  mov  bx, sp
  mov  bx, sp
  sseg
  sseg
    add  [bx], #10
    add  [bx], #10
  sseg
  sseg
    mov  bx, [bx+2]
    mov  bx, [bx+2]
  push bp
  push bp
  push si
  push si
  push di
  push di
 
 
  xor  ax, ax
  xor  ax, ax
  mov  ds, ax
  mov  ds, ax
int1a_callfunction:
int1a_callfunction:
  call _int1a_function
  call _int1a_function
  ; popa ; we do this instead:
  ; popa ; we do this instead:
  pop di
  pop di
  pop si
  pop si
  pop bp
  pop bp
  add sp, #2
  add sp, #2
  pop bx
  pop bx
  pop dx
  pop dx
  pop cx
  pop cx
  pop ax
  pop ax
 
 
  pop  ds
  pop  ds
  iret
  iret
 
 
;------------------------------------------------
;------------------------------------------------
;- IRET Instruction for Dummy Interrupt Handler -
;- IRET Instruction for Dummy Interrupt Handler -
;------------------------------------------------
;------------------------------------------------
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
dummy_iret_handler:
dummy_iret_handler:
  iret
  iret
 
 
.org 0xfff0 ; Power-up Entry Point
.org 0xfff0 ; Power-up Entry Point
;  hlt
;  hlt
  jmp 0xf000:post
  jmp 0xf000:post
 
 
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
.ascii BIOS_BUILD_DATE
.ascii BIOS_BUILD_DATE
 
 
.org 0xfffe ; System Model ID
.org 0xfffe ; System Model ID
db SYS_MODEL_ID
db SYS_MODEL_ID
db 0x00   ; filler
db 0x00   ; filler
ASM_END
ASM_END
 
 
ASM_START
ASM_START
.org 0xcc00
.org 0xcc00
bios_table_area_end:
bios_table_area_end:
// bcc-generated data will be placed here
// bcc-generated data will be placed here
ASM_END
ASM_END
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.