        .z80
        cseg
; Version 2.1 / 03-JUN-1989
; Dieses Programm 'patcht' die CP/M Plus Systemdatei
; fuer die Verwendung von 80 Track-Laufwerken, eines
; 3. Floppylaufwerkes sowie einer RAM- Floppy
; (laeuft nur unter CP/M+)
;
; Floppy Parameter
;------------------------------------------------------------------------------
bigdrives	equ	1
floppy3		equ	0
;nur wichtig wenn bigdrives <>0
fd3drv          equ     'D'             ; 3. Laufwerk log. Bezeichnung
step_b          equ     04              ; Steprate B:
step_c          equ     04              ; Steprate D:

; RAM Disk Parameter
;------------------------------------------------------------------------------
rddrv           equ     'C'             ; log. Drive Bezeichnung
tracks          equ     28              ; Anz. der Spuren (Baenke)
track0          equ     8               ; CP/M-Bank der 1. Spur
sector0         equ     4000h           ; Adresse des 1. Sectors
dirblks         equ     2               ; Anzahl der Directory-Bloecke
al0             equ     11000000b       ; Pos. der Dir.-Bloecke auf Disk
al1             equ     00000000b
rddirb          equ     9000h           ; RAM-Disk Directory-Puffer-Adresse
rddirs          equ     20              ; und Laenge in Sectoren

;Puffer Parameter
;------------------------------------------------------------------------------
fdsecsz         equ     512             ; Floppy Sectorgroesse
fddirb          equ     9a00h           ; Floppy Directory-Puffer-Adresse
fddirs          equ     8               ; und Laenge in Sectoren

fddbnk1         equ     2               ; Floppy Datenpuffer 1 Bank
fddatb1         equ     5480h           ; Adresse
fddats1         equ     21              ; und Laenge

fddbnk2         equ     7               ; Floppy Datenpuffer 2 Bank
fddatb2         equ     4000h           ; Adresse
fddats2         equ     32              ; und Laenge

fddbnk3         equ     0               ; Floppy Datenpuffer 3 Bank
fddatb3         equ     0000h           ; Adresse
fddats3         equ     0               ; und Laenge

;BIOS Variablen/ Vectoren
;------------------------------------------------------------------------------
bios            equ     0fc00h          ; BIOS Sprungleiste
selbnk          equ     bios+3*27       ; F27: Bank selektieren
xmove           equ     bios+3*29       ; F29: extended Move
bmove           equ     0fccbh          ; F25: Move (nicht ueber system call)
system          equ     0fd1ch          ; Amstrad Call System Vektor
adrv            equ     0bef0h          ; abs. Laufwerksnummer
trk             equ     0bef2h          ; Spurnummer
sec             equ     0bef4h          ; Sectornr.
dma             equ     0bef6h          ; DMA Adresse
dmabnk          equ     0bef9h          ; DMA Bank
sendmsg         equ     00572h          ; BIOS Einschaltmeldung ausgeben

; Parameter des Installationsprogramms
;------------------------------------------------------------------------------
ramdsk          equ     6c00h           ; Adr. RAM-Disk-Treiber im SYS-File
boot            equ     0               ; CP/M warm
bdos            equ     5               ; BDOS
fcb1            equ     5ch             ; File Control Block 1
lf              equ     10              ; ASCII-Konstanten
cr              equ     13

patch macro ident                       ; macro zum patchen des System-Files
        ld      hl,ident&src
        ld      de,ident&dst
        ld      bc,ident&end-ident&src
        ldir
        endm

; RAM Disk Installationsprogramm
;------------------------------------------------------------------------------
instal:
        ld      (oldsp),sp              ; Stack einrichten
        ld      sp,stack
        ld      de,hallo                ; Begruessung
        call    print
        call    open                    ; System-File eroeffnen
        call    sysread                 ; lesen
        call    sysptch                 ; patchen
        call    open
        call    syswrte                 ; schreiben
        call    close                   ; und schliessen

