From 89f38d70a0916ad09c7d699d981a6f495f8eb0f9 Mon Sep 17 00:00:00 2001 From: Bobbi Webber-Manners Date: Sun, 13 Oct 2019 00:33:50 -0400 Subject: [PATCH] Added a few more of the simple BDOS calls. --- SOFTCARD80.ASM#040000 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SOFTCARD80.ASM#040000 b/SOFTCARD80.ASM#040000 index 135ad9a..15f2da9 100644 --- a/SOFTCARD80.ASM#040000 +++ b/SOFTCARD80.ASM#040000 @@ -1 +1 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Z80 code running on Softcard ; This is invoked by the companion SOFTCARD65 6502 code ; Bobbi 2019 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SOFTCARD EQU 0E400H ; Softcard in slot 4 ($C400) CMD EQU 0F006H ; 6502 $06 AREG EQU 0F007H ; 6502 $07 XREG EQU 0F008H ; 6502 $08 YREG EQU 0F009H ; 6502 $09 ADDR EQU 0F0EBH ; 6502 $EB (LSB) ADDRH EQU 0F0ECH ; 6502 $EC (MSB) ; Addresses of 6502 routines, in 6502 address space COUT EQU 0FDEDH ; Print char in A RDKEY EQU 0FD0CH ; Read key, return in A BELL EQU 0FBE4H ; Sound the bell ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Entry point when Z80 cold starts is 0000H ORG 0000H JP START ; Skip to the actual program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; BDOS entry point must be at address 0005H for CP/M compatibility ; Function to invoke is passed in C ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ORG 0005H BDOS JP BDOSI ; BDOS code is at top of memory ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; The application program proper starts at 0100H ; in order to be compatible with CP/M .COM programs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ORG 0100H STCHAR EQU 65 ; First character code 'A' ENDCHAR EQU 91 ; Last character code 'Z' ; Print the alphabet using C_WRITE START LD B,STCHAR L1 LD E,B ; Character to print LD C,2 ; C_WRITE call PUSH BC ; Preserve B (and C) CALL BDOS ; CP/M BDOS call POP BC ; Restore B (and C) INC B LD A,ENDCHAR CP B JP Z,S1 JP L1 ; Loop until there is a keystroke waiting using C_STAT S1 LD C,0BH ; C_STAT call CALL BDOS ; CP/M BDOS call CP 0 ; Anything? JR Z,S1 ; If not, loop ; Print a couple of spaces LD E,32 ; LD C,2 ; C_WRITE call CALL BDOS ; CP/M BDOS call LD E,32 ; LD C,2 ; C_WRITE call CALL BDOS ; CP/M BDOS call ; Read keyboard and echo to screen C_READ, C_WRITE L2 LD C,1 ; C_READ call CALL BDOS ; CP/M BDOS call LD E,A ; Prepare to echo keystroke LD C,2 ; C_WRITE call CALL BDOS ; CP/M BDOS call JP L2 ; Forever and ever ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Implementation of BDOS ; Function to invoke is passed in C ; C=01H C_READ Console read ; C=02H C_WRITE Console write ; C=0BH C_STAT Console status ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ORG 0D000H ; $B000 on 6502 - OK FOR NOW ORG 05000H ; Move it down to avoid Z80asm bug BDOSI LD HL,BDOSVEC ; Start of vector table SLA C ; Multiply C by 2 LD B,0 ; MSB of BC is zero ADD HL,BC ; Address of vector in HL LD C,(HL) ; Read LSB of address to jump to INC HL ; Read MSB of address to jump to LD H,(HL) ; ... LD L,C ; Address needs to be in HL JP (HL) ; Jump to it! ; Vector table BDOSVEC DEFW UNIMP ; C=00H DEFW C_READ ; C=01H DEFW C_WRITE ; C=02H DEFW UNIMP ; C=03H DEFW UNIMP ; C=04H DEFW UNIMP ; C=05H DEFW UNIMP ; C=06H DEFW UNIMP ; C=07H DEFW UNIMP ; C=08H DEFW UNIMP ; C=09H DEFW UNIMP ; C=0AH DEFW C_STAT ; C=0BH DEFW UNIMP ; C=0CH ; TODO: Complete this!! ; Unimplemented BDOS call, just ring the bell UNIMP LD HL,BELL ; We are going to call BELL LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! RET ; Return to calling program ; Wait for a character from the console, return it in A and L ; Also echoes the char to the console C_READ LD HL,RDKEY ; We are going to call RDKEY LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! LD A,(AREG) ; Grab the return value PUSH AF ; Preserve A (and F) LD HL,COUT ; Echo the character using COUT LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! POP AF ; Restore A (and F) AND 7FH ; Mask high bit LD L,A ; Copy A to L RET ; Return to calling program ; Write character in E to the console ; TODO: Handle tabs, ^S and ^Q C_WRITE LD A,80H ; Set high bit OR E ; ... CP 8AH ; Check for linefeed RET Z ; If LF, don't print it LD (AREG),A ; Pass char to COUT in 6502 A LD HL,COUT ; We are going to call COUT LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! RET ; Return to calling program ; Returns 0 in A and L if no chars waiting, non zero otherwise ; TODO: Implement this C_STAT LD A,3 ; CMD=3 means peek at keyboard LD (CMD),A ; ... LD (SOFTCARD),A ; Do it LD A,(AREG) ; Grab the return value LD L,A ; Copy A to L RET ; Return to calling program \ No newline at end of file +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Z80 code running on Softcard ; This is invoked by the companion SOFTCARD65 6502 code ; Bobbi 2019 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SOFTCARD EQU 0E400H ; Softcard in slot 4 ($C400) CMD EQU 0F006H ; 6502 $06 AREG EQU 0F007H ; 6502 $07 XREG EQU 0F008H ; 6502 $08 YREG EQU 0F009H ; 6502 $09 ADDR EQU 0F0EBH ; 6502 $EB (LSB) ADDRH EQU 0F0ECH ; 6502 $EC (MSB) ; Addresses of 6502 routines, in 6502 address space COUT EQU 0FDEDH ; Print char in A RDKEY EQU 0FD0CH ; Read key, return in A BELL EQU 0FBE4H ; Sound the bell ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Entry point when Z80 cold starts is 0000H ORG 0000H JP START ; Skip to the actual program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; BDOS entry point must be at address 0005H for CP/M compatibility ; Function to invoke is passed in C ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ORG 0005H BDOS JP BDOSI ; BDOS code is at top of memory ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; The application program proper starts at 0100H ; in order to be compatible with CP/M .COM programs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ORG 0100H STCHAR EQU 65 ; First character code 'A' ENDCHAR EQU 91 ; Last character code 'Z' ; Print signon message using C_WRITESTR START LD DE,WELCOME ; Address of string LD C,09H ; C_WRITESTR call CALL BDOS ; CP/M BDOS call ; Print the alphabet using C_WRITE LD B,STCHAR L1 LD E,B ; Character to print LD C,2 ; C_WRITE call PUSH BC ; Preserve B (and C) CALL BDOS ; CP/M BDOS call POP BC ; Restore B (and C) INC B LD A,ENDCHAR CP B JP Z,S1 JP L1 ; Loop until there is a keystroke waiting using C_STAT S1 LD C,0BH ; C_STAT call CALL BDOS ; CP/M BDOS call CP 0 ; Anything? JR Z,S1 ; If not, loop ; Print a couple of spaces LD E,32 ; LD C,2 ; C_WRITE call CALL BDOS ; CP/M BDOS call LD E,32 ; LD C,2 ; C_WRITE call CALL BDOS ; CP/M BDOS call ; Read keyboard and echo to screen C_READ, C_WRITE L2 LD C,1 ; C_READ call CALL BDOS ; CP/M BDOS call LD E,A ; Prepare to echo keystroke LD C,2 ; C_WRITE call CALL BDOS ; CP/M BDOS call JP L2 ; Forever and ever WELCOME DEFM 'ZAPPLE-II TEST STUB' DEFB 13, '$' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Implementation of BDOS ; Function to invoke is passed in C ; C=00H C_TERMCPM System reset ; C=01H C_READ Console read ; C=02H C_WRITE Console write ; C=09H C_WRITESTR Console write string ; C=0BH C_STAT Console status ; C=0DH S_BDOSVER Return version number ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ORG 0D000H ; $B000 on 6502 - OK FOR NOW ORG 05000H ; Move it down to avoid Z80asm bug BDOSI LD A,C ; Prepare to check C is in range CP 41 ; Max syscall# for CP/M 2.2 is 40 JP NC,UNIMP ; If >41 then call UNIMP LD HL,BDOSVEC ; Start of vector table SLA C ; Multiply C by 2 LD B,0 ; MSB of BC is zero ADD HL,BC ; Address of vector in HL LD C,(HL) ; Read LSB of address to jump to INC HL ; Read MSB of address to jump to LD H,(HL) ; ... LD L,C ; Address needs to be in HL JP (HL) ; Jump to it! ; Vector table BDOSVEC DEFW C_TERMCPM ; C=00H DEFW C_READ ; C=01H DEFW C_WRITE ; C=02H DEFW UNIMP ; C=03H DEFW UNIMP ; C=04H DEFW UNIMP ; C=05H DEFW UNIMP ; C=06H DEFW UNIMP ; C=07H DEFW UNIMP ; C=08H DEFW C_WRITESTR ; C=09H DEFW UNIMP ; C=0AH DEFW C_STAT ; C=0BH DEFW S_BDOSVER ; C=0CH DEFW DRV_ALLRST ; C=0DH DEFW DRV_SET ; C=0EH DEFW UNIMP ; C=0FH DEFW UNIMP ; C=10H DEFW UNIMP ; C=11H DEFW UNIMP ; C=12H DEFW UNIMP ; C=13H DEFW UNIMP ; C=14H DEFW UNIMP ; C=15H DEFW UNIMP ; C=16H DEFW UNIMP ; C=17H DEFW UNIMP ; C=18H DEFW UNIMP ; C=19H DEFW UNIMP ; C=1AH DEFW UNIMP ; C=1BH DEFW UNIMP ; C=1CH DEFW UNIMP ; C=1DH DEFW UNIMP ; C=1EH DEFW UNIMP ; C=1FH DEFW UNIMP ; C=20H DEFW UNIMP ; C=21H DEFW UNIMP ; C=22H DEFW UNIMP ; C=23H DEFW UNIMP ; C=24H DEFW UNIMP ; C=25H DEFW UNIMP ; C=26H DEFW UNIMP ; C=27H ; Unimplemented BDOS call, just ring the bell UNIMP LD HL,BELL ; We are going to call BELL LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! RET ; Return to calling program ; System reset. Jump to $0000 - doesn't return C_TERMCPM RST 0 ; Quick jump to zero ; Wait for a character from the console, return it in A and L ; Also echoes the char to the console C_READ LD HL,RDKEY ; We are going to call RDKEY LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! LD A,(AREG) ; Grab the return value PUSH AF ; Preserve A (and F) LD HL,COUT ; Echo the character using COUT LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! POP AF ; Restore A (and F) AND 7FH ; Mask high bit LD L,A ; Copy A to L RET ; Return to calling program ; Write character in E to the console ; TODO: Handle tabs, ^S and ^Q C_WRITE LD A,80H ; Set high bit OR E ; ... CP 8AH ; Check for linefeed RET Z ; If LF, don't print it LD (AREG),A ; Pass char to COUT in 6502 A LD HL,COUT ; We are going to call COUT LD (ADDR),HL ; ... LD A,1 ; CMD=1 means call 6502 sub LD (CMD),A ; ... LD (SOFTCARD),A ; Do it! RET ; Return to calling program ; Write ASCII string to console. '$' is the terminator ; DE contains the address of the string C_WRITESTR LD A,(DE) ; Fetch character from string CP 36 ; Is it '$'? RET Z ; If so, we are done PUSH DE ; We are gonna need E LD E,A ; For C_WRITE CALL C_WRITE ; Sent char to console POP DE ; Recover the pointer INC DE ; Advance pointer JP C_WRITESTR ; Handle the next char ; Returns 0 in A and L if no chars waiting, non zero otherwise C_STAT LD A,3 ; CMD=3 means peek at keyboard LD (CMD),A ; ... LD (SOFTCARD),A ; Do it LD A,(AREG) ; Grab the return value LD L,A ; Copy A to L RET ; Return to calling program ; Returns system type in B and H, BDOS version in A and L S_BDOSVER LD B,0 ; System is 8080 CP/M LD H,B ; Also in H LD A,22H ; Pretend to v2.2 LD L,A ; Also in A RET ; Reset disks ; Makes A: drive the default ; TODO: Empty all disk buffers, reset DMA address to BOOT+80H DRV_ALLRST LD A,0 ; 0 means drive A: LD (CURDRV),A ; Store in CURDRV RET ; Select disk ; Disk to select is passed in E (A: is 0, B: is 1 etc.) ; Return 00 for success, FFH for error in A and L DRV_SET LD A,E ; Prepare to compare disk number CP 2 ; Support two 'drives' A:,B: JP NC,DSERR ; If >1 LD (CURDRV),A ; Store the requested drive number LD A,0 ; Return code meaning success JP DSRET ; DSERR LD A,0FFH ; Return code for error DSRET LD L,A ; Return code in L too RET ; BDOS data CURDRV DEFB 0 ; Currently logged in drive \ No newline at end of file