1 line
5.0 KiB
Plaintext
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
|