Zapple-II/SOFTCARD80.ASM#040000

1 line
5.0 KiB
Plaintext

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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