;remove the ORG statement, need to save space for network code
; ####### VDP OUTPUT ENTRY POINT ######
.VDU_OUTPUT
PUSH AF
PUSH BC
PUSH DE
PUSH HL
LD   HL,v_exit
PUSH HL
CALL killcur
.jp_vec
JP   initl

.ascr
DB &20
.v_attr
DB &02
.scrflg
DB &01
.pratr
DB &02
.npatr
DB &02
.wrmsk
DB &E0
.xloc
DB &00
.yloc
DB &00
.csr_flag
DB &FF

; jump table for printing control codes
.ctab
DW      DUMMY   ; ^@
DW      DOTDO   ; ^A
DW      VCTDO   ; ^B
DW      CXYDO   ; ^C
DW      BKGSET  ; ^D
DW      EOLDO   ; ^E
DW      ATRSET  ; ^F
DW      BELDO   ; ^G
DW      BSDO    ; ^H
DW      TABDO   ; ^I
DW      LFDO    ; ^J
DW      UPDO    ; ^K
DW      CLRDO   ; ^L
DW      CRDO    ; ^M
DW      BLSET   ; ^N
DW      BLOFF   ; ^O
DW      COLSET  ; ^P
DW      COLSET  ; ^Q
DW      COLSET  ; ^R
DW      COLSET  ; ^S
DW      COLSET  ; ^T
DW      COLSET  ; ^U
DW      COLSET  ; ^V
DW      COLSET  ; ^W
DW      INITLZ_CRT  ; ^X
DW      FWDDO   ; ^Y
DW      HMEDO   ; ^Z
DW      ESCDO   ; ^[
DW      SCRSET  ; ^\
DW      PGESET  ; ^]
DW      CSSET   ; ^^
DW      CSOFF   ; ^_   
.initl
PUSH BC
CALL clrdo
POP  BC
LD   HL,crtgo
LD   (jp_vec+1),HL
.crtgo
LD   A,C
AND  &E0
JR   Z,ctrl_code
;       PRINTABLE CHARACTER
;.frig1
;CALL dummy        ;code only needed with selectable fonts
CALL XYCALC
call set_write
ld a,c
out (1),a
CALL FWDDO
RET              ;jump to exit via stacked value above

.v_exit
;CALL xycalc
CALL setcur
POP  HL
POP  DE
POP  BC
POP  AF
RET

;       CONTROL CODE
.ctrl_code
LD   HL,ctab
LD   D,&00
LD   A,C
ADD  A,C
LD   E,A
ADD  HL,DE
LD   A,(HL)
INC  HL
LD   H,(HL)
LD   L,A
JP   (HL)

.escdo
CALL frigit          ;redirect VDU stream
LD   A,C
CP   &20
JR   C,v_normal
AND  &1F
ADD  A,A
LD   HL,esctab
LD   E,A
LD   D,&00
ADD  HL,DE
LD   A,(HL)
INC  HL
LD   H,(HL)
LD   L,A
JP   (HL)

;cursor X,Y invalid values ignored
.cxydo
CALL frigit          ;redirect VDU stream
LD   A,C
SUB  &20
AND  &7F
CP   40              ;screen width
JR   NC,cxskip
LD   (xloc),A        
.cxskip
CALL frigit          ;redirect VDU stream
LD   A,C
SUB  &20
AND  &7F
CP   24              ;screen rows
JR   NC,cyskip
LD   (yloc),A
.cyskip
;this section returnes the VDU stream to normal after assembling a multi byte command
.v_normal
LD   HL,crtgo
LD   (jp_vec+1),HL
RET

;set the VDU stream to code following the call to frigit, for assembling multi byte commands
.frigit
POP  HL
LD   (jp_vec+1),HL
RET

;character background not setable, so code does nothing
.bkgset
CALL frigit          ;redirect VDU stream
LD   A,C
AND  &07
RLCA
RLCA
RLCA
LD   C,A
LD   A,(pratr)
AND  &C7
OR   C
LD   (pratr),A
LD   A,(npatr)
AND  &C7
OR   C
LD   (npatr),A
JP   v_normal

;no attributes on 9928 code does nothing
.atrset
CALL frigit          ;redirect VDU stream
LD   A,C
LD   (pratr),A
LD   (npatr),A
JP   v_normal

; no bitmap character set on the 9928 setup so plot and draw disabled
; swallow the character codes to maintain compatibility
.dotdo
CALL frigit          ;redirect VDU stream
LD   A,C
SUB  &20             ;&20 byte offset in plot commands
LD   (initl),A        ;save first perameter
CALL frigit          ;redirect VDU stream again
LD   A,C
;SUB  &20
LD   H,A             ;2nd parameter
LD   A,(initl)
LD   L,A
;CALL plotd
JP   v_normal          ;reset stream

