"80186"
;	@(mktid) 64764-11001  80186/8 EMUL FOREGRND MONITOR            A.00.01 27Jan88 11:06:39                                                                   
; Foreground monitor code for the 80186 emulator
;
; This is the standard foreground monitor for the 80186 odyssey emulator.
; The monitor occupies 2K of emulation memory space (seperate from the
; normal user space).  Following is a map of how this memory is organized:
;
;-----------------------------------------------------------------------------
;
;   000H ****************************************************
;        *  IP,CS and flag jam area (all 8 bytes used)      *
;   008H ****************************************************
;        *  Vector area                                     *
;   00CH ****************************************************
;        *  Communications area                             *
;   020H ****************************************************
;        *  I/O area 0                                      *
;   030H ****************************************************
;        *  I/O area 1                                      *
;   040H ****************************************************
;        *  Set JAMBKGR flag                                *
;   048H ****************************************************
;        *  Reset JAMBKGW flag                              *
;   050H ****************************************************
;        *  Set BKGPS flag                                  *
;   058H ****************************************************
;        *  Reset BKGPS flag                                *
;   060H ****************************************************
;        *  Set BKGWTT flag                                 *
;   068H ****************************************************
;        *  Reset BKGWTT flag                               *
;   070H ****************************************************
;        *  Set BKGRFT flag                                 *
;   078H ****************************************************
;        *  Reset BKGRFT flag                               *
;   080H ****************************************************
;        *  Background handler                              *
;        *  Monitor Area                                    *
;   380H ****************************************************
;        *  Register Area                                   *
;   400H ****************************************************
;        *  Alternate entry table                           *
;   6E0H ****************************************************
;        *  Data buffer                                     *
;   7F0H ****************************************************
;        *  Background reset area                           *
;   7FFH ****************************************************
;
;-----------------------------------------------------------------------------
; I/O Area 0
;
; A read from this area will bring in the following emulator status flags:
;
; Bit     Flag
;
;  0      Break request
;  1      Run request
;  2      Was Halted
;  3      Sixteen bit processor
;
; A write to this area will set the ready flag true.
;-----------------------------------------------------------------------------
; I/O Area 1
;
; A read from this area does the same thing as a read from I/O area 0.
;
; A write to this area sets the jam counter to the value written (only bit
; D0 is used).
;-----------------------------------------------------------------------------
; Locations 40H thru 7FH are special in that they require an opcode
; fetch from the appropriate range to set or reset the indicated flag.
; In all cases except for setting the jam read flag, JAMBKGR, the desired
; function must be called using the macro sfunc (sfunc guarantees that only
; opcode fetches are generated).
;-----------------------------------------------------------------------------

JAMAREA         EQU     000H
VECTAREA        EQU     008H
COMMAREA        EQU     00CH
IOAREA0         EQU     020H
IOAREA1         EQU     030H
MONAREA         EQU     080H
REGAREA         EQU     380H
VTABLEAREA      EQU     400H
BUFAREA         EQU     6E0H
STACKAREA       EQU     BUFAREA-8
SBIAREA         EQU     7E8H
RESETAREA       EQU     7F0H
ENTRYVECTOR     EQU     7FEH
TRUE            EQU     1
FALSE           EQU     0
SINGLE_STEP     EQU     100H

SPECEN0         EQU     00001100000B
SPECEN1         EQU     00001000000B

BPA             EQU     00000B
BPB             EQU     01000B
BPC             EQU     10000B
BPD             EQU     11000B

IRETTOFG        EQU     00001000000B         ;SPECEN1 + BPA
CLRJAMBKGW      EQU     00001001000B         ;SPECEN1 + BPB
SETBKGPS        EQU     00001011000B         ;SPECEN1 + BPD
CLRBKGPS        EQU     00001010000B         ;SPECEN1 + BPC

SETBKGWTT       EQU     00001101000B         ;SPECEN0 + BPB
CLRBKGWTT       EQU     00001100000B         ;SPECEN0 + BPA
CLRBKGRFT       EQU     00001110000B         ;SPECEN0 + BPC
SETBKGRFT       EQU     00001111000B         ;SPECEN0 + BPD

BREAKMASK       EQU     0001B
RUNMASK         EQU     0010B
WASHALTEDMASK   EQU     0100B
SXTNSELMASK     EQU     1000B
CMDAVAIL        EQU     0
CMDCOMPLETE     EQU     0FFFFH
INRFGLOOP       EQU     0FFFFH
EM186           EQU     0
EM188           EQU     1


