#TITLE  "8080 EMULATOR FOR NEC V-30  BY ESKAY 12/07/85"
       #PAGE   132,66
       MODULE  "EmulV30"
;
;       This copyrighted program has been released to the Public Domain
;       for NONCOMMERCIAL uses only. Users wishing to use this utility
;       for ANY purpose other than personal use must first obtain written
;       authorization. Commercial distribution of this utility is
;       strictly forbidden without authorization and a $20.00 royalty fee
;       per distributed copy.
;       The above does not apply to distribution via "SIG-M library"!
;
;       The author assumes no liability of any kind for damages arising
;       from the use or inability to use this utility.
;
JMP     ==      0XC3
;
; below we define the CP/M version number which is returned in response to
; BDOS function 12. Note that TurboDOS and MP/M-86 users should select
; "0X0130" to recognize MP/M functions. See .DOC file for more info.
;
CPMVER  ==      0X0022          ; CP/M VERSION RETURNED
;
; below, the new BDOS interrupt vector is defined
;
BDOSN   ==      0XFE            ; NEW BDOS INTERRUPT FOR EMULATION MODE
;
       LOC     Extra#
;
;       THIS BECOMES THE 8080 ENVIRONMENT
;       SAVE A FEW BYTES BY STATIC ALLOCATION RATHER
;       THAN DYNAMIC.
;
ENV80:  RES     0X7FFF
       RES     0X7FFF
;
       LOC     Data#
;
;       IN THIS VERSION OF EMUL, THE 8080 ENVIRONMENT IS
;       CARRIED IN THE DATA SEGMENT AND LOADED INTO ALLOCATED
;       RAM IN A 2-STEP PROCESS. NOTE THAT DATA SEGMENT BECOMES
;       USABLE ONLY FROM 100H, THUS ALL EQUATES IN THE BDOS/BIOS
;       AREA ARE SEEMINGLY OFF BY 0X100.
;
WBOOT:  BYTE    JMP                     ; BASE PAGE WARMBOOT JUMP
       WORD    &WBOOTE
       BYTE    0
       BYTE    0
BDOS:   BYTE    JMP                     ; BDOS ENTRY POINT
       WORD    &BDOSE
       LOC     WBOOT+0X5C
DFCB1:  BYTE    0,"           ",0,0,0,0 ; DEFAULT FCB 1
DFCB2:  BYTE    0,"           ",0,0,0,0 ; DEFAULT FCB 2
       LOC     WBOOT+0X80
DBUF:   BYTE    0                       ; DEFAULT DMA BUFFER
       RES     127
TPA:    BYTE    0X11                    ; LXI D,TEST1
       WORD    &TEST1-0X100
       BYTE    0X0E,0X09               ; MVI C,9
       BYTE    0XCD                    ; CALL BDOS
       WORD    &BDOS-0X100
       BYTE    JMP                     ; JMP WBOOT
       WORD    &WBOOT-0X100
TEST1:  BYTE    "ERROR: no command line specified.\r\n\7"
       BYTE    "USAGE:\r\n"
       BYTE    "EMUL <command> [tail]\r\n"
       BYTE    "Where <command> is an 8080 CP/M .COM file which must be\r\n"
       BYTE    "currently accessible, and [tail] is an optional command\r\n"
       BYTE    "tail which is to be passed to the command file.\r\n"
       BYTE    "    This message is produced by the emulation mode.\r\n\n"
       BYTE    "NOTE: commercial distribution without authorization\r\n"
       BYTE    "strictly prohibited. License fee for commercial use: 20.00"
       BYTE    " dollars.\r\n"
       BYTE    "(c) 1985, S. Kluger, 7120 Skillman #2104,"
       BYTE    " Dallas TX 75231\r\n\n"
       BYTE    "CP/M-80 available TPA space = 0100..FEFC (65020 bytes)."
       BYTE    "\r\n$"
;
BEGENV  ==      .                       ; BEGINNING OF BDOS/BIOS ENVIRONMENT
BDOSE   ==      WBOOT+0XFDFD
       BYTE    JMP
       WORD    &NATIVE
;
; SIMULATED BIOS TABLE
;
CBOOT   ==      BDOSE+3
       BYTE    JMP                     ; COLD BOOT
       WORD    &ENDEM
WBOOTE  ==      BDOSE+6
       BYTE    JMP                     ; WARMBOOT ENTRY (RETURN TO 16 BIT)
       WORD    &ENDEM
CONST   ==      BDOSE+9
       BYTE    JMP                     ; CON STATUS
       WORD    &BCONST
CONIN   ==      BDOSE+12
       BYTE    JMP                     ; CON IN
       WORD    &BCONIN