.vctdo
CALL frigit
LD   A,C
SUB  &20
LD   (initl),A
CALL frigit
LD   A,C
SUB  &20
LD   (initl+1),A
CALL frigit
LD   A,C
SUB  &20
LD   (initl+2),A
CALL frigit
LD   A,C
SUB  &20
LD   C,A
;CALL plotv
JP   v_normal

.initlz_crt
LD   A,&FF
LD   HL,scrflg
LD   (HL),&FF
INC  HL
LD   (HL),&02
INC  HL
LD   (HL),&02
INC  HL
LD   (HL),&E0
CALL    CSSET
CALL    CRDO
CALL    LFDO
ret 
;JP      ESTD

;blink on and off not used, as no character level attributes

.blset
LD   A,(pratr)
OR   &40
LD   (pratr),A
RET

.bloff
LD   A,(pratr)
AND  &BF
LD   (pratr),A
RET

;no hardware cursor on 9928 in text mode
;turn cursor on value will be used as bit mask
.csset
ld a,&FF
ld (csr_flag),a
RET

.csoff
xor a
ld (csr_flag),a
RET

;scroll flag is 0 for page mode (no scroll)
.scrset
LD   A,&FF
LD   (scrflg),A
RET

.pgeset
XOR  A
LD   (scrflg),A
RET

; 9928 does not support individual charater attributes in text mode
; so this code does nothing
.colset
LD   A,C
AND  &07
LD   C,A
LD   A,(pratr)
AND  &F8
OR   C
LD   (pratr),A
RET

; carriage return justs sets the X location back to zero
; dummy entry point for the nul codes
.crdo
XOR  A
LD   (xloc),A
.dummy
RET


; tab forward by setting the low bits of the x location then drop into cursor right
.tabdo
LD   A,(xloc)
OR   &07
LD   (xloc),A
.fwddo
LD   A,(xloc)
CP   39             ;screen widht less 1
JR   Z,fwdl
INC  A
LD   (xloc),A
RET

; need to go down a line so reset x to zero and drop through into cursor down
.fwdl
XOR  A
LD   (xloc),A
.lfdo
LD   A,(yloc)
CP   &17           ; are we on the 24th row (rows are 0-23) 
JR   Z,LFS         ;jump forward to test the scroll flag
INC  A
.pagem
LD   (yloc),A
RET

.lfs
LD   A,(scrflg)
OR   A
JR   Z,pagem      ;set Y back tothe top of the screen if it's page mode
CALL scrup        ;otherwise scroll up, leaving Y as 23
RET

; "DING"
;"beep" code from the Magrom
.beldo 
push AF
push BC
push hl
ld HL, 284
LD A,L
AND &0F
OR &80
call s_sound          ; SEND TONE 1 + 4 BITS OF FREQUENCY
LD A,L
SRL A
SRL A
SRL A
SRL A
LD C,A
LD A,H
SLA A
SLA A
SLA A
SLA A
OR C
AND &3F                  ; REMAINING 6 OF THE 10 BITS OF FREQUENCY
call s_sound
LD A,&90                 ; ATTENUATION 0DB TONE 1
call s_sound
ld bc,00A0
.delay_loop
djnz delay_loop
dec c
jr nz delay_loop
;kill sound
LD A,&9f          ; ATTENUATION OFF TONE 1
call s_sound
pop hl
pop bc
pop AF
RET

;send data to sound port with delay to guarantee sound chip time to load it. 
.S_sound
OUT (6),A
IN A,(3)
ld B,2
.ss_loop
djnz ss_loop
RET


;non clearing backspace
.bsdo
LD   A,(xloc)
OR   A
JR   Z,bsu
DEC  A
LD   (xloc),A
RET

;backspace needs to go up a line
.bsu
LD   A,39          ;screen with less 1
LD   (xloc),A
LD   A,(yloc)
OR   A
JR   Z,bss
DEC  A
LD   (yloc),A
RET

;were already at 0,0 so need to put the x position back to 0
.bss
;   XOR  A    ; not needed A was 0 or we wouldn't be here?
LD   (xloc),A
RET

;cursor up   
.updo
LD   A,(yloc)
OR   A
ret  Z             ;can't go up from top row
DEC  A
LD   (yloc),A
RET