SFUNC           MACRO   &SUBADDR
                MOV     BP,#($+6)
                JMP     NEAR PTR &SUBADDR
                MEND

SFUNCRET        MACRO
                JMP     BP
                MEND

MONCALL         MACRO
                MOV     BX,#($+5)
; Compensate for HP assembler bug...
;   ...can't generate JMP [SI] !!
                DB      0FFH,024H
                MEND

MONRET          MACRO
                JMP     BX
                MEND

                ASSUME CS:ORG

;Reserve stack area for monitor entry and exit.  Because we cant depent on
;any specific stack pointer value, all 8 bytes are reserved.
                ORG     JAMAREA
                DW      ?,?,?,?

;Load vector for monitor entry
                ORG     VECTAREA
                DW      mon_entry
                DW      ?

;Define communications area
                ORG     COMMAREA
wf_ready        DW      ?
wf_reset        DW      ?
semiphore       DW      CMDCOMPLETE
command         DW      2,?,?,?,?,?,?

                ORG     ENTRYVECTOR
entry_vector    DW      ?

;Define location of status reg
                ORG     IOAREA0
statloc         LABEL   BYTE
rdyloc          LABEL   BYTE

;Define location of counter (also status reg but we dont use this address
;range for it)
                ORG     IOAREA1
cntrloc         LABEL   BYTE

;Define locations of special functions

;A jump to irettofg causes the emulator to go to foreground.  Depending on
;the way things are set up, the following 3 or 6 memory reads are jammed
;from the jamming area, loading the desired values of the ip, cs and flag
;registers.  When this is done, the transistion to foreground is performed.
                ORG     IRETTOFG
irettofg:       IRET

;A jump to clrjambkgw makes the internal sequencer stop jamming background
;writes.  This is done as soon as we enter the monitor so we dont overwrite
;the values of the ip, cs and flag registers that were saved during the
;NMI used to enter background.
                ORG     CLRJAMBKGW
clrjambkgw:     JMP     SHORT mon_entry1

;A jump to setbkgps places the emulator in a mode that presents unmodified
;cycles to the target system.  This is used to allow us to perform writes
;to the target while in background.
                ORG     SETBKGPS
setbkgps:       SFUNCRET

;A jump to clrbkgps places undoes a jump to setbkgps.  This is the normal
;condition for this flag
                ORG     CLRBKGPS
clrbkgps:       SFUNCRET

;A jump to setbkgwtt enables background writes to be sent to the target system
                ORG     SETBKGWTT
setbkgwtt:      SFUNCRET

;A jump to clrbkgwtt undoes a jump to setbkgwtt.  This is the normal condition
;for this flag.
                ORG     CLRBKGWTT
clrbkgwtt:      SFUNCRET

;A jump to setbkgrft allows the emulator to read from the target system.
                ORG     SETBKGRFT
setbkgrft:      SFUNCRET

;A jump to clrbkgrft allows the emulator to read from monitor memory.
                ORG     CLRBKGRFT
clrbkgrft:      SFUNCRET


                ORG     MONAREA

; This is the entry point we use when we do a break.  When we get here, we
; are in background.
;
; Before going to the monitor, we check to see if we broke out of it.
; If so, we reenter it without saving registers.  If not, we first save
; the registers then enter the monitor.
;
; When we enter this routine all registers are correct except IP, CS and
; the flag register.  These three registers were jammed, so they must be
; read from the jam area.
mon_entry:
                JMP     SHORT clrjambkgw      ;stop jamming background wrts