exit:
        ld      sp,(oldsp)              ; Stack restaurieren
        jp      boot                    ; und fertig ...

sysread:                                ; System-file an die Adresse 0c00h lesen
        ld      de,0c00h                ; also dma setzen
        call    setdma
        ld      e,128                   ; die ersten 128 records
        call    multis                  ; lesen
        xor     a                       ;
        ld      (fcb1+32),a             ; current record =0
        call    readsq
        ld      de,0c00h+128*128        ; dann die restlichen 72
        call    setdma
        ld      e,72
        call    multis
        jp      readsq

syswrte:                                ; gepatchtes System-File abspeichern
        ld      de,0c00h                ; dma= 0c00h
        call    setdma
        ld      e,128                   ; die ersten 128 records
        call    multis                  ; lesen
        xor     a                       ;
        ld      (fcb1+32),a             ; current record =0
        call    writesq
        ld      de,0c00h+128*128        ; dann die restlichen 72
        call    setdma
        ld      e,72
        call    multis
        jp      writesq

sysptch:                                ; System-File patchen
        patch   lodr                    ; CP/M Plus Loader
        patch   dtrd                    ; RAM-Disk ins Drive Table
        patch   seld                    ; select Disk
        patch   rdc                     ; RAM-Disk Controller
        patch   buffr                   ; BCB's
        patch   mesg                    ; Einschaltmeldung

     if bigdrives
        patch   ptch1                   ; 2. Head check
        patch   ptch2                   ; seek Track
     endif

     if floppy3
        patch   dtfd3                   ; Floppy3 ins Drive Table
     endif

        ret

; BDOS Funktionsaufrufe
;------------------------------------------------------------------------------
print:
        ld      c,9                     ; print String
        jp      bdos

open:
        ld      de,fcb1                 ; open file
        xor     a
        ld      (fcb1+12),a             ; extent=0
        ld      c,15
        jp      exec

close:
        ld      de,fcb1                 ; close file
        ld      c,16
        jp      exec

readsq:
        ld      de,fcb1                 ; read sequential
        ld      c,20
        jp      exec

writesq:
        ld      de,fcb1                 ; write sequential
        ld      c,21
exec:
        call    bdos
        or      a
        jp      nz,exit                 ; bei Error raus
        ret

setdma:                                 ; set DMA Adress
        ld      c,26
        jp      bdos

multis:
        ld      c,44                    ; set Multi-Sector Count
        jp      bdos

hallo:  db      cr,lf,'RAM Disc Installer V 2.0',cr,lf,lf
        db      'RAM disc drive: ',rddrv,':',cr,lf,lf,'$'

oldsp:                                  ; Stackbereich
        ds      64
stack:

; CP/M 3 System File Patches
;------------------------------------------------------------------------------
lodrsrc:                                ; die CPC Versions-Pruefroutine
lodrdst         equ     0cd5h           ; muss dem RAM-Disk Loader Platz machen
        .phase  lodrdst
        ld      hl,ramdsk               ; der RAM-Disk-Controller wird an die
        ld      de,0aa00h               ; Adr. a000 geschoben
        ld      bc,rdcend-rdcsrc
        ldir
        ret
        .dephase
lodrend:

dtrddst aset    262fh+2*(rddrv-'A')     ; RAM Disk DPH ins
dtrdsrc:                                ; Drive Table eintragen
        dw      dph_rd
dtrdend:

     if floppy3
dtfd3dst aset   262fh+2*(fd3drv-'A')
dtfd3src:                               ; Floppy 3 ins DPH eintragen
        dw      dph_fd3
dtfd3end:
     endif

     if bigdrives
ptch1dst aset   1a1ah                   ; patch in der Resultphasen
ptch1src:                               ; auswertung
        call    TwoInOne
ptch1end:

