; DSKRAM - A RAMDISK IMPLEMENTATION FOR TURBODOS
; 16 BIT SLAVES WITH SUFFICIENT MEMORY
;
; NOTE: THE logic WAS BORROWED FROM NORMAN KOHN'S DISK DRIVER FOR
; 8 BIT BANKED SLAVES.  THE code IS ORIGINAL.
;
; DSKRAM.O IS COPYLEFT ESKAY SOFTWARE.  ALL LEFTS REVERSED.
;
       MODULE  "DSKRAM"
;
       LOC     Data#
;
; THE FOLLOWING DEFINES A 256K RAMDISK IN A 512K SLAVE
; BE SURE TO SET MEMTBL+3 = {SEGDSK}-0X50 IN THE PAR FILE!
; ALSO READ DSKRAM.DOC!
;
SEGDSK::WORD    0X4000                  ; STARTING SEGMENT
NUMSGS::BYTE    4                       ; NUMBER OF SEGMENTS
;
DMXSPH: WORD    1                       ; MUTUAL EXCLUSION
       WORD    .                       ;   SEMAPHORE
       WORD    .-2
;
; DISK SPECIFICATION TABLE
;
DST:
BLKSIZ: BYTE    0XC4                    ; 2K, FIXED, 16K EXTENTS
NMBLK:  WORD    0                       ; CALCULATED BY INIT
       BYTE    4                       ; 128 DIR ENTRIES
SECSIZ: BYTE    1                       ; 256 BYTE SECTORS
SPT:    WORD    4                       ; 4 SECTORS PER TRACK
NMTRK:  WORD    0                       ; CALCULATED BY INIT
       WORD    0                       ; ONE RESERVED TRACK
;
       LOC     Code#
;
; INITIALIZE WHATEVER THERE HAS TO BE INITED
;
DSKIN_::
       PUSH    DS              ; SAVE DATA SEGMENT
       MOV     CL,NUMSGS       ; GET NUMBER OF SEGMENTS TO CHECK
       MOV     AX,SEGDSK       ; GET POINTER TO DISK START SEG
       MOV     DS,AX           ; MAKE THIS OUR DATA SEG FOR NOW
;
; FIRST SEE IF THIS WAS A COLD BOOT
; (CHECK DIRECTORY LABEL)
;
       XOR     BX,BX           ; POINT TO FIRST BYTE
       CMP     [BX],=BYTE 0XE5
       JNZ     __IL            ; MUST FORMAT
       CMP     12[BX],=BYTE 0X80       ; DIR MUST BE HASHED
       JNZ     __IL
       CMP     15[BX],=BYTE 0XFF
       JZ      __CALC
__IL:   XOR     BX,BX           ; GET READY TO WIPE THIS SEGMENT
__E5:   MOV     [BX],=WORD 0XE5E5
       INC     BX
       INC     BX
       JNZ     __E5            ; UNTIL SEGMENT DONE
       DEC     CL              ; DECREMENT SEGMENT COUNTER
       JZ      __CALC          ; DONE, CALCULATE BLIND SPOTS IN DST
       MOV     BX,DS           ; GET DATA SEGMENT
       ADD     BX,=0X1000      ; MAKE NEXT SEG ADDR
       MOV     DS,BX
       JMPS    __IL            ; DO AGAIN
;
; CALCULATE NMBLK AND NMTRK
;
__CALC: POP     DS              ; GET OUR DS BACK
       MOV     AL,=64          ; 64K PER SEGMENT
       MUL     NUMSGS          ;   TIMES THE # OF SEGS
       MOV     NMTRK,AX        ; STORE AS NUMBER OF TRACKS (AT 1K EACH)
       SHR     AX,=1           ; DIVIDE BY 2
       MOV     NMBLK,AX        ; STORE AS NUMBER OF BLOCKS
       RET                     ; AND QUIT
;
; THIS IS THE ACTUAL RAM DISK DRIVER
;
DSKDR_::
       MOV     BX,&DMXSPH      ; MAKE SURE WE'RE ALONE OUT THERE
       CALL    WAIT#
       CALL    __DD
       LAHF
       PUSH    AX
       MOV     BX,&DMXSPH      ; LET THE OTHER GUY BACK IN
       CALL    SIGNAL#
       POP     AX
       SAHF
       RET