mon_entry1:
                CLD                     ;make sure we autoincrement
                MOV     CS:tempax,AX    ;save AX
                MOV     CS:tempds,DS    ;save DS
                MOV     AX,CS           ;put CS into AX
                MOV     DS,AX           ;put CS into DS
                MOV     DS:tempes,ES    ;save ES
                MOV     ES,AX           ;put CS into ES
                MOV     DS:tempdi,DI    ;save DI
                MOV     DS:tempsi,SI    ;save SI
                MOV     DI,OFFSET tempip ;point to temp area for IP, CS and FL
                MOV     SI,SP           ;point to stack
                MOV     AX,#111B        ;load mask in AX

                AND     SI,AX           ;stay in jam area
                MOVSB                   ;move the byte
                AND     SI,AX           ;stay in jam area
                MOVSB                   ;move the byte
                AND     SI,AX           ;stay in jam area
                MOVSB                   ;move the byte
                AND     SI,AX           ;stay in jam area
                MOVSB                   ;move the byte
                AND     SI,AX           ;stay in jam area
                MOVSB                   ;move the byte
                AND     SI,AX           ;stay in jam area
                MOVSB                   ;move the byte

                MOV     SI,DI           ;SI <- &iretip (DI has it)
                MOV     DI,CS           ;DI <- CS
                CMP     DI,DS:tempcs    ;see if we broke out of
                JNE     not_from_mon    ;the monitor
                CMP     DS:tempip,#SBIAREA      ;
                JAE     not_from_mon    ;

; We broke out of the monitor.  Therefore, we dont save registers and we
; dont change the stack pointer.  Enter the monitor at <monitor>.
                MOV     WORD PTR[SI],OFFSET monitor ;load iretip
                JMP     SHORT go_to_mon

not_from_mon:
; We broke out of user code.  In this case we want to enter the foreground
; monitor at a point where it will save the registers.  We make room on the
; stack for the IRET to foreground so that the user's stack is properly
; preserved.
; We enter the monitor at <save_regs1>.
                MOV     WORD PTR[SI],OFFSET save_regs1 ;load iretip
; Make room for the IRET to the foreground monitor
                SUB     SP,#6
; Place tempfl into iretfl--we wish to use the flags we broke with
                XCHG    AX,DI
                MOV     AX,DS:tempfl
                MOV     DS:iretfl,AX
                XCHG    AX,DI
; Go to the foreground monitor
;
; - SI must point to iretip
; - iretip, iretcs and iretfl MUST contain the desired offset, the monitor
;   CS the entry flags (iretfl gets tempfl).
; - AX MUST contain #111B
go_to_mon:
                MOV     DI,SP
                AND     DI,AX
                MOVSB
                AND     DI,AX
                MOVSB
                AND     DI,AX
                MOVSB
                AND     DI,AX
                MOVSB
                AND     DI,AX
                MOVSB
                AND     DI,AX
                MOVSB

                MOV     AX,DS:proc_type ;get proc type
                OR      AX,SP           ;or with sp
                MOV     DS:cntrloc,AL   ;write it to the counter
                MOV     DS:rdyloc,AL    ;set ready
                JMP     irettofg        ;go to foreground

reset_entry     LABEL   NEAR
                MOV     CS:axreg,AX     ;save AX
                MOV     AX,CS           ;get code seg
                MOV     DS,AX           ;put in ds
                MOV     ES,AX           ;put in es
                MOV     SS,AX           ;put in ss
                MOV     DS:ssreg,AX     ;set reset ss
                MOV     SP,#STACKAREA   ;set user stack
                MOV     DS:spreg,SP     ;save value

                XOR     AX,AX           ;clear AX
                MOV     DS:esreg,AX     ;set reset es
                MOV     DS:dsreg,AX     ;set reset ds
                MOV     DS:csreg,#0FFFFH ;set reset cs
                MOV     DS:ipreg,AX     ;set reset ip
                MOV     DS:flreg,#0F002H ;set reset flags

                MOV     DS:direg,DI     ;save the reset value of DI
                MOV     DS:sireg,SI     ;save the reset value of SI
                MOV     DS:bpreg,BP     ;save the reset value of BP
                MOV     DS:dxreg,DX     ;save the reset value of DX
                MOV     DS:cxreg,CX     ;save the reset value of CX
                MOV     DS:bxreg,BX     ;save the reset value of BX

                MOV     AL,DS:statloc   ;get status
                TEST    AL,SXTNSELMASK  ;test for 80186 (ZF false)
                JNZ     is186           ;skip if true
                MOV     AX,#EM188       ;load 188 type
                JMP     SHORT proc_typed ;and skip
is186:
                MOV     AX,#EM186       ;load 186 type
