.title "K84SCRN.ASM Kaypro '83 screen driver 11/8/86" .sbttl "Copyright (c) 1986 Plu*Perfect Systems" noatt = 1 ;nul return-attribute function to save space DEBUG = 0 .remark \== Source code for CDL/TDL Z80 assembler (AZM.COM). ; production by: ; AZM k84scrn ZLINK *k84.com=k84scrn.rel */locate .prog.=3f80; *q ZSID k84.com m3f80 4500 100 ^C SAVE 5 k84scrn.drv ==\ ; revision history: ; ; v 1.0: no scroll on line 24 in cut ; id imbedded in string ; most data put in-line to save bytes .XLIST .ifg DEBUG, [ bios =\ 'Base of bios = ?' ] .remark \=== The first sections of code are generic (except for some terminal equates); beginning at 'STMRKS' it is terminal-specific. Particular features of Kaypro '84 code: 1. Video ram must be accessed via video controller. 2. We store screen attributes as nybbles. 3. Cursor-movement sequences are all single-byte control characters. Space is very tight; in-line data used extensively. ===\ .ifg DEBUG, [ codloc = 100h .phex .psym .pabs consta = bios +06h conin = bios +09h conout = bios +0ch ] ; [ .prel .ident SCRK84 consta = 0 conin = 0 conout = 0 outch = 0 puts = 0 bwrch = 0 bflush = 0 ] .xsym .sall ; ; ascii equates ; NUL = 00h BELL = 07h BS = 08h CR = 0dh LF = 0ah ESC = 1bh SPACE = 20h DEL = 7fh ; ; CUT command characters ; HOME = 'H' ;home the cursor LOHOME = 'h' MARK = 'X' ;set a mark LOMARK = 'x' PASTE = 'P'-'@' ;paste region at cursor CANCEL = 'C'-'@' ;cancel cut command ; ; ; TERMINAL-SPECIFIC EQUATES ; ; kaypro cursor controls ; LEFT = 08H RIGHT = 'L'-'@' UP = 'K'-'@' DOWN = 0AH ; LEFT8 = 82h ;kaypro raw keypad arrow values... RIGHT8 = 83h UP8 = 80h DOWN8 = 81h ; HOMEC = 1eh ;home cursor ; ; Kaypro '84 screen parameters ; NCOLS = 80 NROWS = 25 NROW24 = 24 ;# rows excluding status line ; SCRSIZ = NCOLS*NROWS ; ; Kaypro '84 controller ports ; vcbase = 1ch vccmd = vcbase vcstat = vcbase vcrdat = vcbase+1 vcdata = vcbase+3 ; ; controller register numbers ; cstart = 10 ;cursor start cstop = 11 ;cursor stop hiadd = 18 ;hi address byte - update register loadd = 19 ;lo "" ; scrcmd = 12 ;"scroll" set home addr curcmd = 14 ;place cursor rwcmd = 18 ;read/write strcmd = 31 ;strobe ; ;========================= .ifg DEBUG, [ .loc codloc ] ; [ .loc .PROG. ] ; ;------------------------------------------------------------ ; ; id sector - nul-terminated string - at 3f80h ; sdid: .ascii "Kaypro '84 driver v 1.0" db 0 ;NUL terminator idlen = . - sdid ds 80h-idlen ;total of 80h bytes ; START: ; ; ; Start of Screen Module. Assemble to run at 4000h. ; ;***** MODULE ENTRY HEADER ; ; EXTERNAL ADDRESSES, supplied by loader ; jjcons: jmp consta ;bios constat jjconi: jmp conin ;bios conin jjouta: jmp outch ;A to conout, preserving bc,de,hl jjputs: jmp puts ;hl-string to conout, NUL/bit-7 term. ; preserving bc,de,hl jjbrdc: jmp 0000 ;buffered read char from cut-swp jjbwrc: jmp bwrch ;buffered write char to cut-swp jjbflu: jmp bflush ;flush (write) buffer ; ; INTERNAL ENTRY POINTS ; savscr: jmp savpag ;save screen resscr: jmp respag ;restore saved screen lastnb: jmp lstnbl ;last non-blank char in rows 1-24 dmpchr: jmp retnch ;return next screen char dmpcur: jmp retncu ;return buffer cursor dmpatt: jmp retnat ;return next screen attribute setmrk: jmp stmrks ;set region marks, move cursor cutrg: jmp docut ;cut region pastrg: jmp dopast ;paste region ininpd: jmp ininot ;initialize notepad putnpd: jmp putnch ;put char to notepad ; ;======================================== ; generic ; ININOT: ; ; Initiate Notepad - clear screen, print banner. ; lxi h,Zbanner jr jjputs ; ;======================================== ; generic ; PUTNCH: ; ; Put char in A to notepad (screen) ; Convert CR to CRLF, DEL to rubout. ; cpi CR lxi h,Zcrlf ;convert CR to CR,LF jrz jjputs cpi DEL lxi h,Zrub jrz jjputs jr jjouta ;======================================== ; generic ; RETNCU: ; ; Return buffer cursor as row/col. ; ; ret: D = binary row, E= binary col ; L = ascii row, H = ascii col (for shld ...) ; lhld bcursor ; ; Convert offset to col/row. ; exit: D = binary row, E = binary col ; H = ascii col, L = ascii row <-- NOTE ORDER ; off2cr: mvi b,0 ;convert to row,col lxi d,-NCOLS ..1: dad d jrnc ..2 inr b ;row count++ jr ..1 ..2: lxi d,NCOLS dad d mov a,l ;col mov e,a ;binary col in E mov d,b ;binary row in D adi SPACE ; + bias mov h,a ;H = ascii col mov a,b ;row adi SPACE ; +bias mov l,a ;L = ascii row ret ; ;======================================== ; generic ; DOPASTE: ; ; Paste the last-cut region onto active screen at the current cursor. ; ; 1. Get previously-cut region from external routine ; 2. Send chars to screen, avoiding boundary overflows. ; ; 'savpag' not needed if terminal supports 'send cursor address' ;;-- call savpag ;get current screen, ;in order to find cursor mvi b,4 ;read 4 data bytes ..0: push b call jjbrdc pop b djnz ..0 ; mov b,a ;4th byte is # rows push b call crs2hl ;current cursor's row/col to hl pop b ; ; loop over rows ; ..rowlp:push b push h mov e,l ;e = col no. push d call stcrshl ;set cursor at h,l ..collp:call jjbrdc ;read char from cut-swp cpi CR jrz ..rend mov c,a ;save char pop d ;check for off screen mov a,e cpi NCOLS inr e push d ;row/col to stack cc sendc ;to conout, unless off edge jr ..collp ; ..rend: pop d ;clear row/col pop h pop b inr h ;bump row mov a,h ;check for off bottom of screen cpi NROWS jrnc ..xit djnz ..rowlp ..xit: xra a ret ; ;======================================== ; generic ; DOCUT: ; ; Cut rectangular region defined by keypresses. ; 1. Parse keypresses to move cursor and mark corners. ; Highlight region as cursor is moved. ; 2. Send the marked region, row-wise to external routine. ; Append CR after each row. ; ; Data structure is: ; size (word) ; # columns (byte) ; # rows (byte) ; row 1 ; CR ; row 2 ; CR ; .... ; .ifg DEBUG, [ ;for debugging, use cutbuf for output lxi h,cutbuf ;set ptr shld dbgptr ] ; xra a sta mrkcnt ;init for next time ; ; ; set ctcols = # cols, ctrows = # rows ; (assumes mark2 is SE of mark1) ; mark1 = .+1 mark1r = .+2 corners:lxi d,0000 ;binary col, then row of upperleft mark ; mark2 = .+1 mark2r = .+2 lxi h,0000 ;lower right mark mov a,h ;# rows = 1 + mark2row -mark1row inr a sub d mov h,a mov a,l ;# cols = 1 + mark2col -mark1col inr a sub e mov l,a shld ctcols ; ; cut rectangle [mark1...mark2] & copy to buffer ; append CR at end of each row ; xchg push h ;mark1 call wrpara ;write parameters pop h ;mark1 call rc2off ;convert to scr addr lda ctrows ;get # rows mov b,a ; ; write the cut region to external buffer ; ..rowlp:push b ;(+1 push h ;(+2 lxi d,buf ;fetch from screen buffer dad d ; ; write 1 row of cut region to external buffer ; lda ctcols mov b,a ;b = # cols ; ; buffered write B chars at hl, ascii only ; ..bwrt: push b push h mov a,m cpi DEL jrnc ..mksp cpi SPACE ;convert graphics jrnc ..1 ..mksp: mvi a,SPACE ; to space ..1: mov c,a call jjbwrch pop h pop b inx h djnz ..bwrt ; mvi c,CR ;append CR to each row call jjbwrch pop h ;(+1 pop b ;(+0 lxi d,NCOLS ;bump to next row dad d djnz ..rowlp ; and loop jmp jjbflu ;flush the write buffer ; ; ; write parameters: size, # cols, # rows to swp file ; de = ctcols ; wrpara: mov b,d ;# rows mvi d,0 inr e ;+1 for CR lxi h,0 ;accum. ..0: dad d djnz ..0 call bwhl ;write word ctcols = .+1 ctrows = .+2 lxi h,0000 ;now #cols, # rows ; bwhl: push h mov c,l call jjbwrch pop h mov c,h jmp jjbwrch ;======================================== ; generic ; LSTNBL: ; ; Find last non-blank line (1-24 only) in current scr buffer. ; Graphics and 8-bit characters are considered blanks. ; If B=0ff, save screen first. ; ; ret: H=row, L=col of last non-blank char in rows 1-24 ; inr b cz savpag lxi b,NROW24*100h + NCOLS ;b=# rows, c=# cols lxi d,buf lxi h,0 ..lp: ldax d cpi SPACE+1 ;don't count cntl chars or SPACE jrc ..1 cpi DEL ; or DEL or graphics 8-bit jrnc ..1 shld savrc ..1: inx d inr l dcr c jrnz ..lp ;loop over cols inr h mov l,c ;0 mvi c,NCOLS djnz ..lp ;loop over rows savrc = .+1 lxi h,0000 ;hl = last non-blank ret ;---------------------------------------- ; xring: mvi c,BELL ; ; send C to screen, exit Z, no CY ; sendc: mov a,c ; send A to screen, exit Z, no CY ; (this will scroll, however!) ; send: call jjouta xra a ;Z, no CY ret ;======================================== ; ; end of generic code ; ;======================================== ; specific ; ; bump row/col var that tracks actual cursor ; if mark not yet, send cntl char ; ret NZ if mark is set ; inrsnd: inr m ;next row/col call anymrk cz sendc ; ; nz if a mark has been set ; mrkcnt = .+1 anymrk: mvi a,00 ora a ret ; STMRKS: ; ; Move cursor and set marks. Return CY clear until exit. ; ; 1. move cursor, until: ; 2. 'X' = set 1st mark ; turn on hiliting, set mark, keep cursor at mark ; 3. move cursor right/down only ; 4. 'X' = set 2nd mark ; turn off hiliting, set 2nd mark ; exit CY (done) ; 5. cntl-C = CANCEL. ; turn off hilighting, set CY, exit ; ; lxi h,bincol ;load ptr to actual col/row cpi CANCEL jrz abort cpi LEFT jrz jjlef8 ;;jz golef8 cpi LEFT8 jjlef8: jz golef8 ; cpi UP jrz jjup8 ;;jz goup cpi UP8 jjup8: jz goup8 ; cpi RIGHT jrz jjrt8 ;;jz gort cpi RIGHT8 jjrt8: jz gort8 ; cpi DOWN jrz jjdn8 ;;jz godn cpi DOWN8 jjdn8: jz godn8 ; cpi CR jrz ..mrk ; ani 5fh ;convert rest to uppercase cpi HOME jrz gohome ; cpi MARK jrz ..mrk xra a ;no action ret ..mrk: lxi h,mrkcnt ;if no mark yet set mov a,m ora a mvi m,1 jrz mk1 ;..set mark1 call mk2 ;else set mark2 mrkxit: xra a sta mrkcnt ;init for next time stc ;CY = all done ret ; abort: call normal ;restore normal video jr mrkxit ;------------------------------------------- ; ; set 1st mark, turn on rev. video, don't move cursor ; mk1: call crs2hl shld mark1 shld mark2 shld curcol ;L->curcol,H->currow push h call reverse ;reverse video on ; ; Hilite the marked char. ; pop h ;mark1 mvi a,1 ;blink 1 char sta colct sta rowct call showro jmp sendbs ; ; set 2nd mark, restore normal video, set CY ; mk2: call normal ;dummy - restore normal video stc ;CY = all done ret ; ;====================== ; for H19, etc that use ESC sequences, ; change these routines to send ESC, then the byte. ; gohome: mvi c,HOMEC ;convert to video driver's cntl char call anymrk ;if mark set, jnz xring ;..error mov h,a ;set row=col=0 mov l,a shld bincol jjsndc: jmp sendc ; ; cursor left and cursor up: ; send if not at top or left margin ; golef8: mvi a,LEFT ;convert to 7-bit char ; goleft: ;hl = bincol ; zck: mov c,a ;save char in c call anymrk rnz cmp m ;ck col/row == 0 jz xring ;..error dcr m ;dcr col/row jr jjsndc ; goup8: mvi a,UP ;7-bit code goup: inx h ;binrow jr zck ;ck for top row and send ; ; cursor right and cursor down: ; if mark is not set, move cursor ; if mark is set, expand region and highlight ; keep track of cursor location in both cases ; don't move if it would scroll ; ; move cursor right ; gort8: mvi a,RIGHT ;convert to 7-bit code ; gort: mov c,a ;save in c mvi a,NCOLS-2 cmp m jcxrng: jc xring call inrsnd ;bump col & send if mrk not set rz ;rtn if mark not yet set ; ; hilite marked column ; gort1: lxi h,mark2 inr m ;bump 2nd mark-row lxi h,curcol ;bump col inr m mov l,m lda mark1r ;top row mov h,a ;h=row, l=col for col to hilite rowct = .+1 mvi b,00 ; ; loop over each row in cut region ; ..rlp: push b push h ;save binary row/col mvi a,1 ;display 1 char in each row call showhi pop h pop b inr h ;next row djnz ..rlp lxi h,colct ;prepare to bump col cnt & exit jr inrmbs ; ; move cursor down ; godn8: mvi a,DOWN ;7bit code godn: mov c,a ;save char inx h ;binrow mvi a,NROW24-2 ;ck if already on bottom row cmp m jc jcxrng call inrsnd ;bump row & send rz ;rtn if mark not yet set ; ; hilite marked row ; godn1: lxi h,mark2r ;row inr m ;bump 2nd mark-col lxi h,currow ;bump row inr m mov h,m lda mark1 ;left col mov l,a ;h=row, l=col for row to hilite call showro ;display 1 cut row lxi h,rowct ;bump row cnt inrmbs: inr m ; and exit sendbs: mvi a,BS ;back up cursor jmp send ; .remark \==== For Kaypro '84, use bios conout. if down: set cur at next row, left col send partial row rowcnt++ BS (back up 1) if right: set cur at toprow, next col send partial column colcnt++ ====\ ; ; enter: H = binary row, L= binary col ; showro: colct = .+1 mvi a,00 ; ; Fetch A chars at H=binary row, L=binary col from buffer. ; Put chars to screen, setting BLINK attribute. ; showhi: push psw push h call stcrshl ;set cursor at h,l pop h call rc2off lxi d,buf ;fetch from screen buffer dad d pop psw ;#chars mov b,a ..lp: mov a,m inx h call jjouta djnz ..lp ora a ret ; ;======================================== ; RETNCH: ; ; Return next screen char. ; ; enter: ; d = row, e = col ; b = FF ==> read screen ; c = FF ==> set bufptr ; exit: ; A = char, CY set if good ; DE -> row,col of next char, HL -> buf of next char ; CY clear if out of range ; xra a call stdump rnc mov a,m ;get char inx h ;bump bufptr ret ; ;======================================== ; .slist .list RETNAT: ; .ifg noatt, [ ; save space with a NUL FUNCTION xra a ;clear CY ret ] [ ; ;-------------------- ; Return next screen attribute. ; ; enter: ; d = row, e = col ; b = FF ==> read screen ; c = FF ==> set bufptr ; exit: ; A = attr, CY set if good ; DE -> row,col of next char, HL -> buf of next char ; CY clear if out of range ; mvi a,0ffh call stdump rnc ; ; fetch attr from buffer, advance hl every 2 ; mov a,m ;fetch attr byte from buffer bit 0,e jrnz ..podd ;DE here is CHAR addr, not attr +1 rar rar rar rar jr ..done ..podd: inx h ;bump hl ..done: ani 0fh ret ; ] .rlist ;-------------------- ; ; ret: NC if out of range ; stdump: sta attflg inr b jrnz ..0 push b push d call savpag pop d pop b ..0: inr c jrnz ..1 call conv rnc ;out of range ..1: inx d ;col++ mov a,e cpi NCOLS rc mvi e,0 ;col = 0 inr d ;row++ mov a,d cpi NROWS ret ;NC if out of range ; ; enter: d = row, e = col ; exit: hl -> buffer address, cy set ; de preserved ; CY clear if error (off screen) ; conv: mov a,d cpi NROWS jrnc cnvbad mov a,e cpi NCOLS jrnc cnvbad lxi h,buf mov a,d lxi b,NCOLS ;row*(cols per row) inr a ..lp: dcr a jrz ..2 dad b jr ..lp ..2: mvi d,0 ;+ col # dad d attflg = .+1 mvi a,00 ora a stc rz lxi b,SCRSIZ ;bump ptr to attributes dad b stc ret cnvbad: xra a ret ; ;======================================== ; SAVPAG: ; ; Save screen to buffer. ; xra a call iscr call crs2off ;find screen cursor shld bcursor push h push d call off2cr sded bincol ;save binary col/row pop d pop h ; ;-------------------- ; doscr: lxi b,SCRSIZ push b ;save count push d ;save addr ; ; first the characters ; ..0: call datadr ;set addr call vch ;r/w char inx d dcx b mov a,b ora c jrnz ..0 pop d ;addr pop b ;count ; ; now the attributes ; inx d ;attributes lead 1 byte ..2: call attadr call vat inx d dcx b mov a,b ora c jrnz ..2 ret ; ;======================================== ; RESPAG: ; ; Restore saved screen from buffer. ; ; First, set any attribute so we undo the effect of a clearscreen. ; This ensures that the restored screen, if it has ; attributes set, will get cleared by a clearscreen or ^X or whatever. ; ;put1att: call svcrsor lxi h,Zoneat call jjputs call cursbak ; mvi a,0ffh call iscr call gethome ;get current top of screen xchg ; to de call doscr ;put buffer to screen lhld bcursor ;and set the cursor ; ; Set cursor on screen by direct cursor addressing. ; enter: HL = cursor offset relative to 0000 ; stcrs: call off2cr ;convert from offset to ascii col/row stcoro: shld colrow ;put ascii col/row into string lxi h,Zcurs ;send set-cursor string jmp jjputs ; ; Set cursor on screen. ; enter: H=binary row, L = binary col ; stcrshl:call rc2off jr stcrs ; ;-------------------- ; ; CONVERSION ROUTINES ; ; Get current cursor position to H=binary row, L=binary col ; crs2hl: call crs2off ;get cursor by ...84 method call off2cr ;returns binary in de xchg ret ; ; convert H=binary row, L=binary col to hl= offset ; (hl = row*NCOLS + col) ; uses bc,de,hl ; rc2off: mov b,h ;b=row mov c,l ;c=col lxi h,0 inr b lxi d,NCOLS jr ..bot ..0: dad d ;rows*NCOLS ..bot: djnz ..0 dad b ;+ col ret ; ; get raw relative cursor to HL ; crs2off: call gethome ;get top of scr addr xchg ;keep in de call gcur ;get cursor addr ; mod800: ora a dsbc d mod8ck: rnc lxi d,800h dad d ret ; ;-------------------- ;initialize for screen ; iscr: sta putflg ;0=save, 0ff=restore lxi h,buf ;init char ptr jr shcptr ; ; ; read/write 1 char from video controller, to/from buffer ; status must already be checked and ok ; vch: lhld cptr lda putflg ora a jrnz vchput in vcdata ;get char from screen mov m,a ; & put into buffer inxcpt: inx h shcptr: shld cptr ret ; vchput: mov a,m ;fetch char from buffer call inxcpt out vcdata ; & put to screen ret ; ; read/write 1 attribute nybble to/from buffer ; stored: upper nybble = 00, lower nybble = 01, upper = 02,... ; cptr = .+ 1 vat: lxi h,0000 ;char ptr ; putflg = .+1 mvi a,00 ;NZ to restore(put) screen from buf ora a jrnz ..put ; ; get attribute from screen, store in buffer ; ..get: bit 0,e ;test for even col (de leads 1 ) jrz ..odd rld ;a->lo, lo->hi in vcdata ;get char from screen rrd ;a->hi, hi back to lo ret ..odd: rrd ;do low nybble, a->hi, hi->lo in vcdata rld jr inxcpt ;and bump ptr ; ; fetch attr from buffer, advance hl every 2, put to screen ; ..put: mov a,m ;fetch attr byte from buffer bit 0,e jrz ..podd ;DE leads 1 rar rar rar rar jr ..done ..podd: inx h ;bump hl shld cptr ..done: ani 0fh out vcdata ; & put to screen ret ; ; gethome:call svcrsor ;save cursor in bios rom mvi a,HOMEC ;home it call jjouta call gcur ; cursbak:push h lxi h,Zrestc ;restore bios copy of cursor addr call jjputs pop h ;ret home addr in hl ; ; v 1.4a FIX turborom v2.6. Restore cursor calls ldcursor ; w/o waiting for good status. The next controller read cause ; cursor-type byte to be written to screen. ;--- fixtrb: push h lxi d,SCRSIZ dad d ;point at 1st char in gap xchg call datadr ;set addr in vcdata ;read the controller to flush pop h ;the cursor-type byte. ;--- ret ; ; HL = raw cursor read from video controller ; uses h,l,a ; gcur: mvi a,curcmd out vccmd ;to get scrolling address call vwait ; may be unnecessary ?? in vcrdat mov h,a mvi a,curcmd+1 ;get low byte out vccmd call vwait in vcrdat mov l,a ret ; ;-------------------- ; ; wait, set DE attribute addr, stroke ; attadr: mov a,d ;qualify D for attribute space ani 07h ori 08h jr xadr1 ; ; wait, set DE data address, stroke ; datadr: mov a,d ;qualify DE for data space ani 07h xadr1: mov d,a xadr2: in vcstat ral jrnc xadr2 ; ;send DE to reg A, A+1, stroke & wait ; ;setrw: mvi a,hiadd out vccmd mov a,d out vcrdat mvi a,loadd out vccmd mov a,e out vcrdat mvi a,strcmd ;stroke chip out vccmd vwait: in vcstat ral jrnc vwait ret ;---------------------------------------- ; ; DATA AREA bincol: db 0 ;pair binrow: db 0 ; curcol: db 0 currow: db 0 ; Zrub: db BS,SPACE,BS+80H ;rub-out previous char ; ;**************************************** ; ; TERMINAL-SPECIFIC data ; svcrsor:lxi h,Zsavec ;save cursor & push state in bios rom jr jputs ; ; turn on normal video ; normal: lxi h,Znorm jputs: call jjputs ora a ;clr CY ret ; ; turn on reverse video ; reverse:lxi h,Zrev jr jputs ; ; Kaypro '84 video strings ; Zsavec: .ascis [1bh]'B6' ;save cursor location Zrestc: .ascis [1bh]'C6' ;restore it ; Zcurs: .ascii [1bh]'=' ;set cursor to colrow: db SPACE,SPACE ; row,col - modified in-line db NUL ;must have following NUL ; Zrev: .ascii [1bh]'B0' ; reverse video .ascis [1bh]'B1' ; with 1/2 intensity Znorm: .ascii [1bh]'C0' ; normal video .ascis [1bh]'C1' ; with full intensity ; ; !! this causes momentary flashing, can we do it elsewhere? ; Zoneat: .ascii [1bh]'B3 ' .ascis [1bh]'C3' ; .ifg DEBUG, [ Zclr: db 1Ah,NUL ;kaypro ] ; ; ;================================ ; ; JOTPAD BANNER - just 2 lines' worth ; ; 1. Clear screen. ; 2. Remind user of usage, to extent space is available. ; The editing keys are those supported by the terminal itself. ; Zbanner: db 1ah ;clear screen KAYPRO-SPECIFIC ; .ascii 'JOT: =exit, ^Paste' db CR,LF .ascii 'ESC E/ESC R=ins/del line' ; NO ROOM FOR THIS ! ; if turborom--> ;.ascii 'Cntl-A = insert char. Cntl-B = delete char. ' ; Zcrlf: db CR,LF+80h ; .slist .list codlen = .-start ;length of code .rlist ; ;++++++++++++++++++++++++++++++ .remark \== Debugging stragegy: Assemble screendriver at 100h. Load with Z80 debugger. Clear ram buffers. Set breakpoints as needed. Call these test routines and inspect buffers. ==\ .ifg DEBUG, [ dbg0 = . ; ; these emulate the external BGii routines ; using ram buffers for debugging ; bwrch: push h lhld dbgptr ;put to debug cut buffer mov m,c inx h shld dbgptr pop h ret ; bflush: ret ; ;bios display-a-string ; nul/8-bit terminated string at hl ; preserves bc,de,hl ; puts: push h ;save hl, outch save bc,de ..0: mov a,m rlc srlr a ;shift right logical (register) A inx h jrz ..1 push psw call outch pop psw jrnc ..0 ..1: pop h ret ; ; char in A to conout, preserve bc,de,hl ; outch: push b push d push h mov c,a call conout pop h pop d pop b ret ; ; Various routines for debugging in ram. ; TSTACK = 05000h ;test stack, above bank-switching tdump: lxi b,0ffffh ;fetch scr, set ptr lxi d,0 ;from row 0,col 0 call dmpchr ; tdump2: lxi b,0 call dmpchr ; tdump3: lxi d,100h + 0 lxi b,00ffh call dmpchr ; tdump4: lxi d,3000h ;out of range test lxi b,00ffh call dmpchr rst 7 ; ; clear: lxi h,Zclr ;clear screen call jjputs rst 7 ; flood: lxi h,Zflood ;write to screen call jjputs rst 7 Zflood: .ascii '=======TESTING=======' db 0 ; tsave: lxi sp,TSTACK ;save screen call savscr rst 7 trest: lxi sp,TSTACK ;restore screen call resscr rst 7 tmark: lxi sp,TSTACK ;set a mark call savscr call sttop ;so debugger doesn't scroll screen ..0: call conin call setmrk jnc ..0 ; rst 7 nop ; tcut: lxi h,cutbuf ;clear buffer mvi m,0 lxi d,cutbuf+1 lxi b,2*80h ldir call cutrg ;cut region call setbot ;put cursor out of way rst 7 ; place cursor nerar bottom or top ; setbot: lxi h,100h*(20h+18) +20h jr sttop1 sttop: lxi h,2020h sttop1: shld colrow lxi h,Zcurs ;send set-cursor string jmp jjputs ; dbgptr: dw 0 .slist .list dbglen = . - dbg0 .rlist ] ;++++++++++++++++++++++++++++++ ; .list ; SCREEN BUFFER STRUCTURE ; ; The rest of the 4K block is available ; for the screen image and other data. xbreq = 2 + NROWS*NCOLS + (NROWS*NCOLS)/2 ;required space ; .ifg DEBUG, [ ; ; put buffer on even byte ( for attributes) bstart = start + 800h ;make some room ] ; [ ; put buffer at end of 4K area, to just fit bstart = (start + 400h) + (3*400h-xbreq) short = start+codlen-bstart xfree = - short .ifg (short), [ .prntx '[07]Code overflows buffer!' ] ] ; ; addresses: ; bcursor = bstart ;cursor location in saved screen buf = bcursor+2 ;start of screen buffer ; ;buffer uses (25 lines x 80 chars) + 1/2 that for attributes ; bufend = buf + 25*80 + (25*80)/2 ; .ifg DEBUG, [ ; ; put cutbuffer in ram for debugging ; datcut = bstart+10h+3*400h cutbuf = datcut ] .xlist .remark \====================== This routine is needed to calculate locations of mark1, mark2 if cursor movements are not restricted to DOWN and RIGHT after 1st mark is set. Not used in current implementation. ; ; Code for minimum calc:: ; ; stored row, col ; set mark1(row,col) = min row,min col ; mark2(row,col) = max row,max col ; ctcols = #cols, ctrows = # rows ; corners:lxi d,mark1 lxi h,mark2 ldax d ;col 1 = min(col1,col2) mov b,m cmp b jrc ..1 ;cy if 1 < 2 mov m,a ;exchange mov a,b stax d ..1: inx h ;row 1... inx d ldax d ;row 1 = min(row1,row2) mov b,m cmp b jrc ..2 mov m,a mov a,b stax d ..2: ldax d ;row1 sub m ; - row2 cma ; gives (row2 - row1 - 1) inr a inr a sta ctrows dcx h dcx d ldax d sub m cma inr a inr a sta ctcols ret ; =========================\ .end jjcons