;
__DD:   MOV     AL,0[SI]        ; GET FUNCTION NUMBER
       OR      AL,AL
       JZ      RDDSK           ; FCN 0 = READ DISK
       DEC     AL
       JZ      WRDSK           ; FCN 1 = WRITE DISK
       DEC     AL
       JZ      RETDST          ; FCN 2 = RETURN DST
RETFF:  MOV     AL,=0XFF        ; ELSE RETURN FAILURE
       RET
;
; RETURN DST
;
RETDST: MOV     14[SI],=WORD DST
       JMPS    RETFF
;
; READ DISK
;
RDDSK:  PUSH    ES
       PUSH    DS
       PUSH    SI
       PUSH    DI
       CLI                     ; LET'S NOT GET DISTURBED...
       CALL    GETADR          ; GET ADDRESS IN ES:BX
       MOV     AX,10[SI]       ; GET DMA OFFSET
       MOV     DX,12[SI]       ; GET DMA SEGMENT
       MOV     CX,8[SI]        ; GET BYTE COUNT
       PUSH    ES              ; GET DISK ADDRESS SEGMENT...
       POP     DS              ;   ... INTO DS
       MOV     ES,DX           ; DESTINATION SEG INTO ES
       MOV     DI,AX           ; DESTINATION OFFSET INTO DI
       MOV     SI,BX           ; SOURCE ADDRESS INTO SI
       CLD                     ; SET AUTO-INCREMENT
       REP
       MOVS    BYTE            ; MOVE THE STUFF
       POP     DI
       POP     SI
       POP     DS
       POP     ES              ; (WISH THIS WAS A '186... PUSHA/POPA!)
       STI                     ; MAY INTERRUPT AGAIN
       JMPS    RETZZ           ; RETURN OK
;
; WRITE DISK
;
WRDSK:  PUSH    ES
       PUSH    DS
       PUSH    SI
       PUSH    DI
       CLI                     ; LET'S NOT GET DISTURBED...
       CALL    GETADR          ; GET ADDRESS IN ES:BX
       MOV     AX,10[SI]       ; GET DMA OFFSET
       MOV     DX,12[SI]       ; GET DMA SEGMENT
       MOV     CX,8[SI]        ; GET BYTE COUNT
       MOV     DI,BX           ; DESTINATION OFFSET INTO DI
       MOV     SI,AX           ; SOURCE ADDRESS INTO SI
       MOV     DS,DX           ; SOURCE SEGMENT INTO DS
       CLD                     ; SET AUTO-INCREMENT
       REP
       MOVS    BYTE            ; MOVE THE STUFF
       POP     DI
       POP     SI
       POP     DS
       POP     ES              ; (WISH THIS WAS A '186... PUSHA/POPA!)
       STI                     ; MAY INTERRUPT AGAIN
RETZZ:  XOR     AL,AL           ; RETURN OK
       RET
;
; GET "DISK" ADDRESS IN ES:BX
;
GETADR: MOV     AX,2[SI]        ; GET TRACK NUMBER
       MOV     CL,=64          ; 64K PER SEGMENT
       DIV     CL              ; FIGURE WHICH SEGMENT
       MOV     CL,AL           ; PUT SEGMENT NUMBER INTO CH
       PUSH    CX              ; SAVE SEGMENT NUMBER
       MOV     AL,AH           ; GET REMAINDER
       MOV     AH,=0
       MOV     CX,=1024        ; 1024 BYTES PER TRACK
       MUL     CX              ; AX IS NOW TRACK ADDRESS IN SEG CL
       MOV     BX,AX           ; TRACK ADDR TO BX
       MOV     AX,4[SI]        ; GET SECTOR
       MOV     CX,=256         ; BYTES PER SECTOR
       MUL     CX
       ADD     BX,AX           ; BX NOW HAS FULL OFFSET
       MOV     AX,=0X1000
       POP     CX
       MOV     CH,=0
       MUL     CX
       MOV     DX,SEGDSK
       ADD     DX,AX
       MOV     ES,DX
       RET
       END