
        TITLE    'BDOS-BIOS EMULATOR for V20 on IBM PC'
        PAGE 60
; this is bdos minus the disk calls, which are passed on to msdos

; philosophy

        ; handle character calls in 8080 mode so that
        ; can do submit and EX files
        ; line editing and ^S , ^C handling are easier this way

        ; the character i/o calls are off to the BIOS
        ; eventually anyway

        ; bdos disk calls passed off directly to 8086 MSDOS
        ; add selected higher calls to support
        ; time, date, make dir, change dir calls
        ; can be done in Turbo bdos-handler

VER    equ 2
REV    equ 2

BDOSHANDLE   equ  0c2h;   8086 interrupt numbers to get to 8086 mode
BIOSHANDLE   equ  0c3h;   80,81h used by other end to get here

; V20 macros ( used only once )

CALLN   macro     x  ; call 8088 routine at int x
        db        11101101b,11101101b  ;
        db        (x  and 0ffh)  ;
        endm

RETEM   macro
        db   0edh,0fdh
        endm

BOOTV   equ  0000H; Vector to BIOS warm boot routine
IOBYTE  equ  0003H; System I/O device assignment
TBUFF   equ  0080H; Default DMA buffer location

FALSE   equ  0
TRUE    equ  1

CR      equ     0DH
LF      equ     0AH
TAB     equ     09H             ; Tab
BACKSP  equ     08H             ; Backspace
CTRLC   equ     03H             ; Control-C
CTRLE   EQU     05H             ; Control-E
CTRLP   EQU     10H             ; Control-P
CTRLR   EQU     12H             ; Control-R
CTRLS   EQU     13H             ; Control-S
CTRLU   EQU     15H             ; Control-U
CTRLX   EQU     18H             ; Control-X
DELDAT  EQU     0E5H            ; Deleted data byte

        ORG   0FA00H ;  CSEG    ; DOSLOC

SERIAL: DB      0,0,0           ; Room for serial number
        DB      0,0,0

ENTRY:  JMP     BDOS            ; Entry to disk monitor ; serial + 6

;****
;Put bdos dpb and allocation vector here so can be found easily.
; these are doctored up by the Turbo Bdos-handler

DATASTART EQU   $
BDOSDPB:   ;serial + 9
        DS      16     ;
BDOSALLOC: ;serial + 25
        DS      256
CTEMP1: DB      0               ; temp used for console input buffer
CTEMP2: DB      0               ; temp count holder for buffer
COLUMN: DB      0               ; column pointer for buffer
LSTCPY: DB      0               ; list copy toggle byte
CHRRDY: DB      0               ; char waiting flag
OLDSP:  DB      0,0             ; Caller's Stack ptr
        DB      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        DB      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        DB      0,0,0,0,0,0,0,0 ; 48 bytes (room for stack)
USRCOD: DB      0               ; user and disk code lives here
CURDSK: DB      0               ; current disk holder
FCB:    DW      0               ; Storage for caller's parms
ODATA:  DW      0               ; return information storage
IDATA:  DB      0
OUT1:   DB      0
OLDDSK: DB      0
OUTDSK: DB      0
DATAEND equ     $
        ds      4  ; buffer area in case miscounted


;****
;bdos entry point. data enters as follows:
;               C  = command
;               DE = address or 16 bit data word
;               E  = 8 bit data word

;      return from bdos data is as follows:
;               A  = status or value
;               HL = 16 bit value or address


;****
;bdos entry saves input data as follows:

;    DE -> FCB          0  -> OLDDSK
;    E  -> IDATA        0  -> OUT1
;    0  -> ODATA        sets return to BEXIT on stack
;    SP -> OLDSP

;    saves input data and jumps to command routine

; DESTROYS A AND HL RIGHT AWAY

BDOS:   LDA     0FFFFH;  -1      ; test for exit
        ORA     A
        JNZ     BREAKOUT         ; in BIOS area  do a RETEM