.clrdo
CALL clrscn      ;clear the screen and fall through into home to set the cursor
.hmedo
XOR  A
LD   (xloc),A
LD   (yloc),A
RET

.erln
LD   A,(xloc)
PUSH AF
XOR  A
LD   (xloc),A
CALL eoldo
POP  AF
LD   (xloc),A
RET

.eoldo
CALL xycalc
LD   A,(xloc)
LD   B,A
JP   erase_eol

;       UTILITIES

.grpmap
LD   A,C
AND  &7F
LD   C,A
AND  &40
RET  Z
LD   A,C
AND  &20
RLCA
RLCA
OR   C
AND  &9F
LD   C,A
RET

.altmap
LD   A,C
OR   &80
LD   C,A
RET

.getmsk
LD   A,C
CP   &30
JR   NZ,getbit
XOR  A
RET

.getbit
DEC  A
AND  &07
LD   C,A
CALL ncalc
OR   A
RET


; set the VRAM pointer to HL for reading and writing respectively
.set_read
push AF
ld a,L          ;setup VDP address
out (2),a
and &3f
ld a,h          ;bit 6 and 7 clear for VRAM read
out (2),a
pop AF
ret

.set_write
push AF
ld a,L          ;setup VDP address
out (2),a
ld a,h          ;set bit 6, bit 7 clear for VRAM write
add a,&40 
out (2),A
pop AF
ret


;cursor on/off needs to preserve registers as is called before any VDU output
;uses inverted version of screen character, 
.setcur
.killcur
push hl
push DE
push af
call xycalc
call set_read
in a,(1)
call set_write
xor &80         ; need to qualify this with the cursor on/off flag
out (1),a
pop af
pop DE
pop hl
RET

; calculate the cursor position
.xycalc
LD   A,(xloc)
LD   D,A
LD   A,(yloc)
LD   E,A
.calc1
; enter here if DE already set
LD   A,E      
ADD  A,A      ;y x 2
ADD  A,A      ;y x 4
ADD  A,E      ;y x 5
ADD  A,A      ;y x10    ;max Y value 24, now move to 16 bit addition
LD   L,A
LD   H,&00
ADD  HL,HL    ;y x20
ADD  HL,HL    ;y x40
LD   E,D
LD   D,&00
ADD  HL,DE    ;y x40 + x
LD   A,H
AND  &07
LD   H,A
RET

.ncalc
INC  C
LD   A,&01
.ncalcl
DEC  C
RET  Z
RLCA
JR   ncalcl

;delete line at cursor and scroll up
; set HL to pont to the start of the line below
; set C to the number of lines remaining 
; then call the scroll up code at it's looping point
.edcsln
ld a,(yloc)
cp &17           ;are we already on the last line ?
jp z blank_last
inc a
ld e,a
ld d,0
call calc1
ld a,e
CPL
ADD a,23
ld c,a
call scroll_loop     ;does the scroll and blanks the last line
jp v_normal

.scrup
ld HL,40        ;start with line 1
ld c,23         ;23 rows to scroll
.scroll_loop
call set_read
ld de,scroll_buff
ld b,40
.scroll_read
in a,(1)
ld (de),a
inc DE
djnz scroll_read
ld de,&ffD8     ;subtract 40 from HL to find the address to write
add hl,de
call set_write
ld de,scroll_buff
ld b,40
.scroll_write
ld a,(de)
out (1),a
inc DE
djnz scroll_write
ld de,80        ;add 2x line length
add hl,de       ;move HL on to the next line to be read in
dec c
jr nz,scroll_loop
jp blank_last


.clrscn
ld hl, &0000
call set_write
ld BC,&c004        ;write 960 spaces (&3c0)
ld a,32
.CLRscLP
out (1),a
djnz clrsclp
dec c
JR NZ,clrsclp
RET

; erase to the end of the line from character B
;xycalc has been called so HL holds the screen position
.erase_eol
LD   A,40
sub b
LD   B,A
call set_write
ld a, 32
.ereol_lp
out (1),a
djnz  ereol_lp
ret


;       ESCAPE SEQUENCE LOOK-UP TABLE

