; *************************************************************** ; * * ; * ZRT-80 Video Terminal Driver Program * ; * Written By * ; * William White * ; * 437 Ogden Lane * ; * New Braunfels, Texas 78130 * ; * * ; *************************************************************** ; ; Copyright William White and Digital Research Computers, (c) 1983 ; title 'Terminal Driver Software' ; ; Created March 7, 1983 ; Last modified August 18, 1983 ; Version 1.01 ; ; This source file is assembled using the Digital Research MAC ; 8080 macro assembler with the Z80 macro library for Z-80 instructions ; ; Special thanks to Mark Kaufman and Wally Kulecz for help with the project. ; maclib z80 ; false equ 0 true equ not false ; ; Options: video monitor selection normal equ true ; normal selection of screen formats motorol equ false ; Motorola high resolution monitor ; ; ; system memory organiztion: ; orgn equ 00000h ; start of program eprom2 equ 01000h ; start of second EPROM ram equ 04000h ; start of scratchpad ram ramlen equ 00400h ; length of ram screen equ 0c000h ; screen refresh memory ; ; system i/o ports ; ; ins8250 receive equ 0 ; see ins8250 data sheet for details xmit equ 0 lobaud equ 0 inten equ 1 hibaud equ 1 intid equ 2 linctl equ 3 modctl equ 4 ; bit 3=chrgen, 2=led, 1=rts, 0=dtr linstat equ 5 modstat equ 6 ; bit 7=rlsd, 6=capslock, 5=dsr, 4=cts ; 6845S ports crtaddr equ 8 ; set the address of the port wanted crtdata equ 9 ; transfer data to/from port ; stat1 and stat2 define default values for options ; see definitions at dip1, dip2 respectively ; note that these ports are inverted i.e. a zero is on, a one is off stat1 equ 18h ; dip switch 2 stat2 equ 20h ; dip switch 3 kbd equ 10h ; keyboard input port beep equ 30h ; short duration bell equ 38h ; long duration ; ASCII equates bel equ 'G'-64 bs equ 'H'-64 ht equ 'I'-64 lf equ 'J'-64 cr equ 'M'-64 xon equ 'Q'-64 xoff equ 'S'-64 esc equ '['-64 space equ ' ' del equ 127 ; misc equates ; cursor size definitions cstart equ 0 ; start raster cend equ 7 ; end raster - 1 ; macro definitions ; mask will place hl in the rage c000 to ffff mask macro mov a,h ori 11000000b mov h,a endm ; mask8 will place hl in the range c000 to dfff mask8 macro mov a,h ori 11000000b ani 11011111b mov h,a endm ; maskh8: place hl in range e000 to ffff maskh8 macro mov a,h ori 11100000b mov h,a endm ; subhle will subtract: hl:=hl-e ; uses d subhle macro ana a mvi d,0 dsbc d endm ; addhle will add: hl:=hl+e ; uses d addhle macro mvi d,0 dad d endm ; turnon: turn a bit in memory on turnon macro ?A,?B lxi h,?A setb ?B,m endm ; turnoff: turn off a bit in memory turnoff macro ?A,?B lxi h,?A res ?B,m endm page ; ********************************* ; * * ; * initialization * ; * * ; ********************************* org orgn ; start of rom reset jmp startup ; copyright notice db 'Copyright 1983 Wm. White ' db 'Digital Research Comp' page ; ********************************* ; * * ; * interrupts * ; * * ; ********************************* ; the maskable interrupt (38h) is the ins8250 uart. ; it will interrupt on either received data or status line change if $>(orgn+38h) ; check for errors 'overrun error at 38h.' endif org orgn + 38h rxvisr push psw ; find cause of interrupt in intid ani 6 cpi 4 jrz rxint ; receiver interrupt ; modem status line has changed: ; copy dsr to rts output in modstat bit 5,a jrnz rtsnl call rtslow jr preti ; end routine ; *************************************************************** ; Non-maskable interrupt * if $>(orgn+66h) ; check for errors * 'Error at 66h.' ; * endif ; * org orgn+66h ; * ; * keyvisr push psw ; save registers * in kbd ; get keyboard character * sta kbuff ; save in buffer * mvi a,0ffh ; set flag * sta kflag ; * pop psw ; restore * retn ; return & restore int status * ; * ; *************************************************************** ; uart interrupt service routine continued: ; set rts high if x-on mode or computer is not waiting on terminal rtsnì in stat1 cma bit 6,a ; check for x-on control jrz rtsw call rtshi jr preti rtsw ldá dip3 bit a,5 cz rtshi jr preti ; receiver interrupt: get a character rxint in stat2 cma bit 5,a ; check for local in receive ; get chr from uart res a,7 ; rid of parity, no check! cz storx ; store the rx chr in the fifo ; pop & reti preti pop psw ei reti ; keyboard lookup table ; bit 7 is the alternate keyboard mode bit. ; bit 7 set on second byte sends ESC first ; ; these tables may also be used to recode keyboard codes. ktheath db '1','S'+80H ; function key 1 db '2','T'+80H ; 2 db '3','U'+80H ; 3 db '4','V'+80H ; 4 db '5','W'+80H ; 5 db '6','P'+80H ; blue db '7','Q'+80H ; red db '8','R'+80H ; gray klheath equ ($-ktheath)/2 ktadm db 0,0 ; empty table kladm equ ($-ktadm)/2 ktbee db '1','p'+80h db '2','q'+80h db '3','r'+80h db '4','s'+80h db '5','t'+80h db '6','u'+80h db '7','v'+80h db '8','w'+80h db '9','x'+80h db '0','y'+80h klbee equ ($-ktbee)/2 ktadds db 0,0 kladds equ ($-ktadds)/2 page ; ********************************* ; * * ; * initialization * ; * * ; ********************************* ; initialize all buffers, pointers, flags, and i/o startup lxi sp,stack di im1 ; clear buffer space in RAM lxi h,rambuff mvi b,buffsiz strtclr mvi m,0 inx h djnz strtclr ; initialize fifo's lxi h,rxfifo shld rxinp shld rxout lxi h,txfifo shld txinp shld txout ; setup the flags in dip1,2,3,4 in stat1 cma sta dip1 in stat2 cma sta dip2 mvi a,init3 sta dip3 mvi a,init4 sta dip4 ; initialize CRTC call crtcmod ; set the mode call cursmod ; set the cursor call statmod ; set the status line ; initialize UART call setbaud ; set the baud rate from dip1 mvi a,9 out inten ; enable int for rx & modstat mvi a,initmod sta modcopy ; copy of data sent to modem port out modctl ; set dtr high rst 7 ; execute interrupt routine once ; this reads input port & sets outputs ; Check for EPROM istalled in second ROM socket. lda eprom2 ; first byte must be a JMP instruction cpi 0c3h cz eprom2 ; execute the program now if there. ; ei ; let the receiver interrupt jmp main ; execute main program ; set baud rate ; take data from 4 bits of dip1 and setup 8250 setbaud lda dip1 ani 15 ; keep 4 bits rlc mov e,a mvi d,0 lxi h,baudtab ; baud rate divisor table dad d ; program 8250 mvi a,083h out linctl mov a,m out lobaud inx h mov a,m out hibaud ; set 2 stop bits for 110 baud or lower ani 04h ; bit 2 is on for these ori 3 ; 8 bits, no parity, normal mode out linctl ret ; table of baud rate divisors ; xtal = 2.4576 MHz baudtab dw 8 ; 19,200 dw 16 ; 9600 dw 21 ; 7200 dw 32 ; 4800 dw 43 ; 3600 dw 64 ; 2400 dw 77 ; 2000 dw 85 ; 1800 dw 128 ; 1200 dw 256 ; 600 dw 512 ; 300 dw 1024 ; 150 dw 1142 ; 134.5 dw 1396 ; 110 dw 2048 ; 75 dw 3072 ; 50 ; set rts high rtshi lda modcopy ori 6 jmp rtso ; set rts low rtslow lda modcopy ani 0f9h rtso sta modcopy out modctl ret page ; ********************************* ; * * ; * CRTC routines * ; * * ; ********************************* ; procedure crtcmod ; read mode from 3 bits of dip2 and setup the crtc accordingly ; clear the screen and set crtc cursor position crtcmod lda dip2 ani 111b ; lookup in table (16 byte entries) lxi h,crttabl rlc rlc rlc rlc mov e,a mvi d,0 dad d mov a,m ; get cpl sta cpl inx h mov a,m ; get lps sta lps inx h mov a,m ; get vsyn sta vsyn inx h mov a,m ; get scrsiz sta scrsiz inx h mov a,m sta scrsiz+1 inx h ; load up crtc registers mvi c,0 ; register counter mvi b,10 ; init 10 registers crt1 mov a,c ; get register number out crtaddr mov a,m ; get data out crtdata inx h inr c djnz crt1 call escreen call setcurs ret ; crttabl is a table of initalization values for the crt controller ; ; each 16 byte entry has: ; cpl,lps,vsyn,scrsiz,d0,d1,d2,d3,d4,d5,d6,d7,d8,d9,0 ; cpl is the number of characters / line ; lps is the number of lines / screen ; vsyn is the vertical sync position for status line display ; scrsiz the screen size in bytes ; where di is crtc port data ; ; Note: The board must have at least 1 memory chip for each ; 2048 characters on the screen. ; ; Xtal=20.000 MHz ; ; registers are: ; 0 horizontal total 5 vert total adj ; 1 horizontal displayed 6 vertical displayed ; 2 horiz sync pos 7 vert sync pos ; 3 sync width 8 interlace & skew ; 4 vertical total 9 maximum raster ; ; Other formats can be programmed: Refer to Hitachi data sheet on ; the HD6845S or the Motorola data sheet on the MC6845*1 to determine ; correct values for registers. The dot clock can typically be run up ; to about 25MHz without modification. The dot clock frequency can be ; changed without affecting any other circuitry on the board. ; crttabl ; 0 1 2 3 4 5 6 7 8 9 x ; 80 lines x 24 characters, 15748Hz horizontal, 60 Hz vertical, 10 rasters/line db 80,24,25 dw 1920 db 7eh,50h,61h,68h,19h,03h,18h,18h,50h,09h,0 ; 80 x 48, 15748, 60, 9 db 80,48,52 dw 3840 db 7eh,50h,61h,68h,39h,03h,30h,34h,53h,07h,0 ; 80 x 24 17544, 60, 11 db 80,24,25 dw 1920 db 71h,50h,5ah,68h,19h,06h,18h,18h,50h,0ah,0 ; 80 x 48, 18691, 60, 11 db 80,48,52 dw 3840 db 6ah,50h,55h,68h,37h,07h,30h,34h,53h,09h,0 ; 96 x 24, 15748, 60, 10 db 96,24,25 dw 2304 db 7eh,60h,67h,68h,19h,03h,18h,18h,50h,09h,0 ; 80 x 24, 15748, 50, 11 db 80,24,1ah dw 1920 db 7eh,50h,61h,68h,1bh,07h,18h,1ah,50h,0ah,0 if normal ; these two can be replaced by specials ; 80 x 48, 15748, 50, db 80,48,51 dw 3840 db 7eh,50h,61h,68h,38h,03h,30h,33h,53h,09h,0 ; 96 x 24, 15748, 50, 11 db 96,24,26 dw 2304 db 7eh,60h,67h,68h,1bh,07h,18h,19h,50h,0ah,0 endif if motorol ; SPECIAL MONITOR SETUP: ; ; crtc parameters for use with Motorola M4408-540 high resolution monitor: ; This monitor is a vertical page format monitor that allows operation with ; up to 66 lines of 96 characters with this terminal. This is the exact ; capacity of an 8-1/2 x 11 inch page on an elite typewriter. It is actually ; possible to run better than 80 lines but 66 seems more practical. ; ; This monitor has a nominal horizontal frequency of 30.5kHz and a vertical ; frequency of 60 Hz. The video bandwidth is 50MHz. ; ; In order to use this board with the monitor, the dot clock is run at ; 32 Mhz, (and slightly modified), the dot clock counter is replaced with ; a schottky chip (74S196). ; ; 96 x 33, 29000, 60, 15 db 96,33,35 dw 96*33 db 111,96,97,104,35,9,33,34,81,12,0 ; 96 x 66, 29000, 60, 15 db 96,66,70 dw 96*66 db 111,96,97,104,72,6,66,70,83,11,0 endif ; ; ; set display register ; turn on extra display line when status line is enabled ; change vertical sync position ; this helps center the display in the useable area of the monitor statmod mvi a,6 ; vertical displayed out crtaddr lda dip4 bit 0,a ; check for status lda lps jrz nostat inr a nostat out crtdata rz ; no status ; if status line enabled, then change vertical sync position mvi a,7 out crtaddr lda vsyn out crtdata ret ; set cursor mode ; use cursor enable,block cursor, blink bits in dip3, dip4 cursmod lda dip3 ; see if cursor is enabled bit 4,a mvi c,20h ; cursor disabled jrz cursmen ; cursor is enabled: check for blink/non-blink bit 1,a ; check for blink mvi c,0 ; no blink jrz cursmen mvi c,60h ; cursor blink ; find correct type of cursor cursmen lda dip4 bit 1,a mvi b,cstart ; top line for block cursor jrnz cursblk ; underscore cursor mvi b,cend ; single line cursblk mvi a,10 out crtaddr mov a,b ora c ; enable/disable out crtdata mvi a,11 out crtaddr mvi a,cend ; bottom out crtdata ret ; ********************************* ; * * ; * housekeeping routines for crt * ; * * ; ********************************* ; setcurs ; send the cursor position to the crt controller setcurs mvi a,15 out crtaddr lda cursor out crtdata mvi a,14 out crtaddr lda cursor+1 out crtdata ret ; sethome ; save new position of home and copy the status line. ; if status enabled, copy cpl bytes from home+scrsiz to newhome+scrsiz sethome mask ; put in proper range lda dip4 bit 0,a jrz sethno ; no status push h ; save new home lbcd scrsiz dad b mask8 xchg ; de=newhome+scrsiz lhld home dad b ; hl=home+scrsiz mask8 lbcd cpl mvi b,0 ldir ; copy status line pop h ; save new home sethno shld home ; mvi a,13 out crtaddr mov a,l ; get low(home) out crtdata mvi a,12 out crtaddr mov a,h ; get high(home) out crtdata ret page ; ********************************* ; * * ; * Main Program Loop * ; * * ; ********************************* main lxi h,main ; any routine called will return here push h call fetchrx ; get a character ; process the character: ; case ; chr=del do nothing ; chr<32 control character: lookup routine & exec ; chr>=32 printable character: write to screen cpi del rz ; do nothing cpi 32 jrc control ; control character ; it is a printing character call write ; put it on the screen jmp cinc ; increment cursor position ; control character: ; take the character and look for a match in the control code table ; for the protocol being used. ; CR, LF, HT are handled as special cases control cpi ht ; check for commonly used codes first jz ctab ; this improves the speed of execution cpi cr jz hcr cpi lf jz hlf lxi h,ctltab ; find correct table for emulation mode call select ; select a control table, lookup routine pchl ; execute the routine ; esc character received: ; take next character and lookup routine associated with it ; according to the selected protocol. escseq call fetchrx lxi h,esctab call select pchl ; ctltab is a table with 4 entries, one for each emulation mode ; terminals are: ; 0. Heathkit H-19 ; 1. Lear Seigler ADM-3 ; 2. Beehive ; 3. ADDS Regent 200 ctltab dw ctheath db 3 ; width db clheath ; length ; dw ctadm db 3 ; width db cladm ; length ; dw ctbee db 3 ; width db clbee ; length ; dw ctadds db 3 ; width db cladds ; length ; esctab dw etheath ; table db 3 ; width db elheath ; length ; dw etadm ; table db 3 ; width db eladm ; length ; dw etbee ; table db 3 ; width db elbee ; length ; dw etadds ; table db 3 ; width db eladds ; length ; ; key code lookup table keytab dw ktheath db 2,klheath dw ktadm db 2,kladm dw ktbee db 2,klbee dw ktadds db 2,kladds ; control code table for heath terminal ; note that cr,lf,ht are already taken care of ctheath db esc ; escape sequence dw escseq db bel ; ring bell dw ring db bs ; back-space dw cleft clheath equ ($-ctheath) / 3 ; escape codes for heath and adm terminal etadm etheath db '=' ; cursor addressing for adm3 dw caddr ; cursor functions db 'Y' ; cursor addressing for heath dw caddr db 'H' ; home cursor dw chome db 'C' ; cursor right, stop at right margin d÷ crighô db 'D' ; cursor left, stop at left margin dw cleft db 'B' ; cursor down, don't scroll dw cdown db 'A' ; cursor up, don't scroll dw cup db 'I' ; reverse line feed dw crlf db 'n' ; cursor position report dw crep db 'j' ; save cursor position dw csav db 'k' ; restore cursor position dw cresto ; edit and erase db 'E' ; erase screen dw escreen db 'b' ; erase start to cursor, inclusive dw ebegin db 'J' ; erase cursor to end, inclusive dw eend db 'l' ; erase line dw eline db 'o' ; erase left to cursor, inclusive dw eleft db 'K' ; erase cursor to right, inclusive dw eright db 'L' ; insert line dw insline db 'M' ; delete line dw delline db 'N' ; delete character dw delchr ; modes db '@' ; enter insert character mode dw inson db 'O' ; exit insert character mode dw insoff db 'p' ; enter inverse video mode dw invon db 'q' ; exit inverse video mode dw invoff db 'F' ; enter graphics mode dw gron db 'G' ; exit graphics mode dw groff db 'r' ; set baud rate dw setbrg db 'x' ; set mode -- takes one chr dw setmode db 'y' ; reset mode -- takes one chr dw resmode db '{' ; enable keyboard dw keyoff db '}' ; disable keyboard dw keyon db 'v' ; enable wraparound mode dw wrapon db 'w' ; disable wraparound mode dw wrapoff ; misc db 'z' ; reset to power on state dw reset db esc ; same as first escape dw escseq ; added features db 't' ; test routines dw testmod db 's' ; set screen format dw setcrtc db 'f' ; alternate character set dw alton db 'g' ; standard character set dw altoff elheath equ ($-etheath)/3 ; end of heath table eladm equ ($-etadm)/3 ; end of adm3 table ; adm-3 assignments ctadm db bs ; back-space dw cleft db bel ; right bell dw ring db 'K'-64 ; cursor up dw cup db 'L'-64 ; cursor right dw cright db 'N'-64 ; keyboard enable dw keyoff db 'Q'-64 ; keyboard disable dw keyon db 'Z'-64 ; erase screen dw escreen db '['-64 ; escape code dw escseq db '^'-64 dw chome cladm equ ($-ctadm)/3 ; Beehive terminal assignments: ; only those codes that are implemented are included. ; Many features on the Beehive terminals are not included. ctbee db bel ; ring bell dw ring db bs ; back-space dw cleft db esc ; escape code dw escseq clbee equ ($-ctbee)/3 etbee db '7' ; set baud rate dw setbrg db 'Q' ; insert mode on dw inson db '@' ; insert mode off dw insoff db 'A' ; cursor up dw cup db 'B' ; cursor down dw cdown db 'C' ; cursor right dw cright db 'D' ; cursor left dw cleft db 'E' ; erase screen dw escreen db 'F' ; cursor addressing dw caddr db 'G' ; read cursor posn dw cread db 'H' ; cursor home dw chome db 'J' ; erase to end dw eend db 'K' ; erase right dw eright db 'L' ; insert line dw insline db 'M' ; delete line dw delline db 'P' ; delete character dw delchr db 'R' ; graphics on dw gron db 'S' ; graphics off dw groff db 'V' ; reset terminal dw reset db 'Y' ; cursor addressing dw caddr db 'Z' ; toggle cursor on/off dw curstog db '\' ; report cursor position dw crep db 'b' ; keyboard enable dw keyoff db 'c' ; keyboard disable dw keyon db 'l' ; inverse video dw invon db 'm' ; normal video dw invoff elbee equ ($-etbee)/3 ; ADDS Regent 200 terminal assignments ctadds db bs ; back-space dw cleft db esc ; escape dw escseq db bel ; ring bell dw ring db 'A'-64 ; home cursor dw chome db 'B'-64 ; keyboard unlock dw keyoff db 'F'-64 ; cursor right dw cright db 'L'-64 ; erase screen dw escreen db 'U'-64 ; cursor left dw cleft db 'Y'-64 ; keyboard lock dw keyon cladds equ ($-ctadds)/3 etadds db 'E' ; delete character dw delchr db 'F' ; insert character dw hinschr db 'l' ; delete line dw delline db 'M' ; insert line dw insline db 'Y' ; cursor addressing dw caddr db 'k' ; erase to end dw eend db 'K' ; erase to right dw eright db 'Z' ; next chr is graphic dw graphic db 's' ; reset terminal dw reset db 'A' ; set baud rate dw setbaud eladds equ ($-ctadds)/3 page ; ********************************* ; * * ; * General Purpose Routines * ; * * ; ********************************* ; Search a table for an entry matching the accumulator ; HL is table start ; D is table length ; E is table width ; A is character to match ; return: ; A is character after match, or same character if no match ; HL is address of character after match ; c is set if no match found search mov c,a ; save chr srch1 cmp m ; check this entry jrz srch3 ; match ; no match: mov b,e ; width mov a,c ; get chr srch2 inx h ; advance e bytes djnz srch2 dcr d ; length-1 jrnz srch1 mov a,c stc ret ; match: srch3 inx h mov a,m ret ; Select a pair values for hl,de based on ; the emulation mode selected and table address in hl ; there exists a table at (hl) with 4 four byte entries ; lookup the address of the routine using search ; and return it in hl select push psw in stat2 ; its in bits 3,4 cma rrc ani 00001100b mov e,a mvi d,0 dad d ; hl now points to entry mov e,m inx h mov d,m inx h mov c,m inx h mov b,m xchg mov d,b mov e,c ; h,l,d,e have been loaded. pop psw ; search for the address call search jc noroutn ; no routine found: do noop inx h mov h,m ; get h mov l,a ; get l ret ; no carry noroutn lxi h,noop noop ret ; read keyboard character and put in fifos ; keybd ; ; there is a keyboard translation table for each terminal type. ; any entry in the table with bit 7 set will send an ESC char first ; ; get a keyboard character ; lookup translated value in table ; if capslock then map a-z to A-Z ; if bit 7 then send ESC ; send character ; ; check for available character lxi h,kflag bit 0,m ; check for flag rz ; check for keyboard lock lda dip3 bit 3,a rnz ; get a character mvi m,0 ; clear flag inx h ; goto buff mov b,m ; get chr mov a,b ; get chr with 8 bits res 7,b ; clear bit 7 on character ; lookup new value based on character and terminal type push b lxi h,keytab call select ; find new value for this terminal pop b jrc keycvt mov b,a ; save new character ; if capslock and lower case alphabetic then convert case keycvt in modstat bit 6,a ; check bit jrz keyfini ; no capslock ; then if chr >= 'a' and chr <= 'z' mov a,b ; get chr cpi 'a' jrc keyfini ; else do nothing cpi 'z'+1 jrnc keyfini ; then chr := chr - 32 sui 32 mov b,a keyfini ; ready to send the char: ; if printable and col=cpl-8 then ding bell mov a,b ; look at chr cpi ' ' jrc noding cpi 7fh jrnc noding lda cpl sui 8 lxi h,column cmp m cz ding noding ; if bit7 set then bit 7,b ; send ESC mvi a,esc cnz send ; send chr and 7fh mov a,b res 7,a send ; if local or local copy push psw in stat2 cma ani 01100000b jrz sendnlc ; then storx pop psw push psw call storx ; if not local sendnlc in stat2 cma ani 00100000b jrnz sendl ; then stotx pop psw call stotx ret ; ret sendl pop psw ret ; character fifo buffer routines: ; storx: save a received character ; take care of xon/xoff protocol storx push psw push h ; save character, advance pointer lhld rxinp mov m,a ; save character inr l ; no carry to h shld rxinp ; if not xoff sent lda dip3 bit 5,a jrnz srx ; then if full lda rxout ; pos of last chr sent sub l neg ; out-inp is number of chrs in buffer cpi 256 * 3/4 ; compare to 3/4 full jrnz srx ; do nothing ; then send xoff call sndxoff ; set xoffsent flag lxi h,dip3 setb 5,m ; return srx pop h pop psw ret ; fetchrx: fetch a received character ; any time the terinal is idle, this routine is executing ; take care of xon/xoff protocol ; check keyboard buffer for character ; transmit a character if tbe and chr is avail fetchrx push b push d push h ; transmit if possible frxagn call keybd ; handle the keyboard call transmt ; take care of transmissions ; check for received characters ; if char available lhld rxout lda rxinp cmp l jrz frxels ; nothing ; then get character mov b,m ; get chr ; advance pointer inr l shld rxout ; if xoff-sent lda dip3 bit 5,a jrz frxret ; then if buffer=1/4 lda rxinp sub l cpi 256 * 1/4 ; check for 1/4 buffer jrnz frxret ; then send xon call sndxon ; reset flag lxi h,dip3 res 5,m jr frxret ; else frxels ; setcurs call setcurs ; goto fetchrx jr frxagn ; return frxret mov a,b pop h pop d poð b ret ; xon/xoff routines: ; turn led on/off ; if x protocol is enabled, then ; stotx an xon/xoff ; else ; turn rts on/off ; ret sndxoff in stat1 cma bit 6,a jrz sxhrd ; set rts low ; send x-off mvi a,xoff call stotx lda modcopy jr sxled sxhrd lda modcopy res 1,a ; rts low sxled res 2,a ; led off sta modcopy out modctl ret sndxon in stat1 cma bit 6,a jrz sxnrts mvi a,xon call stotx lda modcopy jr sxnled sxnrts lda modcopy setb 1,a ; rts high sxnled setb 2,a ; led on sta modcopy out modctl ret ; stotx: save a character to be transmitted stotx push h lhld txinp mov m,a inr l res txfsiz,l ; keep in bounds shld txinp pop h ret ; fetchtx: fetch a character to be transmitted ; return carry if there is none fetchtx lhld txout mov a,m inr l res txfsiz,l ; keep in bounds shld txout ret ; see if a chr is present to transmit txchr lhld txout lda txinp cmp l ret ; z means none, nz means chr avail ; Transmit a character if buffer is empty and chr is available transmt call txchr rz ; nothing ; see if transmitter is ready to accept a character ; 1. must have clear to send ; 2. uart buffer must be empty in modstat bit 4,a ; check for cts rz in linstat ; buffer full? bit 5,a rz ; all systems are GO . . . call fetchtx ; get the chr to transmit ; process for parity res 7,a ; strip first mov b,a ; save ; check parity options ; 5 4 option ; ; 0 0 low ; 0 1 high ; 1 1 odd ; 1 0 even in stat1 rlc rlc rlc jrc xmpar ; add parity ; no parity: put in bit 7 and xmit ani 80h ora b jr xmout ; add parity xmpar ani 80h mov c,a mov a,b ana a jpe par xri 80h ; make parity eveb par xra c ; change if neccessary xmout out xmit ret page ; ********************************* ; * * ; * Erasing and Editing * ; * * ; ********************************* ; clear the status line clrstat lhld home lded scrsiz dad d lda cpl mov b,a clrs1 mvi m,space inx h djnz clrs1 ret ; check for status line: return z if yes, nz if no dumpst lda lps ; check for status line. lxi h,line cmp m ; is status line? ret ; erase de bytes from hl ; de >= 0 erase mov a,d ani 8191/256 ; 8k max mov d,a mask8 lda dip3 ; check for inverse video ani 80h adi space mov b,a ; write this chr ; write b into de bytes at hl mov a,d ; check for zero ora e rz inr d eras1 mov m,b ; erase one inx h dcr e jnz eras1 dcr d jnz eras1 ret ; erase the screen ; home := screen ; screen := spaces escreen call dumpst jz eline ; just erase status line lxi h,screen call sethome call chome ; home the cursor ; erase the screen now lhld home ; from lded scrsiz ; length jmp erase ; eline: erase line with cursor, leave cursor alone ; find start of line ; erase cpl bytes eline lhld cursor lded column subhle mask8 ; keep everything in bounds lded cpl mvi d,0 jmp erase ; ebegin: erase from home to cursor inclusive ; (cursor-home+1) bytes from home ebegin call dumpst ; dump if status line rz lhld cursor lded home ana a dsbc d inx h xchg lhld home jmp erase ; eend: erase from cursor to end of display inclusive ; (scrsiz-cursor+home) bytes from cursor eend call dumpst rz lhld scrsiz lded home dad d lded cursor ana a dsbc d xchg lhld cursor jmp erase ; eleft: erase from left of line to cursor inclusive ; col+1 bytes from (cursor-col) eleft lhld cursor lded column subhle mask8 lded column mvi d,0 inr e jmp erase ; eright: erase from cursor to right end of line inclusive ; (cpl-col) bytes from cursor eright lxi h,column lda cpl sub m mov e,a mvi d,0 lhld cursor jmp erase ; inschr: insert a character ; move col...cpl-2 to col+1...cpl-1 ; ie from cursor to cursor+1 with (cpl-col-1) bytes ; do not change character at col. ; hl=cursor+cpl-column-2; de=cursor+cpl-column-1; bc=cpl-col-1 inschr lxi h,column lda cpl sub m dcr a rz ; zero bytes mov c,a mvi b,0 lhld cursor lded cpl addhle lded column subhle dcx h maskh8 mov d,h mov e,l dcx h maskh8 lddr ret ; hinschr: insert a blank hinschr call inschr mvi a,space jmp write ; insline: insert line with cursor ; ccr ; move (scrsiz-cursor-cpl+home+1) from home+scrsiz-1-cpl to home+scrsiz-1 insline call dumpst rz call ccr lhld scrsiz lded home dad d lded cpl subhle lded cursor ana a dsbc d inx h mov a,h ani 8191/256 mov b,a mov c,l ; bc:=scrsiz+home-cursor-cpl+1 ora c ; check for zero jrz insl0 lhld scrsiz lded home dad d dcx h maskh8 push h lded cpl subhle maskh8 pop d lddr insl0 jmp eline ; delline: delete line with cursor, leave cursor at left, fill with spaces ; at bottom. ; ccr ; move (scrsiz-cursor-cpl+home+1) from cursor+cpl to cursor delline call dumpst rz call ccr lhld scrsiz lded home dad d lded cpl subhle lded cursor ana a dsbc d mov a,h ; bc<8k ani 8191/256 mov b,a mov c,l ; bc:=scrsiz+home-cursor-cpl ora c jrz dell0 ; nothing to move lhld cursor mask8 push h lded cpl addhle mask8 ; hl=cursor+cpl pop d ; de=cursor ldir ; erase bottom line ; cpl from home + scrsiz-cpl dell0 lhld home lded scrsiz dad d lded cpl subhle mask8 lded cpl mvi d,0 jmp erase ; delete character: ; move cpl-column-1 from cursor+1 to cursor delchr lxi h,column lda cpl sub m dcr a mov c,a mvi b,0 lhld cursor mask8 mov d,h mov e,l inx h ; check for zero bytes mov a,c ana a jrz delc0 ldir delc0 xchg mvi a,space call writehl ret page ; ********************************* ; * * ; * Cursor Functions * ; * * ; ********************************* write lhld cursor writehl push h ; write a character to the screen: ; if graphics then map 60-7f to 00-1f ; if inverse video then set b7 ; if insert mode then inschr ; store character lxi h,dip3 bit 2,m ; check for graphics bit jrz wrnog ; graphics mode: if a>=60, subtract 60h cpi 60h jc wrnog sui 60h ; check for inverse video wrnog bit 7,m jrz wrnoi ori 80h ; turn on inverse video wrnoi bit 6,m ; check for insert mode jrz wrnins push psw call inschr pop psw ; put character on the screen wrnins pop h mov m,a ret ; cinc: increment cursor position ; if col<>cpl-1 ; then col:=col+1 ; cursor := cursor + 1; exit ; else if wraparound ; then crlf ; exit cinc lxi h,column lda cpl dcr a cmp m jrz cincels ; then advance column, cursor, exit inr m lhld cursor inx h mask shld cursor ret ; if wraparound, do ccrlf cincels lda dip2 bit 7,a ; check wrap-around rz ; do nothing jmp ccrlf ; do crlf ; hlf: line feed with optional carriage return hlf call clf lda dip3 bit 0,a rz ; ccr: carriage return ; cursor := cursor-col ; col:=0 ccr lhld cursor lded column subhle ; hl := hl - e mask shld cursor xra a sta column ret ; hcr: carriage return with optional linefeed hcr call ccr lda dip1 bit 7,a rz ; clf: line feed and scroll if at bottom of screen ; ; cursor := cursor + cpl ; if line<>lps-1 ; then line := line+1 ; else home := home + cpl ; sethome ; eline clf call dumpst rz lhld cursor ; advance cursor lded cpl addhle mask shld cursor ; check for bottom of screen lxi h,line lda lps cmp m ; check for status line rz ; dont do nothing dcr a cmp m jrz clfe ; else scroll ; just move down one line inr m ; incr line ret ; else scroll clfe lhld home lded cpl addhle call sethome jmp eline ; erase line ; crlf: reverse line feed ; cursor := cursor - cpl ; if line<>0 ; then line := line - 1; ; else home := home - cpl ; sethome ; eline crlf call dumpst rz lhld cursor lded cpl subhle mask shld cursor lxi h,line xra a cmp m jrz crlfels ; else scroll up ; dcr m ; dcr line ret ; scroll up: crlfels lhld home lded cpl subhle call sethome jmp eline ; erase & return ; ccrlf ; cr ; lf ccrlf call ccr jmp clf ; cleft ; if col <> 0 ; then cdec ; ; cdec: ; if col <> 0 ; then col := col - 1 ; cursor := cursor - 1; cleft cdec lxi h,column xra a cmp m rz ; dec col & cursor dcr m lhld cursor dcx h mask shld cursor ret ; cright ; if col+1 <> cpl ; then cinc cright lxi h,column lda cpl dcr a cmp m rz jmp cinc ; cup ; if line <> 0 ; then rlf cup lda line ana a rz jmp crlf ; cdown ; if line+1 <> lps ; then clf cdown lxi h,line lda lps dcr a cmp m rz jmp clf ; horizontal tab: ; move cursor to a column that is a multiple of 8 ctab lbcd column ; find old location push b call cinc pop b lda column cmp c rz ; quit if nothing happened ani 7 jrnz ctab ret ; cursor home ; cursor:=home ; line:=0 ; col:=0 ; chome lhld home shld cursor xra a sta line sta column ret ; csav: save cursor position for later recall csav lda column sta stoc lda line sta stol ret ; cresto: restore cursor position cresto lbcd stoc ; get c,l jmp setxy ; caddr: cursor addressing ; fetch a line, column caddr call fetchrx sui space push psw call fetchrx sui space mov c,a pop psw mov b,a ; setxy: set the cursor position given b=line, c=column ; cursor := home + cpl*line + column ; if line >= lps then line=statusline setxy lda cpl cmp c ; check column validity jrnc setxok dcr a mov c,a setxok ; check bounds of line specified lda lps cmp b jrnc setyok mov b,a ; make b=lps setyok mov a,c sta column mov a,b sta line ; calculate new cursor position mvi h,0 mov l,c ; hl:=column lded home dad d ; hl=column+home ana a jrz xyline0 lded cpl mvi d,0 setxy1 dad d djnz setxy1 xyline0 mask shld cursor ret ; report cursor address crep mvi a,esc call send mvi a,'Y' call send lda line adi space call send lda column adi space call send ret ; read cursor character cread lhld cursor mov a,m jmp send ; graphic character display graphic call fetchrx call write jmp cinc page ; ********************************* ; * * ; * Configuration * ; * * ; ********************************* ; setcrtc: set the crtc mode setcrtc call fetchrx ; get mode: A thru H sui 'A' rc ani 7 mov b,a lxi h,dip2 mov a,m ani 11111000b ora b mov m,a call statoff ; turn off the status line jmp crtcmod ; setup crtc ; setup the baud rate generator setbrg call fetchrx ; get a character sui '@' ; make binary rc ; bad ani 15 ; save only 4 bits mov b,a lxi h,dip1 mov a,m ani 0f0h ; rid of rate ora b ; put in rate mov m,a ; save new dip1 call setbaud ; make new rate ret ; set mode: turn on or off certain flags setmode call fetchrx lxi h,modton ; mode table mvi d,modtonl ; length jmp goaway ; reset mode: resmode call fetchrx lxi h,modtoff ; off mode table mvi d,modtofl jmp goaway ; test routines: ; 1=print all characters on screen (including ctl & esc) ; 2=fill screen with test pattern ; 3=fill screen with character ; 4=modify crtc register testmod call fetchrx lxi h,testtab mvi d,testlen jmp goaway testtab db '1' ; display EVERY character received dw tstprt ; ( including control characters) db '2' ; fill screen with test pattern dw tstfill db '3' ; fill screen with character dw tstfilc db '4' ; send a value to a crtc port dw tstcrtc testlen equ ($-testtab)/3 ; lookup routine and execute goaway mvi e,3 call search rc ; not found. inx h mov h,m mov l,a pchl ; mode tables modton db '0' ; blinking cursor (default) dw blnkon db '1' ; status line on dw staton db '2' ; bell off dw beloff db '4' ; block mode cursor (default) dw blkon db '5' ; no cursor dw cursoff db '8' ; auto line-feed dw alfon db '9' ; auto carriage-return dw acron modtonl equ ($-modton)/3 modtoff db '0' ; no blinking cursor dw blnkoff db '1' ; no status line (default) dw statoff db '2' ; bell works (default) dw belon db '4' ; underscore cursor dw blkoff db '5' ; cursor enable (default) dw curson db '8' ; auto lf off (default) dw alfoff db '9' ; auto cr off (default) dw acroff modtofl equ ($-modtoff)/3 ; modes on and off: inson turnon dip3,6 ; insert mode ret insoff turnoff dip3,6 ret invon turnon dip3,7 ; inverted video ret invoff turnoff dip3,7 ret gron turnon dip3,2 ; graphics ret groff turnoff dip3,2 ret keyon turnon dip3,3 ; keyboard lock on ret keyoff turnoff dip3,3 ; keyboard lock off ret wrapon turnon dip2,7 ; wraparound mode ret wrapoff turnoff dip2,7 ret alfon turnon dip1,7 ; auto line-feed ret alfoff turnoff dip1,7 ret acron turnon dip3,0 ; auto carriage-return ret acroff turnoff dip3,0 ret belon turnon dip4,2 ; bell enable ret beloff turnoff dip4,2 ret alton turnon modcopy,3 ; alternate chr font lda modcopy out modctl ret altoff turnoff modcopy,3 lda modcopy out modctl ret blnkon turnon dip3,1 ; blinking cursor jmp cursmod blnkoff turnoff dip3,1 jmp cursmod blkon turnon dip4,1 ; block mode cursor jmp cursmod blkoff turnoff dip4,1 jmp cursmod curson turnon dip3,4 ; cursor enable jmp cursmod cursoff turnoff dip3,4 jmp cursmod curstog lxi h,dip3 ; toggle cursor enable mvi a,00010000b xra m mov m,a jmp cursmod staton call clrstat ; status line enable turnon dip4,0 jmp statmod statoff turnoff dip4,0 jmp statmod ; test routines: ; print all characters ; note: the only way to exit this mode is to reset the terminal tstprt call wrapon ; turn on wraparound tstprt1 call fetchrx call write call cinc jr tstprt1 ; fill screen with garbage tstfill lxi h,screen lxi b,8192 tstf1 mov m,l dcx b inx h mov a,b ora c jrnz tstf1 ret ; fill screen with character tstfilc call fetchrx mov e,a lxi h,screen lxi b,8192 tstfc1 mov m,e inx h dcx b mov a,b ora c jrnz tstfc1 ret ; tstcrtc: send data to the crt controller ; ESC t 4 aa dd ; where aa is the port address in the crtc (hex) ; dd is the data to send the crtc (hex) ; if aa=11H then set lps ; if aa=12H then set cpl ; tstcrtc call hexbyte ; get a byte (address) push psw call hexbyte ; get a byte (data) mov b,a ; save data pop psw ; get addr cpi 17 jrz setlps jrnc setcpl out crtaddr mov a,b out crtdata ret setcpl mov a,b sta cpl jmp setsiz setlps mov a,b sta lps ; set screen size: scrsiz := cpl*lps setsiz lda cpl mov b,a lded lps mvi d,0 lxi h,0 multlp dad d djnz multlp shld scrsiz ret ; hexbyte: get a byte & return in a hexbyte call hexnib rlc rlc rlc rlc ani 11110000b mov c,a push b call hexnib pop b ora c ret ; hexnib: get a nibble in hex ; 0000 = '0' ; 0001 = '1' ; ... ; 1001 = '9' ; 1010 = ':' ; 1011 = ';' ; 1100 = '<' ; 1101 = '=' ; 1110 = '>' ; 1111 = '?' hexnib call fetchrx ani 0fh ret page ; ********************************* ; * * ; * Misc * ; * * ; ********************************* ; ring bell ring lda dip4 bit 2,a rz ; bell disabled out bell ret ; ding bell (short duration) ding lda dip4 bit 2,a rz ; bell off out beep ret page ; ********************************* ; * * ; * RAM buffers * ; * * ; ********************************* org ram ; buffers rxfifo ds 256 ; 256 byte fifo for receive txfifo ds 16 ; 16 byte fifo for transmit txfsiz equ 4 ; 2**4 bytes ; pointers, etc rambuff equ $ ; start of flags and buffers, etc rxinp ds 2 ; points to rxfifo store location rxout ds 2 ; points to rxfifo fetch location txinp ds 2 ; points to txfifo store location txout ds 2 ; points to txfifo fetch location cursor ds 2 ; absolute cursor position in memory home ds 2 ; absolute position of first chr on screen scrsiz ds 2 ; screen size vsyn ds 1 ; vertical sync position for status line ena cpl ds 1 ; number of columns per line lps ds 1 ; number of lines per screen column ds 1 ; current column line ds 1 ; current line stoc ds 1 ; saved column stol ds 1 ; saved line ; dip1 and dip2 are ram copies of the dip switch positions at power up. dip1 ds 1 ; bit init function ; 0123 buad rate ; 45 parity ; 6 x-ctl or hardware ; 7 auto-lf dip2 ds 1 ; 012 screen format ; 34 emulation mode ; 5 local ; 6 local copy ; 7 wrap around ; NOTE: dip 3 and 4 are hypothetical only. (just used as software flags) dip3 ds 1 ; various flags ; 0 0 auto-cr ; 1 1 cursor blink ; 2 0 graphics ; 3 0 keyboard lock ; 4 1 cursor enabled ; 5 0 x-off sent ; 6 0 insert mode ; 7 0 inverse video init3 equ 00010010b ; initial value for dip3 dip4 ds 1 ; more flags ; 0 0 status line enabled ; 1 1 block cursor ; 2 1 bell enable init4 equ 110b ; initial value for dip4 modcopy ds 1 ; data sent to uart output port initmod equ 0001b ; initial data sent to modem control port ; 0 1 dtr ; 1 0 rts ; 2 0 led ; 3 0 chrgen (select font) ;keyboard buffer and flag: kflag ds 1 ; zero ==> empty kbuff ds 1 ; keyboard character buffsiz equ $-rambuff ; stack space: stksize equ ram+ramlen-$ ds stksize stack equ $ end