ptch2dst aset   18c7h                   ; patch in der Seek Track Routine
ptch2src:
        jp      steprate
ptch2end:

      endif

selddst aset    3057h
seldsrc:                                ; select Disc umbiegen
        call    seldsk
seldend:

buffrdst aset   0e5ah                   ; init BCB umbiegen
buffrsrc:
        .phase  buffrdst
        jp      initbuf
        .dephase
buffrend:

mesgsrc:                                ; Zusatz bei der Einschaltmeldg
mesgdst equ     1d5fh                   ; als 31. Eintrag in der Mess-Table
        db      'RAM disc drive '
        db      0fdh,' '                ; FDh= Inh. von C ausgeben (Drivenr.)
        db      0f9h,' KB'              ; F9h= Inh. von DE ausgeben (Kapaz.)
        db      cr,lf,lf,0ffh
mesgend:

; RAM Disk
;------------------------------------------------------------------------------
rdcsrc:
rdcdst  aset    ramdsk
        .phase  0aa00h

read:                                   ; Sector lesen
        call    gettrk                  ; Spurnummer holen und
        call    xmove                   ; bankuebergreif. Kop vorber.
        call    getsec                  ; Basisadr. aus der Sectornr. berechn.
        call    bmove                   ; und Sector copieren
        xor     a                       ; A=0 d.h. alles o.k.
        ret

write:                                  ; Sector schreiben
        call    gettrk                  ; Spurnummer holen
        ld      a,c                     ; wie bei read: nur Ziel und Quelle
        ld      c,b                     ; werden vertauscht
        ld      b,a
        call    xmove                   ; Werte an Xmove uebergeben
        call    getsec                  ; Basisadresse berechnen
        ex      de,hl                   ; auch tauschen
        call    bmove                   ; Sector copieren
        xor     a                       ; alles o.k.
        ret

login:                                  ; Laufwerk einloggen
        ex      de,hl                   ; dph-Adresse in HL
        ld      a,(bootflg)             ; erster Zugriff nach
        or      a                       ; einem Kaltstart ?
        ret     z                       ; nein - fertig
        xor     a                       ; sonst RAM-Disk init.
        ld      (bootflg),a             ; Flag loeschen
        push    hl
        push    de
        push    bc
        ld      a,track0                ; Directory ab 4000h einblenden
        call    selbnk
        ld      hl,sector0+1            ; ersten Eintrag ueberpruefen
        ld      b,8                     ; testen ob Filename

checkd:
        ld      a,(hl)                  ; aus ASCII Grossbuchstaben
        cp      ' '                     ; space
        jr      z,nxtchk
        cp      '0'                     ; oder Zahlen besteht
        jr      c,newdir                ; wenn nicht Dir. loeschen
        cp      '9'+1
        jr      c,nxtchk
        cp      'A'
        jp      c,newdir
        cp      'Z'+1
        jp      nc,newdir
nxtchk:
        inc     hl
        djnz    checkd                  ; naechsets Zeichen
        jr      exlogn                  ; alles klar Dir. bleibt

newdir:                                 ; Directory loeschen
        ld      hl,sector0              ; ab Track0, Sector0
        ld      d,h                     ; mit 0e5h fuellen
        ld      e,l
        inc     de
        ld      bc,dirblks*2048
        ld      (hl),0e5h
        ldir

exlogn:                                 ; login beenden
        xor     a                       ; systembank ein
        call    selbnk
        pop     bc
        pop     de
        pop     hl
        ret

gettrk:                                 ; Quell- und Zielbank aus trk und
                                        ; dmabnk berechnen
        ld      a,(trk)                 ; BIOS Spurnr. in Akuu
        add     a,track0                ; Banknr. der 1. Spur dazu
        ld      c,a                     ; und in C ablegen
        ld      a,(dmabnk)              ; B enthaelt die Banknr. des DMA
        ld      b,a
        ret