proc_typed:
                MOV     DS:proc_type,AX ;save processor type

                SUB     SP,#6           ;make room for an IRET to fg
                MOV     DS:iretcs,CS    ;set our CS
                MOV     DS:iretfl,#0F002H ;set monitor flags
                MOV     SI,OFFSET iretip ;setup SI for IRET to fg
                MOV     WORD PTR[SI],OFFSET monitor ;set up the ip
                MOV     AX,#111B        ;put jam mask in AX
                MOV     DS:entry_vector,8001H   ;denote entry type
                MOV     DS:semiphore,#CMDCOMPLETE
                JMP     go_to_mon       ;go to the monitor

;
; FOREGROUND CODE
;
;

                ALIGN
save_regs:
; We have broken into the monitor without first hitting background.  If we
; broke out of user code, all registers are saved
                CLD                     ;make sure we autoincrement
                MOV     CS:temp1bp,BP   ;save BP
                MOV     CS:temp1ax,AX   ;save AX
                MOV     BP,SP           ;get stack ptr
                CMP     WORD PTR[BP],#SBIAREA ;ip in range?
                JAE     not_from_mon1   ;if not skip
                MOV     AX,CS           ;get CS
                CMP     [BP+2],AX       ;correct CS?
                JNE     not_from_mon1   ;if not skip
from_mon1:
                JMP     SHORT monitor   ;we broke out of mon dont savs regs
not_from_mon1:
                MOV     BP,CS:temp1bp   ;restore BP
                MOV     AX,CS:temp1ax   ;restore AX
                MOV     CS:axreg,AX     ;save AX
                MOV     CS:dsreg,DS     ;save DS
                MOV     AX,CS
                MOV     DS,AX
                MOV     DS:esreg,ES     ;save ES
                MOV     ES,AX
                MOV     DS:direg,DI
                MOV     DI,OFFSET bxreg
                XCHG    AX,BX           ;get BX
                STOSW                   ;save BX
                XCHG    AX,CX           ;get CX
                STOSW                   ;save CX
                XCHG    AX,DX           ;get DX
                STOSW                   ;save DX
                XCHG    AX,BP           ;get BP
                STOSW                   ;save BP
                XCHG    AX,SI           ;get SI
                STOSW                   ;save SI
                ADD     DI,#6           ;skip over di,ds,es (already saved)
                MOV     AX,SS           ;get ss
                STOSW                   ;save ss
                MOV     AX,SP           ;get sp
                ADD     AX,#6           ;adjust for break
                STOSW                   ;save sp
                MOV     BP,SP           ;load frame ptr
                MOV     AX,[BP]         ;get IP
                STOSW                   ;save IP
                MOV     AX,[BP+2]       ;get CS
                STOSW                   ;save CS
                MOV     AX,[BP+4]       ;get FLAGS
                STOSW                   ;save FLAGS

                JMP     SHORT monitor

save_regs1:
; We broke out of user code, so registers must be saved.  Some of the
; registers were used while we were in background so they are in memory
; locations.  Other registers were left intact.
                MOV     SI,OFFSET tempblk       ;point si to temp block
                MOV     DI,OFFSET regblk        ;point di to reg block
                MOVSW                           ;save AX (in memory)
                MOV     AX,BX                   ;
                STOSW                           ;save BX (intact)
                MOV     AX,CX                   ;
                STOSW                           ;save CX (intact)
                MOV     AX,DX                   ;
                STOSW                           ;save DX (intact)
                MOV     AX,BP                   ;
                STOSW                           ;save BP (intact)
                MOVSW                           ;save SI (in memory)
                MOVSW                           ;save DI (in memory)
                MOVSW                           ;save DS (in memory)
                MOVSW                           ;save ES (in memory)
                MOV     AX,SS                   ;
                STOSW                           ;save SS (intact)
                MOV     AX,SP                   ;
                ADD     AX,#6                   ;
                STOSW                           ;save SP (intact)
                MOVSW                           ;save IP (in memory)
                MOVSW                           ;save CS (in memory)
                MOVSW                           ;save FLAGS (in memory)
                MOV     DS:entry_vector,8000H   ;denote entry type

monitor:
cmdloop:
; This the the main loop for the foreground monitor
                CMP     DS:semiphore,#CMDCOMPLETE ;test semiphore
                JE      cmdloop
exec_cmd:
                MOV     SI,DS:command   ;get command
                CMP     SI,#7           ;test for max
                JA      cmd_end         ;and skip if too big
                ADD     SI,SI           ;gen a word offset index
                ADD     SI,OFFSET cmd_table
                MONCALL