CONOT   ==      BDOSE+15
       BYTE    JMP                     ; CON OUT
       WORD    &BCONOT
LIST    ==      BDOSE+18
       BYTE    JMP                     ; LST OUT
       WORD    &BLIST
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; LIST STATUS
       WORD    &BLSTS
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
       BYTE    JMP                     ; REST IS INVALID
       WORD    &INVAL
;
       RES     7                       ; LEAVE SOME ROOM
;
BCONST  ==      CBOOT+0X40
       BYTE    0X0E,0X0B,JMP
       WORD    &NATIVE
BCONIN  ==      CBOOT+0X45
       BYTE    0X0E,3,JMP
       WORD    &NATIVE
BCONOT  ==      CBOOT+0X4A
       BYTE    0X59,0X0E,4,JMP
       WORD    &NATIVE
BLIST   ==      CBOOT+0X50
       BYTE    0X59,0X0E,5,JMP
       WORD    &NATIVE
BLSTS   ==      CBOOT+0X56
       BYTE    0XAF,0XC9               ; XRA A ! RET
       BYTE    0                       ; NOP
;
; ENTER HERE WHEN GETTING CONTROL FROM ABOVE
;
ENTRY   ==      CBOOT+0X59
       BYTE    0X31
       WORD    &STK80
       BYTE    0X21,0,0                ; LXI   H,0
       BYTE    0XE5                    ; PUSH  H
       BYTE    0XC3,0,1                ; JMP   100H
;
; CALL THE HIGHER BEING IN THE V30
;
NATIVE  ==      CBOOT+0X63
       BYTE    0X79                    ; MOV   A,C     ; GET FUNCTION #
       BYTE    0XFE,0X0C               ; CPI   12      ; SEE IF VERSION CALL
       BYTE    0XC2                    ; JNZ   NO12    ; NO, SKIP
       WORD    &NO12
       BYTE    0X21                    ; LXI   H,CPMVER ; SET UP OUR VERSION
CV      ==      CBOOT+0X6A
       WORD    CPMVER
       BYTE    0XC9                    ; RET
NO12    ==      CBOOT+0X6D
       BYTE    0XED,0XED,BDOSN         ; CALL NATIVE (INT BDOSN)
       BYTE    0XC9                    ; RET
;
; GO BACK TO CREATOR
;
ENDEM   ==      CBOOT+0X71
       BYTE    0XED,0XFD               ; RETURN FROM EMULATION
;
; INVALID BIOS CALL
;
INVAL   ==      CBOOT+0X73
       BYTE    0X11                    ; LXI D,ERRMSG
       WORD    &ERRMSG
       BYTE    0X0E,0X09               ; MVI C,9
       BYTE    0XCD                    ; CALL NO12 (BDOS)
       WORD    &NO12
       BYTE    JMP                     ; JMP ENDEM (QUIT)
       WORD    &ENDEM
;
ERRMSG  ==      CBOOT+0X7E
       BYTE    "\r\n\nBIOS CALL NOT SUPPORTED!\r\n\n\7$"
;
STK80   ==      WBOOT+0XFEF0
;
ENDENV  ==      .                       ; END OF ENVIRONMENT
;
       LOC     Data#
;
;       +--------------------------------------------------+
;       | THIS IS THE EMULATOR CONTROL PROGRAM'S DATA AREA |
;       +--------------------------------------------------+
;
BANNER: BYTE    "\r\n---------------------------------------------"
       BYTE    "\r\nEMUL           Version 2.20          12/07/85"
       BYTE    "\r\nCP/M-80 emulator  for CP/M-86 and NEC V30 CPU"
       BYTE    "\r\nCopyright 1985 S. Kluger. All Rights Reserved"
       BYTE    "\r\n---------------------------------------------\r\n\n$"
;
BADCPU: BYTE    "\r\nNOT V20 OR V30 CPU???\r\n$"
NOFIL:  BYTE    "ERROR:  $"
NOFIL1: BYTE    "  NOT FOUND!\r\n\7$"
EMDONE: BYTE    "\r\nEMUL: end of emulation\r\n$"
;
DMABAS: WORD    0                       ; ENTRY DMA BASE
DMAOFF: WORD    0                       ; ENTRY DMA OFFSET
;
       RES     0X100
STACK   ==      .
;
;       +----------------------------------------------------+
;       | THIS IS THE CONTROL PROGRAM. LOAD PROGRAM, PROCESS |
;       | COMMAND LINE AND THEN SEND CONTROL TO WORLD BELOW. |
;       +----------------------------------------------------+
;
       LOC     Code#