getsec:                                 ; Quell- und Zieladresse bereitstellen
        ld      hl,(sec-1)              ; BIOS Sectornr. in h
        ld      l,0                     ; l=0 => hl=sec*256
        srl     h                       ; hl/2 =sec*128
        rr      l
        ld      de,sector0              ; sectoradr.=sec*128+sector0
        add     hl,de
        ex      de,hl                   ; in de
        ld      hl,(dma)                ; DMA in hl
        ld      bc,80h                  ; Sectorlaenge in bc
        ret

; BIOS Aenderungen
;------------------------------------------------------------------------------
seldsk:                                 ; die neue Select Disk Routine
        ld      (adrv),a                ; urspruengliche Funktion
        ld      hl,dpbidnt              ; Drive schon selektiert ?
        cp      (hl)
        ret     z                       ; ja - fertig
        push    de
        ld      de,dpb_b                ; DPB B: ins de
        cp      1                       ; ist es B: ?
        jr      z,copydpb
        ld      de,dpb_rd               ; sonst DPB RamD: laden
        cp      rddrv-'A'               ; ist es die RAM-Disk ?
        jr      z,copydpb               ; ja - copieren

     if floppy3                         ; wenn vorhanden
        ld      de,dpb_fd3              ; genauso mit 3. Laufwerk
        cp      fd3drv-'A'              ; verfahren
        jr      z,copydpb
     endif

        pop     de                      ; war nicht dabei - raus ...
        ret

copydpb:
        push    af
        push    bc
        ld      (hl),a                  ; als akt. Laufwerk speichern und
        ld      hl,0ff7fh               ; DPB nach ff7fh cop.
        ex      de,hl
        ld      bc,27
        ldir
        pop     bc
        pop     af
        pop     de
        ret

initbuf:                                ; die neue Init BCB Routine
        ld      bc,rddirs*256           ; RAM Disk Dir.-Buffer
        ld      de,rddirb               ; muss in Bank 0 liegen
        ld      hl,8a00h                ; BCB Adresse
        ld      a,1                     ; 128 Byte Sectoren
        ld      (dirbcbv),hl            ; Adresse des BCB Speichers
        call    initbcb                 ; BCB aufbauen
        dec     hl
        ld      (hl),b                  ; letzter Eintrag (hl)=0
        dec     hl
        ld      (hl),b                  ; (hl-1)=0
        inc     hl
        inc     hl

        ld      bc,fddirs*256           ; DirBCB fuer A; und B: Bank 0
        ld      de,fddirb
        ld      a,fdsecsz/80h           ; Sectorengroesse in a
        push    hl                      ; Adresse auf Stack
        call    initbcb                 ; und aufbauen
        dec     hl
        ld      (hl),b                  ; letzter Eintrag (hl)=0
        dec     hl
        ld      (hl),b                  ; (hl-1)=0
        inc     hl
        inc     hl

        push    hl
        ld      bc,fddats1*256+fddbnk1  ; DatBCB fuer die Floppys
        ld      de,fddatb1              ; Nr. 1
        call    initbcb
        ld      bc,fddats2*256+fddbnk2  ; DatBCB fuer die Floppys
        ld      de,fddatb2              ; Nr. 2
        call    initbcb
        ld      bc,fddats3*256+fddbnk3  ; DatBCB fuer die Floppys
        ld      de,fddatb3              ; Nr. 3
        call    initbcb
        dec     hl
        ld      (hl),b                  ; letzter Eintrag (hl)=0
        dec     hl
        ld      (hl),b                  ; (hl-1)=0

        ld      hl,bcbpars              ; BCB Pars nach ffe8h cop.
        ld      de,0ffe8h
        ld      bc,bcbpend-bcbpars
        ldir
        call    initmsg                 ; RAM-Disk init mess. ausgeben

     if bigdrives                       ; patch 4 & 5
        ld      a,255                   ; wird nach jedem Kaltstart aufger.
        ld      (0be40h),a              ; Flag fuer 2 Drives
        ld      a,1
        ld      (3fb5h),a               ; Drive B:
     endif

        pop     hl
        pop     de
        ret