BEGIN:
        XCHG      ; mov de to fcb and bdde
        SHLD    BDDE
        SHLD    FCB
        XCHG
        LXI     H,BDBC
        mov     m,c             ;
        LXI     h,0             ; zero hl
        SHLD    ODATA           ; save this for the return
        DAD     SP              ; add in the user stack pointer
        SHLD    OLDSP           ; save this for the return also
        LXI     SP,USRCOD       ; point to BDOS stack  { use private stack }
        MOV     A,E             ; move data byte into A
        STA     IDATA           ; save it
        XRA     A               ; zero out a
        STA     OLDDSK          ; save this as the old disk
        STA     OUT1            ; and at OUT1 for disk relog on exit
        LXI     H,BEXIT ;Bexit  ; get the return point address
        PUSH    H               ; and stuff it on the stack for exiting
        MOV     A,C             ; move the command into A
        STA     BDPSW           ; put it into registers at the end
        CPI     13              ; Max Char cmds +1 - is it too big?
        JNC     MSDOSHANDLER    ; return if so
        MOV     C,E             ; get input data from E into C
        LXI     H,CMMNDS        ; point to the dispatch table
        MOV     E,A             ; move the command from A into E
        MVI     D,0             ; zero out D
        DAD     D               ; add in the dispatch table
        DAD     D               ; once more - over two bytes
        MOV     E,M             ; pull the jump address
        INX     H               ; into
        MOV     D,M             ; DE
        LHLD    FCB             ; get the info word into HL
        XCHG                    ; swap DE and HL
        PCHL                    ; jump to the command routine

;****
; command dispatch table

CMMNDS: DW      WBOOTF          ;  0: System reset
        DW      REDCON          ;  1: Console input
        DW      WRTCON          ;  2: Console output
        DW      REDRDR          ;  3: Reader input
        DW      PUNF            ;  4: Punch output
        DW      LISTF           ;  5: List output
        DW      DIRTIO          ;  6: Direct console I/O
        DW      GETIOB          ;  7: Get I/O Byte
        DW      PUTIOB          ;  8: Set I/O Byte
        DW      PRNBUF          ;  9: Print string
        DW      REDBUF          ; 10: Read console buffer
        DW      GCSTAT          ; 11: Get console status
        DW      GETVER          ; 12: Get version number ( 2.2 )

;****
; Read next console character

CONIN:  LXI     H,CHRRDY        ; Point to the char ready flag
        MOV     A,M             ; move the ready byte into A
        MVI     M,0             ; and zero out the flag
        ORA     A               ; was anyone home
        RNZ                     ; return if not
        JMP     CONIF           ; otherwise go get the thing

;****
; Read console character, echo print if it is ok

CIECHO: CALL    CONIN           ; get a character
        CALL    GRAFIC          ; check the control characters
        RC                      ; return if the char is not printable
        PUSH    PSW             ; otherwise save it
        MOV     C,A             ; put a copy into C
        CALL    WRTCON          ; and print it out
        POP     PSW             ; restore it
        RET                     ; and return to sender

;****
;see if A is a good control char, ret with CY set if not

GRAFIC: CPI     CR              ; test for carriage return
        RZ                      ; return if it was
        CPI     LF              ; how about line feed
        RZ                      ; that is ok
        CPI     TAB             ; as is tab
        RZ                      ; so back with it
        CPI     BACKSP          ; Backspace in 2.0
        RZ                      ; is known
        CPI     ' '             ; test all other control characters
        RET                     ; and go back with carry set for no echo

;****
; Check for console break and abort

CONBRK: LDA     CHRRDY          ; get the character ready byte
        ORA     A               ; and check for waiting char
        JNZ     CB1             ; non zero says something is there
        CALL    CONSF           ; check the console if none there
        ANI     01H             ; and in the status bit
        RZ                      ; return if it came up zero
        CALL    CONIF           ; otherwise go get the waiting char
        CPI     CTRLS           ; was it a control-s
        JNZ     CB0             ; if not return with ready flag set
        CALL    CONIF           ; if it was wait for the next char
        CPI     CTRLC           ; is this one control c?
        JZ      BOOTV           ; if so we reboot
        XRA     A               ; or else zero a
        RET                     ; and simply return