cmd_end:
                MOV     AX,CS
                MOV     DS,AX
                MOV     ES,AX
                MOV     DS:semiphore,#CMDCOMPLETE
                JMP     SHORT cmdloop

                ALIGN
cmd_table       LABEL   WORD
                DW      OFFSET step
                DW      OFFSET gotofg
                DW      OFFSET getrboff
                DW      OFFSET read
                DW      OFFSET write
                DW      OFFSET input
                DW      OFFSET output
                DW      OFFSET rfg

; Monitor command 0--Execute a single step in foreground
;
; Parameters:
; Set up the single step trap

step:
; Set the single step flag bit so we will single step when we exit the
; monitor.
                MOV     AX,DS:flreg     ;get flags
                OR      AX,#SINGLE_STEP ;set single step trap
exit:
                CLI                     ;block interrupts
                MOV     SS,DS:ssreg     ;get stack segment
                MOV     SP,DS:spreg     ;get stack pointer
                SUB     SP,#6           ;make room for IRET

                MOV     BP,SP           ;get the stack pointer
                MOV     [BP+4],AX       ;put flags on the stack
                MOV     AX,DS:csreg     ;
                MOV     [BP+2],AX       ;put cs reg on stack
                MOV     AX,DS:ipreg     ;
                MOV     [BP],AX         ;put ip reg on stack

                MOV     DS:semiphore,#CMDCOMPLETE

                MOV     AX,DS:axreg
                MOV     BX,DS:bxreg
                MOV     CX,DS:cxreg
                MOV     DX,DS:dxreg
                MOV     SI,DS:sireg
                MOV     DI,DS:direg
                MOV     BP,DS:bpreg
                MOV     ES,DS:esreg
                MOV     DS,DS:dsreg
                IRET

; Monitor command 1--Go to foreground
;
; Parameters: none

gotofg:
; Put the ip, cs and flg regs in the jam area
                MOV     AX,DS:flreg     ;get flags
                AND     AX,#(.NT.(SINGLE_STEP)) ;clear single step trap
                JMP     exit

; Monitor command 2--Get reg block offset
;
; Data
;  OFFSET 2--word ptr to register block
;

getrboff        PROC    NEAR
                MOV     DS:command+2,OFFSET regblk
                MONRET

; Monitor command 3--Read target memory block
;
; Parameters:
;  OFFSET 2--input type ('b'==> byte, else word)
;  OFFSET 4--number of bytes to read
;  OFFSET 6--offset address of memory to read (in target)
;  OFFSET 8--segment address of memory to read (in target)

read            PROC    NEAR
                MOV     AX,DS:command+2
                MOV     CX,DS:command+4
                MOV     DI,OFFSET buf
                MOV     SI,DS:command+6
                MOV     DS,DS:command+8
                CMP     AL,#'b'
                JE      byteread
wordread:
                REP MOVSW
                MONRET
byteread:
                REP MOVSB
                MONRET

; Monitor command 4--Write target memory block
;
; Parameters:
;  OFFSET 2--input type ('b'==> byte, else word)
;  OFFSET 4--number of bytes or words to write
;  OFFSET 6--offset address of memory to write to (in target)
;  OFFSET 8--segment address of memory to write to (in target)

write           PROC    NEAR
                MOV     AX,DS:command+2
                MOV     CX,DS:command+4
                MOV     SI,OFFSET buf
                MOV     DI,DS:command+6
                MOV     ES,DS:command+8
                CMP     AL,#'b'
                JE      bytewrite
wordwrite:
                REP MOVSW
                MONRET
bytewrite:
                REP MOVSB
                MONRET

; Monitor command 5--Read target I/O block
;
; Parameters:
;  OFFSET 2--input type ('b'==> byte, else word)
;  OFFSET 4--Number of bytes or words to input
;  OFFSET 6--I/O location

input           PROC    NEAR
                MOV     AX,DS:command+2
                MOV     CX,DS:command+4
                MOV     DX,DS:command+6
                MOV     DI,OFFSET buf
                CMP     AL,#'b'
                JE      inputbytes
inputwords:
                IN      AX,DX
                STOSW
                LOOP    inputwords
                MONRET
inputbytes:
                IN      AL,DX
                STOSB
                LOOP    inputbytes
                MONRET

; Monitor command 6--Write target I/O location
;
; Parameters:
;  OFFSET 2--input type ('b'==> byte, else word)
;  OFFSET 4--Number of bytes or words to output
;  OFFSET 6--I/O location