initbcb:
; Buffer Control Block aufbauen -- Parameter:
; a=Sectorgroesse/128; b=Puffergroesse in Sectoren
; c=Pufferbank       ; de=Pufferadresse
; hl=Adresse des BCB's
        inc     b                       ; Laenge=0 ?
        dec     b
        ret     z                       ; ja - Abbruch
        push    hl
        ld      h,a                     ; Sectorlaenge in Bytes
        srl     h                       ; umrechnen
        ld      l,0
        rr      l
        ex      (sp),hl                 ; Sectorlaenge -> Stack

bcbloop:
        push    de
        ld      (hl),0ffh               ; Drivenr. =0ffh
        ld      de,0fh                  ; naechstes BCB 15 Bytes weiter
        add     hl,de
        ld      d,h
        ld      e,l
        dec     hl
        ld      (hl),d                  ; Adresse eintragen
        dec     hl
        ld      (hl),e
        dec     hl
        ld      (hl),c                  ; Speicherbank des Puffers
        ex      de,hl
        ex      (sp),hl
        ex      de,hl
        dec     hl
        ld      (hl),d                  ; Pufferadresse speichern
        dec     hl
        ld      (hl),e
        pop     hl
        ex      (sp),hl
        ex      de,hl
        add     hl,de                   ; naechste Pufferadresse berechnen
        ex      de,hl
        ex      (sp),hl
        djnz    bcbloop
        inc     sp                      ; Sectorlaenge vom Stack
        inc     sp
        ret

     if bigdrives
TwoInOne:
        ld      a,c                     ; ausblenden der Headadresse
        res     2,a                     ; um Kopf 2 im Result des FDC
        or      20h                     ; wie Kopf 1 zu behandeln
        ret

steprate:
        add     iy,bc                   ; urspr. Funktion
        push    hl
        srl     c                       ; Drivenr. in C
        ld      hl,steptab
        add     hl,bc                   ; Eintrag finden
        ld      a,(hl)
        ld      hl,0b0f1h               ; als akt. Steprate
        cp      (hl)                    ; gefunden ?
        jr      z,stimmt
        ld      (hl),a                  ; speichern
        ld      hl,0ad5h                ; hl auf Headload/ - unload
        call    0af2h                   ; an FDC uebergeben
stimmt:
        pop     hl
        pop     bc
        ret

steptab:
        db      04                      ; Steprate A:
        db      step_b                  ; Steprate B:
        db      0                       ; Dummy
        db      step_c                  ; Steprate C:
     endif

initmsg:                                ; RAM-Disk Meldung nach booten
        ld      c,rddrv-'A'             ; Drivenr und
        ld      de,tracks*16            ; Kapazitaet
        ld      a,31                    ; 31. Eintrag aus der Mess.-Table
        jp      sendmsg                 ; ausgeben ...

bcbpars:        ; diese Bytes muessen ins Common-Bereich copiert werden
        db      0                       ; DirBCB Bank
        dw      fddirb                  ;        Buffer
        dw      2469h                   ;        Laenge

        db      fddbnk1                 ; DatBCB Bank
        dw      fddatb1                 ;        Buffer
        dw      2f80h                   ;        Laenge
        db      0ffh
bcbpend:

; XDPH und DPH's
;------------------------------------------------------------------------------
; RAM-Disk
xdph_rd:                                ; eXtended Disk Parameter Header
        dw      write                   ; Sector schreiben
        dw      read                    ; Sector lesen
        dw      login                   ; Disk einloggen
        dw      0                       ; INIT-Vector (nicht genutzt)
        db      2                       ; phys. Drivenr.
        db      0