CB0:    STA     CHRRDY          ; Save input char
CB1:    MVI     A,TRUE          ; and say true to the caller
        RET                     ; and go back

;****
; Output char in C to console, list also if LSTCPY = true

CONOUT: LDA     CTEMP1          ; get the first temp column counter
        ORA     A               ; is it zero?
        JNZ     CONOU1          ; if nonzero jump over
        PUSH    B               ; otherwise save input character
        CALL    CONBRK          ; Check for abort
        POP     B               ; recover the char
        PUSH    B               ; save it again
        CALL    CONOF           ; and print the character on the console
        POP     B               ; recover once more
        PUSH    B               ; would you believe save it again
        LDA     LSTCPY          ; get the list flag byte
        ORA     A               ; to set flags
        CNZ     LISTF           ;  and to list if LSTCPY=true
        POP     B               ; restore char one last time
CONOU1: MOV     A,C             ; put the byte into A
        LXI     H,COLUMN        ; point to the buffer column counter
        CPI     7FH             ; Rubout ?
        RZ                      ; return if so
        INR     M               ; Increment column
        CPI     ' '             ; is the character a space?
        RNC                     ; return if less - must be control
        DCR     M               ; Decrement column
        MOV     A,M             ; and get the character there
        ORA     A               ; check for a null
        RZ                      ; return if it is
        MOV     A,C             ; move the char into C
        CPI     BACKSP          ; was it a backspace?
        JNZ     CONOU2          ; if not jump over
        DCR     M               ; Decrement column
        RET                     ; and return

CONOU2: CPI     LF              ; was it a linefeed?
        RNZ                     ; return if not again
        MVI     M,0             ; Set column to 0
        RET                     ; and return

;****
; Print char in C at console, convert Ctrl chars to ^[char]

CTLOUT: MOV     A,C             ; move the char into A
        CALL    GRAFIC          ; see if it is printable
        JNC     WRTCON          ; jump past cause it is ok
        PUSH    PSW             ; otherwise save ctrl char on the stack
        MVI     C,5EH           ; get the "^" char
        CALL    CONOUT          ; and print it
        POP     PSW             ; get the char back
        ORI     40H             ; add in the bias to make it print
        MOV     C,A             ; put it into C for the next

;****
; BDOS function 2: write to the system console char in C

WRTCON: MOV     A,C             ; which puts it into A
        CPI     TAB             ; check for tab
        JNZ     CONOUT          ; if not jump and print
TABOUT: MVI     C,' '           ; Space gets printed to expand tabs
        CALL    CONOUT          ;  to
        LDA     COLUMN          ;   next
        ANI     07H             ;    tab
        JNZ     TABOUT          ;     stop
        RET                     ; Return

DELAST: CALL    BACKUP          ; back up one character
        MVI     C,' '           ; then get a blank
        CALL    CONOF           ; and print it out
BACKUP: MVI     C,BACKSP        ; get a backspace
        JMP     CONOF           ; and print it as well to move into spot

;****
; Print pound sign, CRLF, and fix columns

LBCRLF: MVI     C,'#'           ; get a pound sign
        CALL    CONOUT          ; and print it
        CALL    CRLF            ; Turn up a new line
LB1:    LDA     COLUMN          ; get the column counter
        LXI     H,CTEMP2        ; point to the temp counter
        CMP     M               ; are they equal?
        RNC                     ; not there yet
        MVI     C,' '           ; so get a space
        CALL    CONOUT          ; and print it out
        JMP     LB1             ; loop til the counts are the same

;****
; Print CR/LF at console