;
START:  MOV     AX,DS                   ; GET DATA SEGMENT
       MOV     SS,AX                   ; SET UP STACK
       MOV     SP,&STACK
       CS MOV  NTRYDS,AX               ; SAVE ENTRY DS IN KNOWN LOCATION
       MOV     CL,=52                  ; GET DMA ADDRESS
       PUSH    ES                      ; PRESERVE 8080 PAGE
       CALL    IBDOS
       MOV     DMABAS,ES
       MOV     DMAOFF,BX
       POP     ES
       MOV     DX,&BANNER              ; SAY WHO WE ARE
       MOV     CL,=9
       CALL    IBDOS
;
; MAKE SOME TESTS (CHECK IF THIS IS V20 OR V30)
;
       MOV     CL,=0X21
       MOV     AX,=2
       SHR     AX,CL
       TEST    AX,=1                   ; NONZERO MEANS 80186/188
       JZ      __MYB                   ; SKIP IF "MAYBE"
__CBAD: MOV     DX,&BADCPU
       JMP     ERROR
;
__MYB:  XOR     AL,AL
       MOV     AH,=0X99
       BYTE    0X0F,0X28,0XC4          ; NEC INSTRUCTION "ROL4 AH"
       OR      AL,AL                   ; MUST HAVE CHANGED
       JZ      __CBAD                  ; NOT V20/30
;
; PREPARE 8080 ENVIRONMENT
;
       MOV     CX,=0X8000              ; FIRST CLEAR RAM
       MOV     DI,=0
       XOR     AX,AX
       REP STOS WORD
       MOV     SI,&WBOOT               ; MOVE BASE PAGE PLUS DEFAULT PGM
       MOV     DI,=0
       MOV     CX,=(BEGENV-WBOOT)
       REP MOVS BYTE
       MOV     SI,&BEGENV              ; MOVE BDOS/BIOS AREA
       MOV     DI,&BDOSE
       MOV     CX,=(ENDENV-BEGENV)
       REP MOVS BYTE
;
; NOW LOAD THE PROGRAM
;
       MOV     CX,=0X7F                ; MOVE COMMAND LINE
       MOV     SI,=0X80
       MOV     DI,SI
       REP MOVS BYTE
       CMP     0X5D,=BYTE ' '          ; EMPTY FILENAME?
       JNZ     __V
       JMP     SETDMA                  ; YES, GO RUN DEFAULT PROGRAM
;
__V:    MOV     0X5C+9,=WORD 0X4F43     ; MAKE ".COM"
       MOV     0X5C+11,=BYTE 'M'
       MOV     DX,&0X5C                ; POINT TO FILENAME
       MOV     CL,=15                  ; OPEN FILE
       CALL    IBDOS
       INC     AL
       JNZ     OO
       MOV     DX,&NOFIL
       MOV     CL,=9
       CALL    IBDOS
       MOV     SI,=0X5C                ; POINT TO FCB
       MOV     AL,[SI]
       INC     SI
       OR      AL,AL
       JZ      __NDV
       ADD     AL,=0X40
       CALL    PUTCH
       MOV     AL,=':'
       CALL    PUTCH
__NDV:  MOV     CX,=11
__DFN:  MOV     AL,[SI]
       INC     SI
       PUSHA
       CALL    PUTCH
       POPA
       LOOP    __DFN
       MOV     DX,&NOFIL1
ERROR:  MOV     CL,=9
       CALL    IBDOS
       MOV     CL,=0
       JMP     IBDOS
;
OO:     MOV     DI,=0X100
__RL:   MOV     SI,=0X80
       MOV     CL,=20                  ; READ A BLOCK
       MOV     DX,=0X5C
       CALL    IBDOS
       OR      AL,AL
       JNZ     LOADED
       MOV     CX,=64
       REP MOVS WORD
       JMPS    __RL
;
LOADED: MOV     CL,=16                  ; CLOSE THE FILE
       MOV     DX,=0X5C
       CALL    IBDOS
;
; SET UP FCBS
;
       MOV     AX,ES
       MOV     DS,AX
       MOV     CX,=0X10
       MOV     SI,&DFCB2-0X100
       MOV     DI,&DFCB1-0X100
       REP MOVS BYTE
       MOV     BX,&DFCB2-0X100
       MOV     [BX],=BYTE 0
       MOV     CX,=11
__F:    INC     BX
       MOV     [BX],=BYTE ' '
       LOOP    __F
       MOV     BX,&DBUF-0X100
       MOV     CL,[BX]
       INC     CL
       MOV     CH,=0
       PUSH    CX
       MOV     SI,&DBUF+2-0X100
       MOV     DI,&DBUF+1-0X100
__CLL:  CMP     CL,=0
       JZ      BLCL
       DEC     CL
       CMP     [SI],=BYTE ' '
       JZ      __FB
       INC     SI
       JMPS    __CLL