dph_rd:                                 ; Disc Parameter Header
        dw      0                       ; kein Skew
        db      0,0,0,0,0,0,0,0,0       ; BDOS scratch
        db      0                       ; kein MF, da kein Diskwechsel
        dw      0ff7fh                  ; DPB Vector
        dw      0                       ; kein Checksum Vector
        dw      alv_rd                  ; Allocation Vector
        dw      dirbcbv                 ; DirBCB Vector
        dw      datbcbv                 ; DatBCB Vector
        dw      05280h                  ; Hashing Table
        db      2                       ; in Bank 2

dpb_rd:
        dw      128                     ; Sectoren pro Spur
        db      4                       ; Blockgroesse 2KB
        db      15
        db      0
        dw      tracks*8-1              ; Kapazitaet in Blocks
        dw      dirblks*64-1            ; Dir.-Groesse
        db      al0,al1
        dw      0                       ; CKS/ kein Checksum
        dw      0                       ; OFF/ kein Offset
        db      0                       ; PSH/ kein Sector Deblocking
        db      0                       ; PHM
        ; Amstrad Parameter
        db      0,0,0,0,0,0,0,0,0,0

alv_rd:
        ds      (tracks*8-1)/4+2        ; Platz fuer die Belegungstabelle
dirbcbv:
        dw      0
datbcbv:
        dw      datbcb
datbcb:
        db      0ffh                    ; Datenpuffer 1 Sector
        ds      3
        db      0
        db      0
        dw      0
        dw      0
        dw      datbuf
        db      0
        dw      0
datbuf:
        ds      128

     if floppy3                         ; nur wenn 3. Laufwerk
xdph_fd3:
        dw      03f1ch                  ; write
        dw      03f17h                  ; read
        dw      03ed6h                  ; login
        dw      03ecbh                  ; init
        db      3                       ; phys. Drivenr.
        db      0
dph_fd3:
        dw      0                       ; kein skew
        db      0,0,0,0,0,0,0,0,0       ; BDOS scratch
        db      0                       ; MF (Mediaflag)
        dw      0ff7fh                  ; wird mit DPB B: getauscht
        dw      csv_fd3                 ; Checksum Vector
        dw      alv_fd3                 ; Allocation Vector
        dw      0befbh                  ; DirBCB
        dw      0befdh                  ; DatBCB
        dw      05080h                  ; Hashing Table
        db      2                       ; in Bank 2

csv_fd3:                                ; Checksum (DRM/4)+1
        ds      33
alv_fd3:                                ; Allocation (DSM/4)+2
        ds      66
dpb_fd3:                                ; DPB 3. Laufwerk
        dw      36                      ; Sectoren pro Spur
        db      5                       ; Blockgroesse 4KB
        db      31                      ;
        db      3                       ; Extend Maske
        dw      00B0h                   ; Kapazitaet in Blocks
        dw      007fh                   ; Dir.-Groesse
        db      80h,00h                 ;
        dw      32                      ; CKS
        dw      2                       ; OFF 2 Systemspuren
        db      2                       ; PSH
        db      3                       ; PHM
        ; Amstrad Parameter
        db      01h,50h,09h,1,0,2,2ah,52h,60h,0ffh
     endif

dpb_b:                                  ; Laufwerk B:
        dw      36                      ; Sectoren pro Spur
        db      5                       ; Blockgroesse 4KB
        db      31                      ;
        db      3                       ; Extend Maske
        dw      00B0h                   ; Kapazitaet in Blocks
        dw      007fh                   ; Dir.-Groesse
        db      80h,00h                 ;
        dw      32                      ; CKS
        dw      2                       ; OFF 2 Systemspuren
        db      2                       ; PSH
        db      3                       ; PHM
        ; Amstrad Parameter
        db      01h,50h,09h,1,0,2,2ah,52h,60h,0ffh
dpbidnt:
        db      0
bootflg:
        db      0ffh
        .dephase
rdcend:
        end