CRLF:   MVI     C,CR            ;  get a cr
        CALL    CONOUT          ; and print it out
        MVI     C,LF            ; followed by a lf
        JMP     CONOUT          ; which goes out too

;****
; Print string at (BC) until '$' with TAB expansion

PRINT:  LDAX    B               ; get the byte at (BC)
        CPI     '$'             ; is it the end mark?
        RZ                      ; if so we are done
        INX     B               ; otherwise bump the pointer
        PUSH    B               ; and save it in the stack
        MOV     C,A             ; get the character into C
        CALL    WRTCON          ; write it out expanding tabs
        POP     B               ; recover the pointer
        JMP     PRINT           ; and loop til we hit the stop

;****
; BDOS function 10: Read console buffer at
;     enter with BC -> console buffer address

REDBUF: LDA     COLUMN          ; get the column counter into A
        STA     CTEMP2          ; save it at CTEMP2
        LHLD    FCB             ; get the information into HL
        MOV     C,M             ; get the buffer count byte
        INX     H               ; and bump the pointer to the next spot
        PUSH    H               ; save it for later
        MVI     B,0             ; zero B
RB0:    PUSH    B               ; save BC for later
        PUSH    H               ; and HL as well
RB1:    CALL    CONIN           ; go get a char from the console
        ANI     7FH             ; strip the parity bit
        POP     H               ; recover HL
        POP     B               ; and BC
        CPI     CR              ; is this character a CR?
        JZ      RBEXIT          ; if so jump over
        CPI     LF              ; how about a LF
        JZ      RBEXIT          ; jump with that as well
        CPI     BACKSP          ; do we have a backspace?
        JNZ     CHKRUB          ; if not over we go
        MOV     A,B             ; put B into A
        ORA     A               ; is it still zero?
        JZ      RB0             ; if so go get another character
        DCR     B               ; if not decrement the count in B
        LDA     COLUMN          ; get the column counter
        STA     CTEMP1          ; save it at CTEMP1 for later
        JMP     RB65            ; jump over

; Check for Rubout (remove & echo last char.)

CHKRUB: CPI     7FH             ; do we have a rubout?
        JNZ     CHKEOL          ; if not jump over
        MOV     A,B             ; if so move b into A
        ORA     A               ; set the flags
        JZ      RB0             ; if b was zero go get another
        MOV     A,M             ; get the char at (ODATA)
        DCR     B               ; decrement the count in B
        DCX     H               ; point back to FCB
        JMP     RB10            ; jump to echo the char

; Check for Control-E (physical end-of-line)

CHKEOL: CPI     CTRLE           ;  is it end of line?
        JNZ     CKPTOG          ; jump over if not
        PUSH    B               ; if so save BC
        PUSH    H               ; and FCB address
        CALL    CRLF            ; Turn up a new line
        XRA     A               ; zero A
        STA     CTEMP2          ; set it into CTEMP2
        JMP     RB1             ; and go get more

; Check for Control-P

CKPTOG: CPI     CTRLP           ; is it the print toggle
        JNZ     CKBOL           ; if not jump past
        PUSH    H               ; if so save FCB address
        LXI     H,LSTCPY        ; get the pointer to print toggle byte
        MVI     A,01H           ; put a 1 into A
        SUB     M               ; subtract it from the toggle
        MOV     M,A             ; and put it back
        POP     H               ; recover FCB
        JMP     RB0             ; and go get more

; Check for Control-X (bacK space to beg. current line)

CKBOL:  CPI     CTRLX           ; do we back up?
        JNZ     CKREML          ; if not on to the next choice
        POP     H               ; if so restore the stack pointer
BLOOP:  LDA     CTEMP2          ; get the byte at CTEMP2
        LXI     H,COLUMN        ; and point to the column counter
        CMP     M               ; are they the same?
        JNC     REDBUF          ; if so go try again for input
        DCR     M               ; if not decrement the CTEMP2 count
        CALL    DELAST          ; delete the character there
        JMP     BLOOP           ; and loop until we are done

