Quantcast
Channel: stardot.org.uk
Viewing all articles
Browse latest Browse all 2379

8-bit acorn emulators • Re: Model Master 128+Acorn Z80 Second Processor

$
0
0
Here is a single assembler source file, for tpasm, which generates HDBIOS.SYS file and gives a binary identical result to the file distributed by JGH. This may make it easier to follow what is happening:

Code:

;;; Acorn Z80 CP/M BIOS                .processor z80                .include   "defs.asm"                .org       $ea00alvC_Z80Tube    EQU   $F700alvC_CoPro      EQU   $FCDEDiskAcc         EQU   $FFA4LoadCCP         EQU   $FFA7alvB            EQU   $F5C6GBPBchn         EQU   alvB+$19GBPBadr         EQU   GBPBchn+1GBPBnum         EQU   GBPBchn+5GBPBptr         EQU   GBPBchn+9CSVd0           EQU   $F4E0         ; CSV for Drive 0CSVd1           EQU   CSVd0+$20     ; CSV for Drive 1ALVd0           EQU   $F520         ; ALV for Drive 0ALVd1           EQU   $F5C6         ; ALV for drive 1BIOS_BOOT:      JP    ColdBootBIOS_WBOOT:     JP    WarmBootBIOS_CONST:     JP    ConsoleStatus ; CONBIOS_CONIN:     JP    ConsoleIn     ; CONBIOS_CONOUT:    JP    ConsoleOut    ; CONBIOS_LIST:      JP    ListOut       ; LST (printer)BIOS_PUNCH:     JP    PunchOut      ; PUNBIOS_READER:    JP    ReaderIn      ; RDRBIOS_HOME:      JP    DiskHomeBIOS_SELDSK:    JP    SelectDiskBIOS_SETTRK:    JP    SetTrackBIOS_SETSEC:    JP    SetSectorBIOS_SETDMA:    JP    SetDMABIOS_READ:      JP    DiskReadBIOS_WRITE:     JP    DiskWriteBIOS_LISTST:    JP    ListStatus      ; LST (printer)BIOS_SECTRAN:   JP    SectorTranslateDriveCfs:       DB    8DriveC:         DB    "$.CPMDISK",13,"*******"                DPH_Base:       DW    $0000         ; DPH for drive 0                DW    $0000                DW    $0000                DW    $0000                DW    LF1F2                DW    DPB_Acorn400k                DW    CSVd0                DW    ALVd0                DW    $0000         ; DPH for drive 1                DW    $0000                DW    $0000                DW    $0000                DW    LF1F2                DW    DPB_Acorn400k                DW    CSVd1                DW    ALVd1DPH_C:          DW    $0000         ; DPH for drive C                DW    $0000                DW    $0000                DW    $0000                DW    LF1F2                DW    DPB_HardDrive                DW    $0000                DW    $0000         ; Set on ColdBoot; DPB for AcornCPM 400k diskDPB_Acorn400k:  DW    $0014         ; SPT=20   Sectors Per Track                DB    $04           ; BSH=4    Block Shift                DB    $0F           ; BLM=15   Block Mask                DB    $01           ; EXM=1    Extent Mask                DW    $00C3         ; DSM=195  Disk Sector Max                DW    $007F         ; DRM=127  Maximum directory entry number                DB    $C0           ; AL0=$C0  Directory occupies                DB    $00           ; AL1=$00    first two blocks                DW    $0020         ; CKS=32   Size of directory checksum vector                DW    $0003         ; OFF=3    Reserved tracks before logical start of disk; Total disk size is 128*(BLM+1)*(DSM+1)=392K; Physical disk size is 128*SPT*OFF+128*(BLM+1)*(DSM+1)=399.5K; DPB for 8M Hard DriveDPB_HardDrive:  DW    $0100         ; SPT=256  Sectors Per Track                DB    $05           ; BSH=5    Block Shift                DB    $1F           ; BLM=31   Block Mask                DB    $01           ; EXM=1    Extent Mask                DW    $07FF         ; DSM=2047 Disk Sector Max                DW    $03FF         ; DRM=1023 Maximum directory entry number                DB    $FF           ; AL0=$FF  Directory occupies                DB    $00           ; AL1=$00    first eight blocks                DW    $0000         ; CKS=0    Size of directory checksum vector                DW    $0000         ; OFF=0    Reserved tracks before logical start of disk; Total disk size is 128*(BLM+1)*(DSM+1)=8192K; Physical disk size is 128*SPT*OFF+128*(BLM+1)*(DSM+1)=8192K                .org  $EA93LEA93:          LD    A,$83         ; Reset input stream, specify CON=UC1 RDR=TTY PUN=TTY LST=LPTLEA95:          LD    ($0003),A     ; Reset IOBYTE                LD    L,$02                LD    A,$02                CALL  OSBYTE        ; Input stream=kbd, serial enabled                JP    LEBBDConsoleStatus:  CALL  LEB02                DB    $81           ; IOBYTE b0-1, test TTY/CRT/BAT/UC1                DW    TTYStatus                DW    CRTStatus                DW    ReaderStatus                DW    UC1StatusConsoleIn:      CALL  LEB02                DB    $01           ; IOBYTE b0-b1, input from TTY/CRT/BAT/UC1                DW    TTYIn                DW    CRTIn                DW    ReaderIn                DW    OSRDCHConsoleOut:     CALL  LEB02                DB    $01           ; IOBYTE b0-b1, output to TTY/CRT/BAT/UC1                DW    TTYOut                DW    CRTOut                DW    ListOut                DW    UC1OutListOut:        CALL  LEB02                DB    $03           ; IOBYTE b6-7, output to TTY/CRT/LPT/UL1                DW    TTYOut                DW    CRTOut                DW    LPTOut                DW    UL1OutListStatus:     CALL  LEB02                DB    $03           ; IOBYTE b6-7, test TTY/CRT/LPT/UL1                DW    SerStatus                DW    TTYempty                DW    UL1Status                DW    UL1StatusPunchOut:       CALL  LEB02                DB    $05           ; IOBYTE b4-5, output to TTY/PTP/UP1/UP2                DW    TTYOut                DW    CRTOut                DW    NullOut                DW    NullOutReaderIn:       CALL  LEB02                DB    $07           ; IOBYTE b2-3, input from TTY/PTR/UR1/UR2                DW    TTYIn                DW    CRTIn                DW    NullIn                DW    NullInReaderStatus:   CALL  LEB02                DB    $07           ; IOBYTE b2-3, test TTY/PTR/UR1/UR2                DW    TTYStatus                DW    CRTStatus                DW    TTYnonempt                DW    TTYnonempt; Indirect character I/O call; ===========================; CALL is followed by an IOBYTE mask flag, then four addresses; If bit 7 of the mask flag is clear, then a flag is cleared; The IOBYTE is rotated by the mask flag to get an index into; the inline addresses. The selected address is then jumped to.;LEB02:          POP   HL                LD    a,(hl)                INC   HL            ; Get IOBYTE mask flag                BIT   7,A                LD    B,A                RES   7,B                JR    NZ,LEB10      ; If $80+n, don't clear something                XOR   A                LD    (LF167),A     ; $00+n, clear this flagLEB10:          LD    A,($0003)     ; Get IOBYTELEB13:          RLCA                DJNZ  LEB13         ; Rotate left by mask flag                AND   $06                LD    D,$00         ; Index into four inline addresses                LD    E,A                ADD   HL,DE                LD    E,(HL)        ; Jump to the inline address specified by                INC   HL            ; IOBYTE rotated by the flag byte                LD    D,(HL)                EX    DE,HL                JP    (HL); Null input - return EOF; -----------------------NullIn:         LD    A,$1A; Null output - sink; ------------------NullOut:        RET; Read UC1 status; ===============UC1Status:      LD    HL,LF167      ; Test flag                XOR   A                OR    (HL)          ; If zero, check current input stream                JR    Z,LEB2E                DEC   (HL)          ; Decrement flag                XOR   A                RET                 ; Return $00LEB2E:          LD    HL,$FF00                LD    A,$B1                CALL  OSBYTE        ; Read input streamLEB36:          CALL  LEB8C                RET   NZ                LD    A,$D8         ; Read soft key length                LD    HL,$ff00                CALL  OSBYTE                LD    A,L                AND   A                JR    NZ,TTYnonempt                LD    HL,LF167       ; Set flag to 12                LD    (HL),$0C                RET; Output to UC1 - RDCH/WRCH; =========================UC1Out:         LD    A,C           ; Send via PROUT to WRCH or TERMOUT                JP    $FF9E; Read CRT status; ===============CRTStatus:      LD    l,$00                JR    LEB36         ; Jump to test buffer 0 (keyboard); CRT input (ie, KBD/VDU); =======================CRTIn:          LD    L,$02         ; Keyboard Input, Serial EnabledLEB56:          LD    A,$02         ; Set input stream                CALL  OSBYTE                CALL  OSRDCH                PUSH  AF            ; Wait for input character                LD    A,L                AND   A                JR    NZ,LEB65      ; If previous stream<>0, reselect it                LD    L,$02         ; Otherwise, enable serial, keyboard inputLEB65:          LD    A,$02         ; Set input stream                CALL  OSBYTE                POP   AF                RET                 ; Return with character read; CRT Output - VDU/KBD; ====================CRTOut:         LD    HL,$00F4      ; Output=*,noprint,*,nospool,printer,novduprinter,vdu,noserialLEB6F:          LD    A,$03         ; Enter here with HL=*FX3 value                CALL  OSBYTE        ; Select output stream                PUSH  HL            ; Save previous output stream                XOR   A             ; Switch off terminal mode                CALL  $FFC8                PUSH  AF            ; Remember previous state                LD    A,C           ; Output the character                CALL  OSWRCH                POP   AF            ; Restore previous terminal state                CALL  $FFC8                POP   HL            ; Get previous output stream                LD    H,$00                LD    A,$03                JP    OSBYTE        ; Restore previous output and return; Read TTY status; ===============TTYStatus:      LD    L,$01         ; Serial Input bufferLEB8C:          LD    A,$98                CALL  OSBYTE        ; Examine buffer                JR    NC,TTYnonempt ; Buffer not emptyTTYempty:       XOR   A                RET                 ; Return A=$00 if emptyTTYnonempt:     XOR   A                DEC   A                RET                 ; Return A=$FF if not empty; Console Input; =============TTYIn:          LD    L,$01                JR    LEB56         ; Jump to read from Serial Input; TTY Output - serial output; ==========================TTYOut:         LD    HL,$00F7      ; Output=*,noprint,*,nospool,printer,novduprinter,novdu,serial                JR    LEB6FSerStatus:      LD    HL,$FFFD                JR    LEBC7         ; Jump to check SerialOut buffer with HL=-3; LPT Output - test printer before outputing; ==========================================LPTOut:         CALL  LEBD2         ; Test printer status; UL1 Output - output straight to printer; =======================================UL1Out:         LD    A,C           ; Test if C=0                AND   A                LD    HL,$001A      ; Output=*,printer,*,nospool,printer,novduprinter,novdu,noserial                JR    NZ,LEB6F      ; If C=0, jump to output to printer                LD    A,$06                LD    L,$FF         ; Set printer ignore char to $FF so can output $00                CALL  OSBYTE                LD    HL,$001A                CALL  LEB6F         ; Write character to printerLEBBD:          LD    A,$06                LD    L,$00         ; Set printer ignore char to $00                JP    OSBYTEUL1Status:      LD    HL,$FFFC      ; HL=-4 - printer bufferLEBC7:          LD    A,$80         ; Check buffer status                CALL  OSBYTE                LD    A,L           ; Return $00 if no space left (bug, should be AND H)                AND   A                RET   Z                XOR   A                DEC   A                RET                 ; Return $FF if space available (bug, don't need XOR A); Test printer status; ===================LEBD2:          LD    A,($0003)     ; Get IOBYTE LST and CON fields                AND   $C3                CP    $82                RET   Z             ; If LST=LPT, CON=BAT, exit                CALL  LEC80         ; Check and return if printer available                RET   NZ                LD    A,$86         ; Read POS and VPOS                CALL  OSBYTE                LD    (LF168),HL                LD    A,$87         ; Read MODE.                CALL  OSBYTE                LD    A,H                LD    HL,$1F36      ; H=32-1 lines, L=54                AND   A                JR    Z,LEBFD       ; MODE 0, 32 lines                CP    $03                JR    Z,LEBFB       ; MODE 3, 25 lines                LD    HL,$0000                JR    LEBFD         ; Others, use 00x00LEBFB:          LD    H,$18         ; H=25-1 linesLEBFD:          PUSH  HL                CALL  LEC6C         ; PRINT TAB(54,Y); or (0,0);                CALL  LEC8E                DB    "Printer off line"                DB    0                CALL  LEC80                POP   HL            ; Get coord back                PUSH  HL                CALL  LEC6C         ; PRINT TAB(54,Y); or (0,0);                CALL  LEC8E                DB    "SPACE starts Printer Sink", 0LEC3A:          CALL  UL1Status                JR    NZ,LEC5A                CALL  ConsoleStatus                AND   A                JR    Z,LEC3A                CALL  ConsoleIn                CP    ' '                JR    NZ,LEC3A      ; Not SPACE, loop back                LD    L,$03                LD    A,$15                CALL  OSBYTE        ; Flush printer buffer                LD    L,$00                LD    A,$05                CALL  OSBYTE        ; Select printer sinkLEC5A:          POP   HL                CALL  LEC6C         ; Get coords and PRINT TAB(54,Y); or (0,0);                LD    B,$19         ; Print 25 spaces to overwrite messageLEC60:          PUSH  BC                LD    C,' '                CALL  ConsoleOut    ; Print a space                POP   BC                DJNZ  LEC60                LD    HL,(LF168)    ; Get original POS/VPOS backLEC6C:          PUSH  BC                PUSH  HL            ; Save HL and BC                LD    C,$1F                CALL  ConsoleOut    ; VDU 31 - TAB                POP   HL            ; Get X coord                PUSH  HL                LD    C,L                CALL  ConsoleOut    ; Send X coord                POP   HL            ; Get Y coord                LD    C,H                CALL  ConsoleOut    ; Send Y coord                POP   BC            ; Restore BC                RET; Test if output to printer online; ================================LEC80:          LD    DE,$AFC8      ; Test 45,000 timesLEC83:          CALL  UL1Status     ; Test printer buffer                RET   NZ            ; return if not full                DEC   DE            ; Decrement timer                LD    A,E                OR    D                JR    NZ,LEC83      ; Loop until timed out and buffer not emptied                XOR   A                RET                 ; Return with Z set, printer offline; Print inline message until $00 byte; ===================================LEC8E:                EX (SP),HL          ; Get address from stack                PUSH DE             ; Save everything else                PUSH BC                PUSH AFLEC92:          LD   A,(HL)         ; Get a byte                INC  HL             ; step to next                AND  A                JR   Z,LEC9E        ; Zero byte, end of message                PUSH HL                CALL LECA3          ; Print the character                POP  HL                JR LEC92            ; Loop back for nextLEC9E:          POP  AF             ; Restore everything                POP  BC                POP  DE                EX (SP),HL          ; Stack pointer                RET                 ; and return to it; CON_ASCII; =========LECA3:          CP    $0D                JR    NZ,LECAC      ; Jump to output non-<CR>                CALL  LECAC         ; Print <CR>                LD    A,$0A         ;  and add a <LF>LECAC:          LD    C,A                JP    ConsoleOut    ; Print character; Complain about disk being booted fromLECB0:          CALL  LEC8E         ; Print message:                DB    13                DB    "Not a CP/M system disc in A",0                CALL  ConsoleIn     ; Wait for a key; WARM BOOT - RESET jumps to here; ===============================WarmBoot:       LD    SP,$F4E0      ; Use internal MOS stack                EI                  ; enable INTs (NB! ColdBoot doesn't explictly enable INTs)                CALL  GetCCP        ; Load CCP and BDOS                CALL  LED32         ; Calculate CCP/BDOS checksum                LD    HL,LED43                CP    (HL)          ; Is is same as at previous ColdBoot?                JR    NZ,LECB0      ; No, jump to complain and reload                CALL  LED44         ; Initialise things, error handler, esc state, zero page jumps; A consequence of the way the WarmBoot CCP/BDOS validity check works is; that between any two ColdBoots, only the same CCP/BDOS will be recognised; as being valid on reloading. This prevents you being able to, for; instance, soft reboot from a different CCP/BDOS. A ColdBoot is required to; load a different CCP/BDOS in and have it's checksum used.;; Enter CCP; ---------LECE6:          LD    A,($0004)     ; Get current drive                CALL  SelectTest                JP    $D403SelectTest:     PUSH  AF                AND   $0F                LD    C,A                CALL  SelectDisk    ; Try to select this drive.                POP   AF            ; Get drive back.                LD    C,A                LD    A,H                OR    L                RET   NZ            ; If valid return C=user+drive.                LD    C,A           ; If not valid, return C=0+0                RET; DiskPatch; (HL+1)=address; (HL+6)=&4B for write, &53 for read; (HL+9)=num OR &20; currDRIVE=drive; currTRACK=track; currBLOCK=block; all registers trashable, return A=resultDiskPatch:      LD    A,(currDRIVE) ; Get current drive.                CP    $02                JR    NC,HDAccess   ; Jump to do hard drive access.                PUSH  HL                LD    A,$04         ; Ensure DFS is selected if needed.                CALL  EnsureFS                POP   HL                PUSH  AF            ; Save previous filing system.                CALL  DiskAcc       ; Do the disk access                POP   HL            ; Get old filing system back.                PUSH  AF            ; Save result.                LD    A,H           ; Reselect old FS if needed.                CALL  RestoreFS                POP   AF            ; Return with result.                RETHDAccess:       LD    DE,GBPBchn    ; Copy address to GBPBaddr                LD    BC,9                LDIR                ; BC now &0000, HL=>num OR 32                LD    (GBPBnum+2),BC ; num=&0000xxxx                LD    A,(HL)                AND   $1F                LD    B,A           ; B=num                DEC   HL                DEC   HL                DEC   HL            ; HL=>cmd                RLD                ADD   A,A           ; &4B/&53 -> &04/&05 -> &08/&0A -> &01/&03                SUB   7                JP    DiskPatch2; Calculate checksum of CCP/BDOS; ==============================LED32:          XOR   A                LD    HL,BIOS_BOOT-$E00+6  ; Point to start of BDOSLED36:          ADD   A,(HL)        ; Add the byte.                INC   HL            ; step to next                EX    DE,HL                SCF                LD    HL,BIOS_BOOT-1                SBC   HL,DE                EX    DE,HL         ; Have we got past $E9FF yet?                JR    NZ,LED36      ; Loop back until all done                RETLED43:          DB    $89             ; CCP/BDOS checksum; Various initialisations; =======================LED44:          XOR   A             ; Clear various things                LD    (LF1E5),A                LD    (LF1E6),A                LD    (LF1E8),A                LD    (LF1E7),A                CALL  $FFBF         ; Ensure RSTERR at $0038 is set up                LD    HL,($FF84)    ; Set default error handler                LD    ($FFFA),HL                LD    A,$E5                LD    HL,1                CALL  OSBYTE        ; ESC key returns ASCII                LD    A,$C3         ; JP opcode                LD    ($0000),A     ; Set RESET and BDOS entries                LD    ($0005),A                LD    HL,BIOS_WBOOT ; Point RESET to BIOS WBOOT entry                LD    ($0001),HL                LD    HL,BIOS_BOOT-$E00+6 ; Point BDOS to BDOS function entry                LD    ($0006),HL                LD    BC,$0080      ; Continue to set DMA to defaut $0080; Set DMA; =======; BC=Disk Memory AddressSetDMA:         LD  (DMAADDR),BC    ; Store current DMA                RET; Home Disk; =========DiskHome:       LD  BC,$0000        ; Prepare TRACK=0                LD  A,(LF1E7)                OR  A                JR  NZ,SetTrack     ; If ???, skip                LD  (LF1E6),A       ; If ???, set ??? to zero; Select track; ============; BC=trackSetTrack:       LD    A,C                LD    (TRACK),A     ; Store current track                RET; Select disk; ===========; C=drive number, E.b0=not first occurance since resetSelectDisk:     LD    A,C                CP    $02           ; Test if hard drive present.                CALL  Z,DiskTest                LD    HL,0          ; Exit with HL=0 if no hard drive.                RET   NC                LD    BC,DPH_Base                LD    (DRIVE),A     ; Store current drive                LD    L,A                ADD   HL,HL         ; Multiply drive by 16 to index into DPB table                ADD   HL,HL                ADD   HL,HL                ADD   HL,HL                ADD   HL,BC         ; Add base of DPB table                RET                 ; Return HL=DPB for this drive; Select sector; =============; BC=sectorSetSector:      LD    A,C                LD    (SECTOR),A    ; Store current sector                RET; Read a sector from disk; =======================; Read one 128-byte sector specified by DRIVE, TRACK, SECTOR; On return, A=$00 - Ok;            A=$01 - Sector error;DiskRead:       LD    (DISKSP0+1),SP; Use internal stack for disk operations                LD    SP,$F4CC                XOR   A                LD    (LF1E8),A     ; LF1E8=$00                LD    A,$01         ; $01=DiskRead                LD    (DSKRDWR),A                LD    (LF1ED),A                LD    A,$02         ; Read can be deferred, no pre-read necessary                LD    (DSKDEFR),A                JP    LEE2F; Write a sector to disk; ======================; Write one 128-byte sector specified by DRIVE, TRACK, SECTOR; On entry,  C=0 - Normal sector write     - Write can be deferred;            C=1 - Write to directory      - Write must be immediate;            C=2 - Write to unused sectors - Write can be deferred, no pre-read is necessary;                  (also set by any read); On return, A=$00 - Ok;            A=$01 - Sector error;DiskWrite:      LD    (DISKSP0+1),SP; Use internal stack for disk operations                LD    SP,$F4CC                XOR   A             ; $00=DiskWrite                LD    (DSKRDWR),A                LD    A,C                LD    (DSKDEFR),A   ; DSKDEFR=write type                CP    $02                JR    NZ,LEDF0      ; No pre-read needed, jump forward; Write can be deferred, no pre-read, writing to unused sectors                LD    A,$10                LD    (LF1E8),A     ; LF1E8=$10                LD    A,(DRIVE)                LD    (LF1E9),A     ; Copy D/T/S to ...                LD    A,(TRACK)                LD    (LF1EA),A                LD    A,(SECTOR)                LD    (LF1EB),A; All types of writeLEDF0:          LD    A,(LF1E8)                OR    A                JR    Z,LEE27       ; $00 - jump for ...                DEC   A                LD    (LF1E8),A     ; <>$00, set to $FF for write                LD    A,(DRIVE)                LD    HL,LF1E9                CP    (HL)                JR    NZ,LEE27      ; Different drive                LD    A,(TRACK)                LD    HL,LF1EA                CP    (HL)                JR    NZ,LEE27      ; Different track                LD    A,(SECTOR)                LD    HL,LF1EB                CP    (HL)                JR    NZ,LEE27      ; Different sector                INC   (HL)                LD    A,(HL)                CP    $14           ; Last sector on track?                JR    C,LEE21                LD    (HL),$00      ; Set sector back to zero.                LD    HL,LF1EA                INC   (HL)          ; increment track.LEE21:          XOR   A                LD    (LF1ED),A                JR    LEE2FLEE27:          XOR   A                LD    (LF1E8),A                INC   A                LD    (LF1ED),A; DiskRead and DiskWrite merge here; ---------------------------------LEE2F:          XOR   A                LD    (LF1EC),A;                                   ; Hook here for additional drives by sector access                LD    A,(SECTOR)                OR    A                RRA                OR    A                RRA                LD    (BLOCK),A     ; BLOCK=SECTOR/4                LD    HL,LF1E6                LD    A,(HL)                LD    (HL),$01                OR    A                JR    Z,LEE68                LD    A,(DRIVE)                LD    HL,currDRIVE                CP    (HL)                JR    NZ,LEE61                LD    A,(TRACK)                LD    HL,currTRACK                CP    (HL)                JR    NZ,LEE61                LD    A,(BLOCK)                LD    HL,currBLOCK                CP    (HL)                JR    Z,LEE85       ; Requested block is in deblock area; Requested block not in deblock area; -----------------------------------LEE61:          LD    A,(LF1E7)                OR    A                CALL  NZ,LEF04      ; Flush disk buffer - write it to diskLEE68:          LD    A,(DRIVE)                LD    (currDRIVE),A ; Set that requested block is in deblock area                LD    A,(TRACK)                LD    (currTRACK),A                LD    A,(BLOCK)                LD    (currBLOCK),A                LD    A,(LF1ED)                OR    A                CALL  NZ,LEEC7      ; Read from disk to disk buffer if needed                XOR   A                LD    (LF1E7),A; Access data in deblock area; ---------------------------LEE85:          LD    A,(SECTOR)    ; Get sector bottom two bits - 0, 1, 2, 3                AND   $03                LD    L,A                LD    H,$00                ADD   HL,HL         ; Multiply by 128 to index into deblock area                ADD   HL,HL                ADD   HL,HL                ADD   HL,HL                ADD   HL,HL                ADD   HL,HL                ADD   HL,HL                LD    DE,LF272                ADD   HL,DE         ; HL=Deblock area + 128*block{b0-b1}                LD    DE,(DMAADDR)                LD    BC,$0080      ; Prepare to copy 128 bytes - one record                LD    A,(DSKRDWR)                OR    A                JR    NZ,LEEAB      ; Skip past if READ                LD    A,$01                LD    (LF1E7),A                EX    DE,HL         ; Swap source and dest for WRITELEEAB:          LDIR                ; Copy data to/from deblock area                LD    A,(DSKDEFR)                CP    $01           ; Was it 'Write to directory'?                LD    A,(LF1EC)DISKSP0:        LD    SP,0          ; Restore stack (modified from elsewhere)                NOP                RET   NZ            ; Return result if not 'Write to directory'                OR    A                RET   NZ            ; Return result if error                XOR   A                LD    (LF1E7),A                CALL  LEF04         ; Update directory cache                LD    A,(LF1EC)                RET                 ; Return result; Read/Write a block to/from deblock area; ---------------------------------------LEEC7:          CALL  LF02D         ; Check if TIME has expired                CALL  LF077         ; Is requested block within directory?                LD    A,$53                JR    Z,LEF1E       ; No, jump past with A=$53 - DSKRD; Access part of the directory; ----------------------------                LD    A,(LF1E5)                AND   A                JR    Z,LEEE9       ; Directory cache not valid, jump to reload                LD    A,(LEFC0)                LD    HL,currDRIVE                CP    (HL)                JR    NZ,LEEE9      ; Different drive, load directory                LD    A,(LEFC7)                LD    HL,currTRACK                CP    (HL)                JR    Z,LEEFF       ; Same drive and track, cache still valid, use itLEEE9:          LD    HL,LEFC0      ; Point to control block to load directory to cache                LD    A,(currDRIVE)                LD    (HL),A        ; Set drive in control block                LD    A,(currTRACK)                LD    (LEFC7),A     ; Set track in control block                CALL  LEF49         ; Clear cache and read new directory                RET   NZ                LD    A,$FF                LD    (LF1E5),A     ; Set directory data validLEEFF:          LD    A,$01                JP    LEFFF         ; Jump to read data from cached directory; Update directory cache after writing to disk buffer; ---------------------------------------------------LEF04:          CALL  LF02D         ; Check if directory cache has expired                LD    A,$4B                CALL  LEF1E         ; Do 'DiskWrite'                JR    NZ,LEF17      ; Error occured, invalidate cache                CALL  LF077                RET   Z             ; Return if not directory data                LD    A,$00                JP    LEFFF         ; Also write to cached dataLEF17:          PUSH AF                XOR  A                LD   (LF1E5),A      ; Set cache has expired                POP  AF                RET; Read/Write data area; --------------------LEF1E:          LD    (LEFBB),A     ; Store disk access command                LD    A,(currDRIVE)                LD    (LEFB5),A     ; Store drive in control block                LD    A,(currTRACK)                CP    $50                JR    C,LEF3A       ; Track<80, side 0, jump forward                LD    C,A                LD    A,(LEFB5)                ADD   A,$02         ; Add 2 to drive for side 1                LD    (LEFB5),A                LD    A,$9F                SUB   C             ; Convert track 80-159 to 79-0LEF3A:          LD    (LEFBC),A     ; Store track in control block                LD    A,(currBLOCK)                CALL  LEFAC                LD    (LEFBD),A                LD    HL,LEFB5LEF49:          PUSH  HL                CALL  LF063         ; Set previous TIME=current TIME                POP   HL; Return here to retry; Hook here to add extra drives by block accessLEF4E:          CALL  DiskPatch     ; Disk Access, HL=>control block                AND   A                JR    Z,LEFA7       ; Ok, jump to update flag and return                CP    $12                JR    NZ,LEFA5      ; Not 'DiskReadOnly', jump to return disk error                PUSH  HL                CALL  LEC8E                DB    13, "Bdos Err On ", 0LEF6A:          LD    A,(currDRIVE)                AND   $01                ADD   A,'A'                LD    C,A                CALL  ConsoleOut    ; Print drive letter                CALL  LEC8E                DB    ": R/O (Disc is Write Protected)", 0                CALL  ConsoleIn     ; Wait for a keypress                POP   HL                CP    'R'                JR    Z,LEF4E       ; 'R'etry                CP    'r'                JR    Z,LEF4E       ; 'r'etry                RST   $00           ; Not Retry, rebootLEFA5:          LD    A,$01LEFA7:          AND   ALEFA8:          LD   (LF1EC),A                RET; Convert BLOCK 0-4 to sector 0/4/8/2/6; -------------------------------------LEFAC:          LD    C,A                LD    B,$00                LD    HL,InterLeaveTab                ADD   HL,BC                LD    A,(HL)                RET; OSWORD $7F control block; ------------------------LEFB5:          DB    $00           ; Drive/SideLEFB6:          DW    LF272         ; Data address                DW    0                DB    $03LEFBB:          DB    $53           ; CommandLEFBC:          DB    $28           ; TrackLEFBD:          DB    $00           ; Sector                DB    $22           ; 2x256-byte sectors                DB    $00           ; Result; OSWORD $7F control block to access directory cache; --------------------------------------------------LEFC0:          DB    $00           ; Drive/Side                DW    $2600         ; Data address in directory cache                DW    $FFFF                DB    $03                DB    $53           ; CommandLEFC7:          DB    $03           ; Track                DB    $00           ; Sector                DB    $2A           ; 10x256-byte sectorsLEFCA:          DB    $00           ; Result; XXXInterLeaveTab:  DB    0             ; Sector interleave table                DB    4                DB    8                DB    2                DB    6; Continue to look for hard drive; -------------------------------DiskTest:       XOR   A                             ; Prepare 'no disk access'DiskPatch2:     LD    (GBPBnum+0),BC                LD    B,A           ; num=&0000nn00, B=0 test, =1 write, =3 read                LD    DE,(currTRACK)                LD    D,C           ; D=0, E=TRACK, B=cmd, C=0, HL=xxx                LD    A,(currBLOCK)                ADD   A,A                ADD   A,A           ; A=BLOCK moved up to b7                SRL   E                RRA                LD    H,A                LD    L,C           ; DE=<0-TRACK>, A=<Tb0-BLOCK-0> -> DE=&00<TRK>, HL=<BLK><00>                INC   H                JR    NZ,DiskNoInc                INC   DE            ; DEHL=<Tb0-BLOCK-0><00000000>+256 - index into MyZ80 disk imageDiskNoInc:      LD    (GBPBptr+0),HL                LD    (GBPBptr+2),DE;                LD     A,(DriveCfs)                CALL   EnsureFS     ; Select DriveC filing system if needed                PUSH   AF           ; Save previous FS,                 LD     C,$FF        ; prepare C=&FF for not found (no drive present)                LD     HL,DriveC                JP     DiskPatch3;; Read or write data to/from directory cache in I/O memory; --------------------------------------------------------LEFFF:          LD    (LF02C),A     ; Store read/write command in control block                LD    A,(currBLOCK)                CALL  LEFAC         ; Convert BLOCK to sector number                LD    HL,$2500      ; HL=cache-256                INC   A                LD    B,A           ; B=sector+1                LD    DE,$0100LF010:          ADD   HL,DE         ; Index into cache at $2600+sector*256                DJNZ  LF010                LD    (LF022),HL                LD    HL,LF020      ; Store in control block                LD    A,$FF                CALL  OSWORD        ; Make transfer.                XOR   A                RET; OSWORD $FF control block - read/write I/O memory; ------------------------------------------------LF020:          DB    $0D           ; Send block length=13                DB    $01           ; Receive block length=1LF022:          DW    $2600         ; I/O transfer address                DW    $0000                DW    LF272                DW    $0000         ; CoPro transfer address                DW    $0200         ; Data lengthLF02C:          DB    $01           ; Transfer type 0=read from I/O, 1=write to I/O; Compare current TIME to previous TIME+3.84s; -------------------------------------------LF02D:          LD    A,$01                LD    HL,LF472                CALL  OSWORD        ; Read current TIME                LD    DE,(LF477+0)                LD    HL,(LF472+0)  ; Compare current TIME to stored TIME                OR    A                SBC   HL,DE                RR    B                LD    DE,$0180                OR    A                SBC   HL,DE                JR    NC,LF05E                LD    DE,(LF477+2)                LD    HL,(LF472+2)                RL    B                SBC   HL,DE                JR    NZ,LF05E                LD    HL,(LF477+4)                LD    A,(LF472+4)                SBC   A,L                RET   ZLF05E:          XOR   A             ; TIME has expired                LD   (LF1E5),A                RETLF063:          LD    A,(currDRIVE) ; Compare with directory drive                LD    HL,LEFC0                CP    (HL)                RET   NZ            ; Different drives, return                LD    HL,LF472      ; Copy currTIME to prevTIME                LD    DE,LF477                LD    BC,$0005                LDIR                RET; Check if requested block is within the directory; ------------------------------------------------LF077:          LD    A,(currTRACK) ; Check requested TRACK                CP    $03           ; Track 3 - directory, exit with A=$FF                JR    Z,LF08B                CP    $04                JR    NZ,LF089      ; Not track 4 - exit with A=$00                LD    A,(currBLOCK) ; Check requested block                CP    $03                JR    C,LF08B       ; Block<3 - directory, exit with A=$FFLF089:          XOR   A             ; A=$00, not directory                RETLF08B:          XOR   A                DEC   A             ; A=$FF, directory                RET; Check for any boot files; ------------------------LF08E:          LD    C,$0E                CALL  $DC06         ; Reset disk system                LD    DE,strBOOT    ; Search for "BOOT.COM"                LD    C,$11                CALL  $DC06                INC   A                JR    Z,LF0BF       ; Not found, try next one                CALL  LEC8E         ; Print message:                DB    "Running BOOT.COM",13,0                LD    HL,cmdBOOT    ; Point to "BOOT" command stringLF0B6:          LD    DE,$D407                LD    BC,$000D      ; Copy command into CCP command buffer                LDIR                RETLF0BF:          LD    DE,subBOOT                LD    C,$11                CALL  $DC06         ; Search for "BOOT.SUB"                INC   A                RET   Z             ; Not there, exit                LD    DE,strSUBMIT  ; Search for "SUBMIT.COM"                LD    C,$11                CALL  $DC06                INC   A                JR    Z,LF0F1       ; Not there, report the problem - if BOOT.SUB is present, SUBMIT.COM needs to also be there                CALL  LEC8E         ; Print message                DB    "Submitting BOOT.SUB",13,0LF0EC:          LD    HL,cmdSUBMIT                JR    LF0B6         ; Jump to copy "SUBMIT BOOT" into CCP command bufferLF0F1:;               CALL  LEC8E         ; Print message:;               DB    "No SUBMIT.COM",0                RETcmdBOOT:        DB    4, "BOOT", 0cmdSUBMIT:      DB    11, "SUBMIT BOOT", 0strSUBMIT:      DB    0, "SUBMIT  COM", 0subBOOT:        DB    0, "BOOT    SUB", 0 ; Will be overwritten when SUMBIT.COM searched forstrBOOT:        DB    0, "BOOT    COM", 0 ; Will be overwritten when BOOT.SUB searched for;; F53B - Start of core MOS code; F800 - Start of Z80Tube MOS code; COLD BOOT - Entered on startup after booting from Reset; =======================================================ColdBoot:       LD    SP,$F4E0      ; Use internal MOS stackLF167           EQU   ColdBoot+20LF168           EQU   ColdBoot+21                CALL  LED32         ; Get 8-bit checksum of CCP/BDOS in memory                LD    (LED43),A                CALL  LED44         ; Initialise things, error handler, esc state, zero page jumps                CALL  LEA93         ; Initialise input stream and printer ignore state                LD    HL,($EA04)                LD    ($EA01),HL    ; ColdBoot now goes to WarmBoot                LD    HL,alvC_Z80Tube+256 ; DriveC allocation vector for Z80Tube                LD    A,(HL)        ; Check for Z80Tube at &F800                DEC   H                CP    $C3                JR    Z,ColdALV     ; Use Z80Tube-256 as alvC                LD    HL,alvC_CoPro ; DriveC allocation vector for hardware CoProColdALV:        LD    (DPH_C+14),HL ; Set up DriveC allocation vector                CALL  LEC8E         ; Print startup message                DB    13,"Acorn CP/M 2.2 - HDBIOS 1.24",13,0                LD    C,13                CALL  $DC06         ; Reset disks                LD    A,2                CALL  SelectTest    ; See if drive C present, C=2 or 0                PUSH  BC                LD    A,C                LD    (4),A         ; Set system drive                LD    E,C                CALL  LF08E         ; Check for boot files on this drive                POP   BC                JP    $D400         ; Enter CCP with C=driveDiskPatch3:     LD    A,(HL)                CP    '!'           ; Is filename present?                JR    C,NoImageFile ; No image filename                LD    A,$C0                CALL  OSFIND        ; Open hard drive image file                AND   A                JR    Z,NoImageFile ; Skip past if no image file                LD    HL,GBPBchn    ; Point to control block                LD    (HL),A        ; set channel                PUSH  AF                 LD    A,B                AND   A                CALL  NZ,OSGBPB     ; do disk data transfer if nonzero                POP   HL                XOR   A                LD    C,A                CALL  OSFIND        ; Close channel, C=&00 for OkNoImageFile:    POP   AF                CALL  RestoreFS     ; Reselect oldFS if needed                LD    A,B                AND   A                LD    A,C                RET   NZ            ; If disk access done, return A=&00/&FF                CP    $FF                LD    A,2                RET                 ; If disk test done, return A=2 (drive C), C=ok, NC=absent;RestoreFS:      AND   A                LD    H,A                JR    NZ,SelectFS   ; A<>&00, select FSEnsureFS:       AND   A                RET   Z             ; Nothing to reselect                LD    H,A                           XOR   A                LD    E,A                CALL  OSARGS        ; A=FS, wantedFS in H preserved                XOR   H                RET   Z                XOR   H             ; If currentFS=wantedFS, return with A=0SelectFS:       PUSH  AF                LD    L,18                LD    A,143         ; Select FS in H                CALL  OSBYTE                POP   AF                RET                 ; Return previous FS or &00 in A; Sector Translate; ================; On entry, BC=sector; On exit,  HL=translated sector;SectorTranslate:                LD    H,B                LD    L,C                RET                 ; No translation;GetCCP:         LD    A,63          ; Ask for a CCP with *fx63                CALL  OSBYTE                INC   L                RET   NZ                  JP    LoadCCP        ; Otherwise, use Z80MOS                org    $f1e0                DB    "HDBIOS 1.24 (12 Sep 2010) (C)JGH"DRIVE           EQU   $F1DE         ; Current driveTRACK           EQU   DRIVE+1       ; Current trackSECTOR          EQU   TRACK+1       ; Current sectorcurrDRIVE:      EQU   SECTOR+1currTRACK:      EQU   currDRIVE+1currBLOCK:      EQU   currTRACK+1BLOCK:          EQU   currBLOCK+1LF1E5:          EQU   BLOCK+1       ; $00 - TIME has expired, $FF - dir cache still validLF1E6:          EQU   LF1E5+1       ; Used in HOMELF1E7:          EQU   LF1E6+1       ; Used in HOMELF1E8:          EQU   LF1E7+1LF1E9:          EQU   LF1E8+1       ; DRIVELF1EA:          EQU   LF1E9+1       ; TRACKLF1EB:          EQU   LF1EA+1       ; SECTORLF1EC:          EQU   LF1EB+1       ; READ/WRITE resultLF1ED:          EQU   LF1EC+1DSKRDWR:        EQU   LF1ED+1DSKDEFR:        EQU   DSKRDWR+1     ; Disk write deferredDMAADDR:        EQU   DSKDEFR+1     ; DMALF1F2:          EQU    $F1F2        ; DIRBUF, 128 bytes.LF272:          EQU    LF1F2+128    ; Disk deblock areaLF472:          EQU    LF272+512    ; Control block to read TIMELF477:          EQU    LF472+5      ; Previously read TIMELF47C           EQU    LF477+5; F4CC - internal stack for Disk routines, 40 entries; F4E0 - internal stack for Boot, 9 entries

Statistics: Posted by Coeus — Thu Feb 15, 2024 3:37 am



Viewing all articles
Browse latest Browse all 2379

Trending Articles