You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

509 lines
15 KiB

;======================================================================
; VDU DRIVER FOR N8VEM PROJECT
;
; ORIGINALLY WRITTEN BY: ANDREW LYNCH
; REVISED/ENHANCED BY DAN WERNER -- 11/7/2009
; ROMWBW ADAPTATION BY: WAYNE WARTHEN -- 11/9/2012
;======================================================================
;
; TODO:
; - ADD REMAINING REGISTERS TO INIT
; - TRY 25 ROW MODE?
; - IMPLEMENT CONSTANTS FOR SCREEN DIMENSIONS
; - IMPLEMENT SET CURSOR STYLE (VDASCS) FUNCTION
; - IMPLEMENT ALTERNATE DISPLAY MODES?
;
;======================================================================
; CVDU DRIVER - CONSTANTS
;======================================================================
;
VDU_RAMRD .EQU 0F0h ; READ VDU
VDU_RAMWR .EQU 0F1h ; WRITE VDU
VDU_STAT .EQU 0F2h ; VDU STATUS/REGISTER
VDU_REG .EQU 0F2h ; VDU STATUS/REGISTER
VDU_DATA .EQU 0F3h ; VDU DATA REGISTER
;
;======================================================================
; VDU DRIVER - INITIALIZATION
;======================================================================
;
VDU_INIT:
PRTS("VDU: IO=0x$")
LD A,VDU_RAMRD
CALL PRTHEXBYTE
;
CALL VDU_CRTINIT ; INIT SY6845 VDU CHIP
VDU_RESET:
LD DE,0
LD (VDU_OFFSET),DE
CALL VDU_XY
LD A,' '
LD DE,1024*16
CALL VDU_FILL
XOR A
RET
;
;======================================================================
; VDU DRIVER - CHARACTER I/O (CIO) DISPATCHER AND FUNCTIONS
;======================================================================
;
VDU_DISPCIO:
LD A,B ; GET REQUESTED FUNCTION
AND $0F ; ISOLATE SUB-FUNCTION
JR Z,VDU_CIOIN ; $00
DEC A
JR Z,VDU_CIOOUT ; $01
DEC A
JR Z,VDU_CIOIST ; $02
DEC A
JR Z,VDU_CIOOST ; $03
CALL PANIC
;
VDU_CIOIN:
JP PPK_READ ; CHAIN TO KEYBOARD DRIVER
;
VDU_CIOIST:
JP PPK_STAT ; CHAIN TO KEYBOARD DRIVER
;
VDU_CIOOUT:
JP VDU_VDAWRC ; WRITE CHARACTER
;
VDU_CIOOST:
XOR A ; A := 0
INC A ; A := 1, SIGNAL OUTPUT BUFFER READY
RET
;
;======================================================================
; VDU DRIVER - VIDEO DISPLAY ADAPTER (VDA) DISPATCHER AND FUNCTIONS
;======================================================================
;
VDU_DISPVDA:
LD A,B ; GET REQUESTED FUNCTION
AND $0F ; ISOLATE SUB-FUNCTION
JR Z,VDU_VDAINI ; $40
DEC A
JR Z,VDU_VDAQRY ; $41
DEC A
JR Z,VDU_VDARES ; $42
DEC A
JR Z,VDU_VDASCS ; $43
DEC A
JR Z,VDU_VDASCP ; $44
DEC A
JR Z,VDU_VDASAT ; $45
DEC A
JR Z,VDU_VDASCO ; $46
DEC A
JR Z,VDU_VDAWRC ; $47
DEC A
JR Z,VDU_VDAFIL ; $48
DEC A
JR Z,VDU_VDACPY ; $49
DEC A
JR Z,VDU_VDASCR ; $4A
DEC A
JP Z,PPK_STAT ; $4B
DEC A
JP Z,PPK_FLUSH ; $4C
DEC A
JP Z,PPK_READ ; $4D
CALL PANIC
VDU_VDAINI:
JR VDU_INIT ; INITIALIZE
VDU_VDAQRY:
LD C,$00 ; MODE ZERO IS ALL WE KNOW
LD DE,$1850 ; 24 ROWS ($18), 80 COLS ($50)
LD HL,0 ; EXTRACTION OF CURRENT BITMAP DATA NOT SUPPORTED
XOR A ; SIGNAL SUCCESS
RET
VDU_VDARES:
JR VDU_RESET ; DO THE RESET
VDU_VDASCS:
CALL PANIC ; NOT IMPLEMENTED (YET)
VDU_VDASCP:
CALL VDU_XY
XOR A
RET
VDU_VDASAT:
XOR A
RET
VDU_VDASCO:
XOR A
RET
VDU_VDAWRC:
LD A,E
CALL VDU_PUTCHAR
XOR A
RET
VDU_VDAFIL:
LD A,E ; FILL CHARACTER GOES IN A
EX DE,HL ; FILL LENGTH GOES IN DE
CALL VDU_FILL ; DO THE FILL
XOR A ; SIGNAL SUCCESS
RET
VDU_VDACPY:
; LENGTH IN HL, SOURCE ROW/COL IN DE, DEST IS CVDU_POS
PUSH HL ; SAVE LENGTH
CALL VDU_XY2IDX ; ROW/COL IN DE -> SOURCE ADR IN HL
POP BC ; RECOVER LENGTH IN BC
LD DE,(VDU_POS) ; PUT DEST IN DE
JP VDU_BLKCPY ; DO A BLOCK COPY
RET
VDU_VDASCR:
LD A,E ; LOAD E INTO A
OR A ; SET FLAGS
RET Z ; IF ZERO, WE ARE DONE
PUSH DE ; SAVE E
JP M,VDU_VDASCR1 ; E IS NEGATIVE, REVERSE SCROLL
CALL VDU_SCROLL ; SCROLL FORWARD ONE LINE
POP DE ; RECOVER E
DEC E ; DECREMENT IT
JR VDU_VDASCR ; LOOP
VDU_VDASCR1:
CALL VDU_RSCROLL ; SCROLL REVERSE ONE LINE
POP DE ; RECOVER E
INC E ; INCREMENT IT
JR VDU_VDASCR ; LOOP
;
;======================================================================
; CVDU DRIVER - PRIVATE DRIVER FUNCTIONS
;======================================================================
;
;----------------------------------------------------------------------
; WAIT FOR VDU TO BE READY FOR A DATA READ/WRITE
;----------------------------------------------------------------------
;
VDU_WAITRDY:
IN A,(VDU_STAT) ; READ STATUS
OR A ; SET FLAGS
RET M ; IF BIT 7 SET, THEN READY!
JR VDU_WAITRDY ; KEEP CHECKING
;
;----------------------------------------------------------------------
; UPDATE SY6845 REGISTERS
; VDU_WRREG WRITES VALUE IN A TO VDU REGISTER SPECIFIED IN C
; VDU_WRREGX WRITES VALUE IN DE TO VDU REGISTER PAIR IN C, C+1
;----------------------------------------------------------------------
;
VDU_WRREG:
PUSH AF ; SAVE VALUE TO WRITE
LD A,C ; SET A TO CVDU REGISTER TO SELECT
OUT (VDU_REG),A ; WRITE IT TO SELECT THE REGISTER
POP AF ; RECOVER VALUE TO WRITE
OUT (VDU_DATA),A ; WRITE IT
RET
;
VDU_WRREGX:
LD A,H ; SETUP MSB TO WRITE
CALL VDU_WRREG ; DO IT
INC C ; NEXT CVDU REGISTER
LD A,L ; SETUP LSB TO WRITE
JR VDU_WRREG ; DO IT & RETURN
;
;----------------------------------------------------------------------
; READ SY6845 REGISTERS
; VDU_RDREG READS VDU REGISTER SPECIFIED IN C AND RETURNS VALUE IN A
; VDU_RDREGX READS VDU REGISTER PAIR SPECIFIED BY C, C+1
; AND RETURNS VALUE IN HL
;----------------------------------------------------------------------
;
VDU_RDREG:
LD A,C ; SET A TO CVDU REGISTER TO SELECT
OUT (VDU_REG),A ; WRITE IT TO SELECT THE REGISTER
IN A,(VDU_DATA) ; READ IT
RET
;
VDU_RDREGX:
CALL VDU_RDREG ; GET VALUE FROM REGISTER IN C
LD H,A ; SAVE IN H
INC C ; BUMP TO NEXT REGISTER OF PAIR
CALL VDU_RDREG ; READ THE VALUE
LD L,A ; SAVE IT IN L
RET
;
;----------------------------------------------------------------------
; SY6845 DISPLAY CONTROLLER CHIP INITIALIZATION
;----------------------------------------------------------------------
;
VDU_CRTINIT:
LD C,0 ; START WITH REGISTER 0
LD B,16 ; INIT 16 REGISTERS
LD HL,VDU_INIT6845 ; HL = POINTER TO THE DEFAULT VALUES
VDU_CRTINIT1:
LD A,(HL) ; GET VALUE
CALL VDU_WRREG ; WRITE IT
INC HL ; POINT TO NEXT VALUE
INC C ; POINT TO NEXT REGISTER
DJNZ VDU_CRTINIT1 ; LOOP
RET
;
;----------------------------------------------------------------------
; CONVERT XY COORDINATES IN DE INTO LINEAR INDEX IN HL
; D=ROW, E=COL
;----------------------------------------------------------------------
;
VDU_XY2IDX:
LD A,E ; SAVE COLUMN NUMBER IN A
LD H,D ; SET H TO ROW NUMBER
LD E,80 ; SET E TO ROW LENGTH
CALL MULT8 ; MULTIPLY TO GET ROW OFFSET
LD E,A ; GET COLUMN BACK
ADD HL,DE ; ADD IT IN
RET ; RETURN
;
;----------------------------------------------------------------------
; SET CURSOR POSITION TO ROW IN D AND COLUMN IN E
;----------------------------------------------------------------------
;
VDU_XY:
LD A,E ; SAVE COLUMN NUMBER IN A
LD H,D ; SET H TO ROW NUMBER
LD E,80 ; SET E TO ROW LENGTH
CALL MULT8 ; MULTIPLY TO GET ROW OFFSET
LD E,A ; GET COLUMN BACK
ADD HL,DE ; ADD IT IN
LD (VDU_POS),HL ; SAVE THE RESULT (DISPLAY POSITION)
LD DE,(VDU_OFFSET) ; NOW GET THE BUFFER OFFSET
ADD HL,DE ; AND ADD THAT IN
LD C,14 ; CURSOR POSITION REGISTER PAIR
JP VDU_WRREGX ; DO IT AND RETURN
;
;----------------------------------------------------------------------
; WRITE VALULE IN A TO CURRENT VDU BUFFER POSTION, ADVANCE CURSOR
;----------------------------------------------------------------------
;
VDU_PUTCHAR:
LD B,A ; SAVE THE CHARACTER
; SET BUFFER WRITE POSITION
LD HL,(VDU_OFFSET)
LD DE,(VDU_POS)
ADD HL,DE
INC DE ; INC
LD (VDU_POS),DE ; SAVE NEW SCREEN POSITION
LD C,18 ; UPDATE ADDRESS REGISTER PAIR
CALL VDU_WRREGX ; DO IT
INC HL ; NEW CURSOR POSITION
LD C,14 ; CURSOR POSITION REGISTER PAIR
CALL VDU_WRREGX ; DO IT
LD A,31 ; PREP VDU FOR DATA R/W
OUT (VDU_REG),A
CALL VDU_WAITRDY ; WAIT FOR VDU TO BE READY
LD A,B
OUT (VDU_RAMWR),A ; OUTPUT CHAR TO VDU
RET
;
;----------------------------------------------------------------------
; FILL AREA IN BUFFER WITH SPECIFIED CHARACTER AND CURRENT COLOR/ATTRIBUTE
; STARTING AT THE CURRENT FRAME BUFFER POSITION
; A: FILL CHARACTER
; DE: NUMBER OF CHARACTERS TO FILL
;----------------------------------------------------------------------
;
VDU_FILL:
LD B,A ; SAVE THE FILL CHARACTER
; SET FILL START POSITION
PUSH DE
LD HL,(VDU_OFFSET)
LD DE,(VDU_POS)
ADD HL,DE
LD C,18
CALL VDU_WRREGX
POP DE
; FILL LOOP
LD A,31 ; PREP VDU FOR DATA R/W
OUT (VDU_REG),A
VDU_FILL1:
LD A,D ; CHECK NUMBER OF FILL CHARS LEFT
OR E
RET Z ; ALL DONE, RETURN
CALL VDU_WAITRDY ; WAIT FOR VDU TO BE READY
LD A,B
OUT (VDU_RAMWR),A ; OUTPUT CHAR TO VDU
DEC DE ; DECREMENT COUNT
JR VDU_FILL1 ; LOOP
;
;----------------------------------------------------------------------
; COPY A BLOCK (UP TO 255 BYTES) FROM HL TO FRAME BUFFER POSITION
; BC: NUMBER OF BYTES TO COPY
; HL: SOURCE POSITION
; DE: DESTINATION POSITION
;----------------------------------------------------------------------
;
VDU_BLKCPY:
; SETUP TO COPY FROM VDU SOURCE TO WORK BUFFER
PUSH DE ; SAVE VDU DESTINATION ADR
PUSH HL ; SAVE VDU SOURCE ADDRESS
LD HL,(VDU_OFFSET) ; GET THE CURRENT OFFSET
POP DE ; RECOVER SOURCE ADDRESS
ADD HL,DE ; HL HAS TRUE SOURCE ADR OF VIDEO BUF W/ OFFSET
LD DE,VDU_BUF ; POINT DE TO WORK BUFFER
PUSH BC ; SAVE COPY LENGTH FOR LATER
LD B,C ; NOW USE B FOR LENGTH (MAX COPY IS 255)
LD C,18 ; SET SOURCE ADDRESS IN VDU (HL)
CALL VDU_WRREGX ; DO IT
LD A,31 ; PREP VDU FOR DATA R/W
OUT (VDU_REG),A ; DO IT
LD HL,VDU_BUF ; HL POINTS TO WORK BUFFER
; LD C,VDU_RAMWR ; LOAD C WITH VDU WRITE REGISTER
VDU_BLKCPY1: ; VIDEO RAM -> BUFFER COPY LOOP
CALL VDU_WAITRDY ; WAIT FOR VDU
;;;;;;;;;;;;;;;;;
; INI IS NOT WORKING FOR ME, GARBAGE DATA READS, NO IDEA WHY
; INI ; READ BYTE, DEC B, INC HL
; IN A,(VDU_DATA) ; BOGUS READ TO INCREMENT VDU RAM ADDRESS!!!
; JR NZ,VDU_BLKCPY1 ; LOOP TILL DONE
;;;;;;;;;;;;;;;;;
IN A,(VDU_RAMRD) ; READ DATA BYTE
LD (HL),A ; SAVE IN BUFFER
INC HL ; BUMP SOURCE ADDRESS
IN A,(VDU_DATA) ; BOGUS READ TO INCREMENT VDU RAM ADDRESS!!!
DJNZ VDU_BLKCPY1 ; LOOP TILL DONE
; SETUP TO COPY FROM WORK BUFFER TO VDU DEST
POP BC ; RECOVER THE COPY LENGTH
LD HL,(VDU_OFFSET) ; GET THE CURRENT VDU OFFSET
POP DE ; RECOVER THE DEST ADDRESS
ADD HL,DE ; HL HAS TRUE DEST ADR OF VIDEO BUF W/ OFFSET
LD B,C ; NOW USE B FOR LENGTH (MAX COPY IS 255)
LD C,18 ; SET DEST ADDRESS IN VDU (HL)
CALL VDU_WRREGX ; DO IT
LD A,31 ; PREP VDU FOR DATA R/W
OUT (VDU_REG),A ; DO IT
LD HL,VDU_BUF ; HL POINTS TO WORK BUFFER
LD C,VDU_RAMWR ; LOAD C WITH VDU WRITE REGISTER
VDU_BLKCPY2: ; BUFFER -> VIDEO RAM COPY LOOP
CALL VDU_WAITRDY ; WAIT FOR VDU
OUTI ; WRITE BYTE, DEC B, INC HL
JR NZ,VDU_BLKCPY2 ; LOOP TILL DONE
;
RET ; RETURN
;
;----------------------------------------------------------------------
; SCROLL ENTIRE SCREEN FORWARD BY ONE LINE (CURSOR POSITION UNCHANGED)
;----------------------------------------------------------------------
;
VDU_SCROLL:
; SCROLL FORWARD BY ADDING ONE ROW TO DISPLAY START ADDRESS
LD HL,(VDU_OFFSET)
LD DE,80
ADD HL,DE
LD (VDU_OFFSET),HL
LD C,12
CALL VDU_WRREGX
; FILL EXPOSED LINE
LD HL,(VDU_POS)
PUSH HL
LD HL,23*80
LD (VDU_POS),HL
LD DE,80
LD A,' '
CALL VDU_FILL
POP HL
LD (VDU_POS),HL
; ADJUST CURSOR POSITION AND RETURN
LD HL,(VDU_OFFSET)
LD DE,(VDU_POS)
ADD HL,DE
LD C,14
JP VDU_WRREGX
;
;----------------------------------------------------------------------
; REVERSE SCROLL ENTIRE SCREEN BY ONE LINE (CURSOR POSITION UNCHANGED)
;----------------------------------------------------------------------
;
VDU_RSCROLL:
; SCROLL BACKWARD BY SUBTRACTING ONE ROW FROM DISPLAY START ADDRESS
LD HL,(VDU_OFFSET)
LD DE,-80
ADD HL,DE
LD (VDU_OFFSET),HL
LD C,12
CALL VDU_WRREGX
; FILL EXPOSED LINE
LD HL,(VDU_POS)
PUSH HL
LD HL,0
LD (VDU_POS),HL
LD DE,80
LD A,' '
CALL VDU_FILL
POP HL
LD (VDU_POS),HL
; ADJUST CURSOR POSITION AND RETURN
LD HL,(VDU_OFFSET)
LD DE,(VDU_POS)
ADD HL,DE
LD C,14
JP VDU_WRREGX
;
;==================================================================================================
; VDU DRIVER - DATA
;==================================================================================================
;
VDU_POS .DW 0 ; CURRENT DISPLAY POSITION
VDU_OFFSET .DW 0 ; CURRENT DISPLAY POSITION
VDU_BUF .FILL 256,0 ; COPY BUFFER
;
;==================================================================================================
; VDU DRIVER - SY6845 REGISTER INITIALIZATION
;==================================================================================================
;
VDU_INIT6845:
; DB 07FH, 50H, 60H, 7CH, 19H, 1FH, 19H, 1AH, 78H, 09H, 60H, 09H, 00H, 00H, 00H, 00H
;
; CCIR 625/50 VERSION (USED IN MOST OF THE WORLD)
; JUMPER K1 2-3, K2 1-2 FOR 2MHz CHAR CLOCK
.DB 07FH ; R0 TOTAL NUMBER OF HORIZONTAL CHARACTERS (DETERMINES HSYNC)
.DB 050H ; R1 NUMBER OF HORIZONTAL CHARACTERS DISPLAYED (80 COLUMNS)
.DB 060H ; R2 HORIZONTAL SYNC POSITION
.DB 00CH ; R3 SYNC WIDTHS
.DB 01EH ; R4 VERTICAL TOTAL (TOTAL CHARS IN A FRAME -1)
.DB 002H ; R5 VERTICAL TOTAL ADJUST (
.DB 018H ; R6 VERTICAL DISPLAYED (24 ROWS)
.DB 01AH ; R7 VERTICAL SYNC
.DB 078H ; R8 MODE B7=0 TRANSPARENT UPDATE DURING BLANKING
; B6=1 PIN 34 IS UPDATE STROBE
; B5=1 DELAY CURSOR 1 CHARACTER
; B4=1 DELAY DISPLAY ENABLE 1 CHARACTER
; B3=1 TRANSPARENT MEMORY ADDRESSING
; B2=0 RAM STRAIGHT BINARY ADDRESSING
; B1,B0=0 NON-INTERLACE
.DB 009H ; R9 SCAN LINE (LINES PER CHAR AND SPACING -1)
.DB 060H ; R10 CURSOR START RASTER
.DB 009H ; R11 CURSOR END RASTER
.DB 00H ; R12 START ADDRESS HI
.DB 00H ; R13 START ADDRESS LO
.DB 00H ; R14 CURSOR ADDRESS HI
.DB 00H ; R15 CURSOR ADDRESS LO
;
; THE CCIR 625/50 TELEVISION STANDARD HAS 625 LINES INTERLACED AT 50 FIELDS PER SECOND. THIS WORKS
; OUT AS 50 FIELDS OF 312.5 LINES PER SECOND NON-INTERLACED AS USED HERE.
; HORIZONTAL LINE WIDTH IS 64uS. FOR A 2 MHz CHARACTER CLOCK (R0+1)/2000000 = 64uS
; NEAREST NUMBER OF LINES IS 312 = (R4+1) * (R9+1) + R5.
; 15625 / 312 = 50.08 FIELDS PER SECOND (NEAR ENOUGH-DGG)
;