; check for control-U

CKREML: CPI     CTRLU           ; do we remove the line after newline?
        JNZ     CKRETL          ; if not try again
        CALL    LBCRLF          ; if so print a "#" and CR
        POP     H               ; restore the stack
        JMP     REDBUF          ; and try for input again

; Check for Control-R (retype current line after new line)

CKRETL: CPI     CTRLR           ; want to retype?
        JNZ     ECHOCC          ; if not onward for next
RB65:   PUSH    B               ; if so save the count in B
        CALL    LBCRLF          ; print a "#" and CRLF
        POP     B               ; recover ODATA
        POP     H               ; and FCB
        PUSH    H               ; saving FCB again
        PUSH    B               ; and ODATA
RB7:    MOV     A,B             ; move the count into
        ORA     A               ; see if it is zero
        JZ      FIXCOL          ; if so jump over
        INX     H               ; if not point to ODATA
        MOV     C,M             ; pull the byte there into C
        DCR     B               ; decrement the count
        PUSH    B               ; save it on the stack
        PUSH    H               ; and the ODATA pointer
        CALL    CTLOUT          ; print it out expanding control chars
        POP     H               ; recover the ODATA pointer
        POP     B               ; and the count in B
        JMP     RB7             ; loop until the line is out

;fix up the column counters

FIXCOL: PUSH    H               ; save the pointer
        LDA     CTEMP1          ; get CTEMP1
        ORA     A               ; set the flags
        JZ      RB1             ; if zero go get the next character
        LXI     H,COLUMN        ; point to the column counter
        SUB     M               ; subtract it from the value of CTEMP1
        STA     CTEMP1          ; and save this back in CTEMP1
FXLOOP: CALL    DELAST          ; delete the last character
        LXI     H,CTEMP1        ; point to CTEMP1
        DCR     M               ; decrement it by one
        JNZ     FXLOOP          ; loop to delete all of them
        JMP     RB1             ; go get the next character

;echo the control character

ECHOCC: INX     H               ; must be some other control character
        MOV     M,A             ; put the character into ODATA+1
        INR     B               ; bump the count by one
RB10:   PUSH    B               ; save it on the stack
        PUSH    H               ; and the pointer as well
        MOV     C,A             ; put the character into C
        CALL    CTLOUT          ; print it out with grafic control chars
        POP     H               ; recover the pointer
        POP     B               ; and the count
        MOV     A,M             ; put the byte at (HL) into A
        CPI     CTRLC           ; is it an abort?
        MOV     A,B             ; put the count into A
        JNZ     RB11            ; if no abort jump over
        CPI     01H             ; is the count 1?
        JZ      BOOTV           ; if so boot
RB11:   CMP     C               ; if not does it equal C
        JC      RB0             ; if less go get another char
RBEXIT: POP     H               ; recover the pointer
        MOV     M,B             ; put the count in b there
        MVI     C,CR            ; get a CR
        JMP     CONOUT          ; and print it out

;****
;BDOS function 1: Read console - return with byte in A

REDCON: CALL    CIECHO          ; get a char echo if printable
        JMP     GOBAK           ; and go back with it

;****
; BDOS function 3: Read reader - return with byte in A

REDRDR: CALL    READF           ; get byte from reader
        JMP     GOBAK           ; and return with it

;****
; BDOS function 6: Direct I/O
;       on entry, C=FF for input, C=char for output
;       (Book says E reg vice C)
;        appears can enter with FE or FF --- ????

;       return with char or status in A

DIRTIO: MOV     A,C             ; Get request
        INR     A               ; Test for FF=input request
        JZ      INREQ           ; Skip down if input request
        INR     A               ; if FF adding one will set zero flag
        JZ      CONSF           ; if it was go get console status
        JMP     CONOF           ; otherwise go send it out

INREQ:  CALL    CONSF           ; get console status
        ORA     A               ; set flags
        JZ      REXIT           ; return if none - restore first
        CALL    CONIF           ; if someone is there go get it
        JMP     GOBAK           ; and return with it