;
__FB:   DEC     CL
       MOV     [BX],CL
       REP MOVS BYTE
       POP     CX
__ZL:   MOV     [DI],=BYTE 0
       INC     DI
       CMP     DI,=0X100
       JZ      __ZZ
       LOOP    __ZL
__ZZ:   MOV     SI,=0X81                ; SOURCE POINTER
       MOV     DI,=0X5C                ; DESTINATION POINTER
       CALL    PFN                     ; PARSE FN
       JC      SETDMA                  ; SKIP IF END OF LINE
       MOV     DI,=0X6C                ; NEXT DESTINATION POINTER
       CALL    PFN
       JMPS    SETDMA
;
BLCL:   MOV     [BX],=BYTE 0
;
; NOW SET UP DMA BUFFER
;
SETDMA: MOV     CL,=51                  ; SET DMA BASE (OFFSET STILL 0X80)
       MOV     DX,ES
       CALL    IBDOS
;
; SET UP INTERRUPT VECTOR AND EXECUTE
;
       XOR     AX,AX
       MOV     DS,AX
       MOV     0X3FC,=WORD ENTRY
       MOV     0X3FE,ES
       MOV     BDOSN*4,=WORD BDOSI
       MOV     BDOSN*4+2,CS
       PUSH    ES                      ; GET THE 8080 SEGMENT
       POP     DS                      ; PUT INTO DATA SEG
;
       BYTE    0X0F,0XFF,0XFF          ; BRKEM 0XFF
;
       CS MOV  AX,NTRYDS               ; ENT ENTRY DATA SEGMENT BACK
       MOV     DS,AX
       MOV     CL,=51                  ; RESET DMA BASE
       MOV     DX,DMABAS
       CALL    IBDOS
       MOV     CL,=9
       MOV     DX,&EMDONE
       CALL    IBDOS
       MOV     CL,=0                   ; EXIT
;
; INTERNAL BDOS ENTRY POINT, SAVE ES
;
IBDOS:  PUSH    ES
       INT     0XE0
       POP     ES
       RET
;
; OUTPUT A CHARACTER (USED FOR FILENAME DISPLAY)
;
PUTCH:  MOV     CL,=2
       MOV     DL,AL
       JMPS    IBDOS
;
; FILE NAME PARSER
; IN:  SI=SOURCE (NULL TERMINATED), DI=DESTINATION
; OUT: SI=POINTER TO NEXT NON-DELIMITER
;      IF CARRY SET, THEN END OF LINE
;
PFN:    CALL    SKNB                    ; SKIP TO NONBLANK
       CMP     1[SI],=BYTE ':'         ; DRIVE?
       JNZ     __NDR                   ;   NO, SKIP
       MOV     AL,[SI]
       SUB     AL,=0X40                ; MAKE 1..16
       CMP     AL,=16
       JA      __EOL
       MOV     [DI],AL
       INC     SI
       INC     SI
__NDR:  INC     DI                      ; POINT TO FILENAME PART
       MOV     CL,=0
__LP:   MOV     AL,[SI]                 ; GET BYTE
       CMP     AL,=' '                 ; CHECK DELIM
       JZ      __DL
       CMP     AL,=0X5C
       JZ      __DL
       CMP     AL,=';'
       JZ      __DL
       CMP     AL,=0                   ; EOL?
       JZ      __EOL
       CMP     AL,='.'
       JZ      __PER
       CMP     CL,=12
       JZ      __SKP
       MOV     [DI],AL
__SKP:  INC     CL
       INC     DI
__SKP1: INC     SI
       JMPS    __LP
;
__DL:   INC     DI
       RET
;
__PER:  CMP     CL,=8
       JNZ     __N8
       JMPS    __SKP1
;
__N8:   INC     DI
       INC     CL
       JMPS    __PER
;
__EOL:  STC
       RET
;
SKNB:   MOV     AL,[SI]
       CMP     AL,=' '
       JZ      __ISB
       CMP     AL,=':'
       JZ      __ISB
       CMP     AL,=';'
       JZ      __ISB
       CMP     AL,=0X5C
       JZ      __ISB
       CMP     AL,='='
       JNZ     __NB
__ISB:  INC     SI
       JMPS    SKNB
;
__NB:   RET
;
NTRYDS: WORD    0                       ; ENTRY DATA SEGMENT
;
; EMULATOR BDOS INTERRUPT
;
BDOSI:  PUSH    BP                      ; SAVE EMULATOR STACK
       CALL    IBDOS
       POP     BP
       IRET
       END
   IF CARRY SET, THEN END OF LINE
;
PFN:    CALL    SKNB                    ; SKIP TO NONBLA