output          PROC    NEAR
                MOV     AX,DS:command+2
                MOV     CX,DS:command+4
                MOV     DX,DS:command+6
                MOV     SI,OFFSET buf
                CMP     AL,#'b'
                JE      outputbytes
outputwords:
                LODSW
                OUT     DX,AX
                LOOP    outputwords
                MONRET
outputbytes:
                LODSB
                OUT     DX,AL
                LOOP    outputwords
                MONRET


; Monitor command 7--Wait for target reset
;

rfg:
                MOV     DS:semiphore,#CMDCOMPLETE
rfg1:
                MOV     CS:wf_reset,#TRUE ;tickle sense location
                JMP     rfg1


                ORG     REGAREA
regblk:
axreg           DW      ?
bxreg           DW      ?
cxreg           DW      ?
dxreg           DW      ?
bpreg           DW      ?
sireg           DW      ?
direg           DW      ?
dsreg           DW      ?
esreg           DW      ?
ssreg           DW      ?
spreg           DW      ?
ipreg           DW      ?
csreg           DW      ?
flreg           DW      ?

tempblk:
tempax          DW      ?
tempsi          DW      ?
tempdi          DW      ?
tempds          DW      ?
tempes          DW      ?
tempip          DW      ?
tempcs          DW      ?
tempfl          DW      ?

iretip          DW      ?
iretcs          DW      ?
iretfl          DW      ?

temp1ax         DW      ?
temp1bp         DW      ?

proc_type       DW      ?

; Vector table area
;
; This table defines monitor entry points other than by breaking.  To use
; these entry points, the processors vector table must be loaded with
; pointers to these locations.
                ORG     VTABLEAREA

div0_entry      MOV     CS:entry_vector,0
                JMP     save_regs
ss_entry:
                MOV     CS:entry_vector,1
                JMP     save_regs
unmi_entry:
                MOV     CS:entry_vector,2
                JMP     save_regs
sbi_entry:
                MOV     CS:entry_vector,3
                JMP     save_regs
into_entry:
                MOV     CS:entry_vector,4
                JMP     save_regs
ab_entry:
                MOV     CS:entry_vector,5
                JMP     save_regs
uop_entry:
                MOV     CS:entry_vector,6
                JMP     save_regs
esc_entry:
                MOV     CS:entry_vector,7
                JMP     save_regs
tm0_entry:
                MOV     CS:entry_vector,8
                JMP     save_regs
res_entry:
                MOV     CS:entry_vector,9
                JMP     save_regs
dma0_entry:
                MOV     CS:entry_vector,10
                JMP     save_regs
dma1_entry:
                MOV     CS:entry_vector,11
                JMP     save_regs
int0_entry:
                MOV     CS:entry_vector,12
                JMP     save_regs
int1_entry:
                MOV     CS:entry_vector,13
                JMP     save_regs
int2_entry:
                MOV     CS:entry_vector,14
                JMP     save_regs
int3_entry:
                MOV     CS:entry_vector,15
                JMP     save_regs
tm1_entry:
                MOV     CS:entry_vector,18
                JMP     save_regs
tm2_entry:
                MOV     CS:entry_vector,19
                JMP     save_regs
user_entry0:
                MOV     CS:entry_vector,0100H
                JMP     save_regs

user_entry1:
                MOV     CS:entry_vector,0101H
                JMP     save_regs

user_entry2:
                MOV     CS:entry_vector,0102H
                JMP     save_regs

user_entry3:
                MOV     CS:entry_vector,0103H
                JMP     save_regs

user_entry4:
                MOV     CS:entry_vector,0104H
                JMP     save_regs

user_entry5:
                MOV     CS:entry_vector,0105H
                JMP     save_regs

user_entry6:
                MOV     CS:entry_vector,0106H
                JMP     save_regs

user_entry7:
                MOV     CS:entry_vector,0107H
                JMP     save_regs

                ORG     BUFAREA
buf             LABEL   BYTE


                ORG     SBIAREA
                NOP
                NOP
                JMP     sbi_entry

                ORG     RESETAREA
; This should be a 'JMP FAR PTR reset_entry', but I cant get the
; assembler to generate that so...
                NOP
                DB      0EAH
                DW      OFFSET reset_entry
                DW      ?