;****
; BDOS function 7: get IO byte into A

GETIOB: LDA     IOBYTE          ; get the iobyte
        JMP     GOBAK           ; and go back with it

;****
; BDOS function 8: set IO byte from C into place

PUTIOB: LXI     H,IOBYTE        ; point to the iobyte
        MOV     M,C             ; put the new value in from C
        RET                     ; and return

;****
; BDOS function 9: Print console buffer until '$'
;       entry string address in DE

PRNBUF: XCHG                    ; swap DE and HL - HL points to buffer
        MOV     C,L             ; and get a copy
        MOV     B,H             ;   of HL into BC
        JMP     PRINT           ; go to the print routine

;****
; BDOS function 11: check console status - return in A

GCSTAT: CALL    CONBRK          ; Check for abort
GOBAK:  STA     ODATA           ; save result in return info byte
JR:     RET                     ; and go back to caller

JR1:    MVI     A,01H           ; get a 1 for return
        JMP     GOBAK           ; set it in to rinfo and return

;****
; BDOS function 12: return version number

GETVER:
        MVI     A,22H
        JMP     GOBAK

;****
; bdos exit routine

BEXIT:  LDA     OUT1            ; get the out flag for drive reset
        ORA     A               ; set the flags
        JZ      REXIT           ; if zero we may exit as is
        LHLD    FCB             ; otherwise get the FCB address
        MVI     M,0             ; put a zero into drive select byte
        LDA     OLDDSK          ; get the old disk out
        ORA     A               ; was it zero
        JZ      REXIT           ; if so exit
        MOV     M,A             ; otherwise set in the old disk byte
        LDA     OUTDSK          ; get the disk to relog
        STA     IDATA           ; save it for the login
        CALL    LOGIN           ; go log in the old disk

REXIT:  LHLD    OLDSP           ; get the old stack pointer out
        SPHL                    ; put it back in place
        LHLD    ODATA           ; get the output data into place
        MOV     A,L             ; put L into A
        MOV     B,H             ; and H into B
        RET                     ; then return from BDOS happy
;****
; hand off all higher calls to 8086 handler
;
MSDOSHANDLER:
        lhld    fcb         ; recover de
        mov     d,h
        mov     e,l
        mov     c,a         ; put call back
        calln   bdoshandle  ; special v20 call
BDOSCALL   EQU  $-1
        lhld    bdhl        ; get return
        shld    odata       ; should return in hl and a
        jmp     Bexit
LOGIN:
        lxi     h,bdbc
        mvi     m,0eh  ; select the disk in a
        lxi     h,bdpsw
        mov     m,a
        CALLN   BDOSHANDLE
LOGCALL EQU     $-1
        ret

; put data at the rear
;****
; console input buffer data storage area


; move part of bios here

COLDBOOT:   ; should load addresses in lower memory
jmp0:
      ; MOVE INTERRUPT LOCATIONS INTO PLACE
      ; FOR BDOS AND BIOS
        LDA    BIOSHAN
        STA    CMMNCALL  ; COMMON BIOS CALL HANDLER
        STA    WMNCALL   ; WARMBOOT CALL HANDLER
        LDA    BDOSHAN
        STA    LOGCALL
        STA    BDOSCALL  ; AND DO WARM BOOT

jmp1: ; warm boot
     ; zero out data areas in bdos also
     lxi    h,datastart
     lxi    b,dataend-datastart
luuu:
    mov    a,b
    ora    c
    jz     doneit
    xra    a
    mov    m,a
    inx    h
    dcx    b
    jmp    luuu
doneit:
     mvi    a,1
     jmp    warmer

jmp2:
     mvi    a,2
     jmp    commonbios

jmp3:
     mvi    a,3
     jmp    commonbios

jmp4:
     mvi    a,4
     jmp    commonbios