.ESCTAB
DW      v_normal  ; @
DW      v_normal  ; DW      EALT    ; A set alternate character font
DW      EBOTH   ; B set both attribute bytes
DW      ESCRL   ; C set scroll mode
DW      EPGE    ; D set page mode
DW      ECSON   ; E cursor on
DW      ECSOFF  ; F cursor off
DW      v_normal  ; DW      EGRPH   ; G set graphic font
DW      v_normal  ; H
DW      EIBLLN  ; I insert blank line at cursor move the other lines down
DW      EDCSLN  ; J delete line at cursor move the other lines up
DW      v_normal  ; K
DW      v_normal  ; L
DW      v_normal  ; M
DW      ENPATR  ; N set non printing attribute
DW      v_normal  ; O
DW      EPRATR  ; P set printing attribute
DW      v_normal  ; Q      ; in SCPM ROM, disable color, cls
DW      EREAD   ; R      ; in SCPM ROM, enable color, cls
DW      v_normal  ; DW      ESTD    ; S set standard font
DW      ESIPR   ; T
DW      ESINP   ; U
DW      ESIBT   ; V
DW      EWRMS   ; W
DW      CNTSIM  ; X
DW      v_normal  ; Y
DW      v_normal  ; Z
DW      v_normal  ; [
DW      v_normal  ; \
DW      v_normal  ; ]
DW      v_normal  ; ^
DW      v_normal  ; _

;       ESCAPE SEQUENCE HANDLERS
;only one character set provided in text 2 mode
;.ESTD
;LD   HL,DUMMY
;LD   (frig1+1),HL
;JP   v_normal

;.ealt
;LD   HL,altmap
;LD   (frig1+1),HL
;JP   v_normal

;.egrph
;LD   HL,grpmap
;LD   (frig1+1),HL
;JP   v_normal
; 
;simulate control character 
.cntsim
CALL frigit
LD   A,C
AND  &1F
LD   C,A
CALL v_normal
JP   ctrl_code

.escrl
CALL scrset
JP   v_normal

.epge
CALL pgeset
JP   v_normal

.ecson
CALL csset
JP   v_normal

.ecsoff
CALL csoff
JP   v_normal

; set attributes directly, rather than by bit
.esipr
CALL frigit
LD   A,C
LD   (pratr),A
JP   v_normal

.esinp
CALL frigit
LD   A,C
LD   (npatr),A
JP   v_normal

.esibt
CALL frigit
LD   A,C
LD   (npatr),A
LD   (pratr),A
JP   v_normal




.blank_last
ld HL,920        ; = the start of the last screen row
.blank_current
call set_write
ld a,32
ld b,40
.blanks_loop
out (1),a
djnz blanks_loop
jp v_normal


;insert line at cursor and scroll down
.eiblln
ld a,(yloc)
cp &17
jr z blank_last     ;on the last row, just blank it
CPL                 ;ones complement so A=-(row)-1
add a,24            ;add 24, as we want one less row - to allow for inserting
ld c,a              ;rows to scroll
ld HL,880          ;working fom the bottom up, row 22 (to row 23) is always the first to be moved    
.scroll_d_loop
call set_read
ld de,scroll_buff
ld b,40
.scroll_d_read
in a,(1)
ld (de),a
inc de
DJNZ scroll_d_read
ld de,40            ;move down to the start of the next row
add hl,DE
call set_write
ld de,scroll_buff
ld b,40
.scroll_d_write
ld a,(de)
out (1),a
inc DE
djnz scroll_d_write
ld de,&FFB0       ;-80 to move up 2 rows
add HL,DE
dec C
jr nz scroll_d_loop
ld de,40         ;move back to the "current" line
add hl,de
; now insert the blank line,
JP  blank_current


;read character at cursor ??
.eread
CALL xycalc
call set_read
ld   a,2             ;set an attribute just in case
ld   (v_attr),A
IN   A,(1)
LD   (ascr),A
JP   v_normal


; setup write mask
.ewrms
CALL frigit
LD   A,C
LD   C,&E0
CP   &30
JR   Z,swrm
LD   C,&C0
CP   &31
JR   Z,swrm
LD   C,&A0
CP   &32
JP   NZ,v_normal
.swrm
LD   A,C
LD   (wrmsk),A
JP   v_normal

;set printing attribute  
.epratr
CALL frigit
CALL getmsk
JR   Z,setpr
LD   C,A
LD   A,(pratr)
OR   C
.setpr
LD   (pratr),A
JP   v_normal

; set non printing attribute   
.enpatr
CALL frigit
CALL getmsk
JR   Z,setnp
LD   C,A
.enpa1
LD   A,(npatr)
OR   C
.setnp
LD   (npatr),A
JP   v_normal

;set both printing and non prining attributes. Does nothing on V9958.
.eboth
CALL frigit
CALL getmsk
JR   NZ,v_setb
LD   (pratr),A
JR   setnp

.v_setb
LD   C,A
LD   A,(pratr)
OR   C
LD   (pratr),A
JR   enpa1

DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
.vstk


END