jmp5:
     mvi    a,5
     jmp    commonbios

jmp6:
     mvi    a,6
     jmp    commonbios

jmp7:
     mvi    a,7
     jmp    commonbios

jmp8:
     mvi    a,8
     jmp    commonbios

jmp9:
     mvi    a,9
     jmp    commonbios

jmp10:
     mvi    a,10
     jmp    commonbios

jmp11:
     mvi    a,11
     jmp    commonbios

jmp12:
     mvi    a,12
     jmp    commonbios

jmp13:
     mvi    a,13
     jmp    commonbios

jmp14:
     mvi    a,14
     jmp    commonbios

jmp15:
     mvi    a,15
     jmp    commonbios

jmp16:
     mvi    a,16
     jmp    commonbios

FILLEND EQU     $

          ORG   SERIAL + 500H;
BIOS:
COLD:     jmp     coldboot
WBOOTF:   jmp     jmp1   ; do dos call to load the ccp again
                         ; under CP/M-86, could reinitialize BDOS
CONSF:    jmp     jmp2   ; CONSOLE STATUS
CONIF:    jmp     jmp3   ; conin
CONOF:    jmp     jmp4   ; Conout
LISTF:    jmp     jmp5   ; list
PUNF:     jmp     jmp6   ; punch
READF:    jmp     jmp7   ; reader

;the following (except for listst) are not implemented
;and will warm boot the CP/M-80 system

HOMF:  jmp     jmp8    ; notimpl; home
SELF:  jmp     jmp9    ; notimpl; seldsk
TRKF:  jmp     jmp10   ; notimpl; settrk
SECF:  jmp     jmp11   ; notimpl; setdsk
DMAF:  jmp     jmp12   ; setdma
DRDF:  jmp     jmp13   ; notimpl; read
DWRF:  jmp     jmp14   ; notimpl; write
LISTS: jmp     jmp15   ; listst ;
SECTRN:jmp     jmp16   ; sectran

; pass all bios calls onto the turbo handler
; wipes out a,bc,hl

breakout:    ; return permanently to 8086 mode where we left with BRKEM
     RETEM   ; to whence it came

commonbios: ; call 8088 code
     sta    bpsw           ; show call
     lda    abortflag      ; TEST FOR ABORT
     ora    a
     jnz    breakout
; most cp/m bios routines only use bc
; disk routines may use more, but not implemented here
     mov    h,b
     mov    l,c
     shld   bbc
     CALLN  BIOSHANDLE     ; go to turbo handler and do it
cmmncall EQU  $-1
     lhld   bhl            ; bios returns in a and hl
     lda    bpsw
     ret                   ; this one not used usually

warmer:
     sta    bpsw           ; show call
     lda    abortflag      ; TEST FOR ABORT
     ora    a
     jnz    breakout
     CALLN   BIOSHANDLE
WMNCALL      EQU   $-1
     LXI     SP,CPMSTACK
     LHLD    BHL           ; get the address
     PCHL                  ; and jump

codeend equ  $
     org     0ff80h;

cpmstack:   dw   0

     ORG     0FFB0H

COLDHAN:     DB    80H
CCPHAN:      DB    81H
BDOSHAN:     DB    82H
BIOSHAN:     DB    83H

     org     0ffc0h;
ccpreg:
ccppsw:   dw    0       ;ax
ccphl:    dw    0       ;bx
ccpbc:    dw    0       ;cx
ccpde:    dw    0       ;dx

          org   0ffd0h
bpsw:     dw    0   ;ax
bhl:      dw    0   ;bx
bbc:      dw    0   ;cx
bde:      dw    0   ;dx

         org   0ffe0h
BDOSreg:
bdpsw:   dw    0   ;ax
bdhl:    dw    0   ;bx
bdbc:    dw    0   ;cx
bdde:    dw    0   ;dx

         org   0ffffh;
abortflag:  db   0;  non-zero aborts
biosend EQU $

     end    ; stub bdos-bios
