title Morrow Terminal Board Rom (6_Feb_1984) ;sbttl 'september 1983 david block, portions by jim kearney' ; ; control program for morrow terminal ; copyright 1984 ; morrow designs, inc. ; san leandro, ca. ; ; written by david block and jim kearney (september 1983) ; ;---------------------------------------------------------------------- ; revision information ;--------------------- ; ; rev 1.4 dec 13,1983: david block ; 1) added esc,+, and esc,* as clear screen commands ; 2) removed keyboard lock command ; 3) fixed translation tables for foreign keyboards ; 4) changed method of determining if 6845 or 6545 ; ; rev 1.5 feb 6,1984: david block ; 1) modified for new keyboard ; 2) fixed xlation code ; ; rev 1.6 mar 8,1984 giora bar-hai ; 1) changed f10 codes to 50h,51h,52h ; 2) fixed tab sub. ; ; rev 2.1 feb 24,1984 giora bar-hai ; 1) change attribute address from 0400h to 0c00h (for mdt 70) ; 2) change f10 code to 50h,51h,52h ; ; rev 2.2 mar 8,1984 giora bar-hai ; 1) fixed tab sub. ; ; rev 2.3 mar 22,1984 giora bar-hai ; 1) change f10,fa,fb,fc,fd codes ; ; rev 3.0 apr 25,1984 giora bar-hai ; 1) changed attribute ram address to 0800h ; 2) modified for the new attributes (one attribute info. on each byte) ; ; rev 3.1 june 4,1984 giora bar-hai ; 1) add txa instruction in masksc sub. (vb.asm) to solve fd problem ; ; rev 3.2 june 26,1984 marc bernstein ; 1) added esc-s to save bottom 2 lines of screen into ram ; 2) esc-p to retrieve the bottom 2 lines and put them back on screen ; 3) added ^-no scroll to place uart interrupt ; 4) keyboard input is checked for during sequence of bells from host page ;---------------------------------------------------------------------- ; equates ;-------- ; ram equ 0000 cram equ 2000:h aram equ 0800:h baud equ 0A000:h uart1 equ 6000:h s1stat equ uart1+1 s1data equ uart1 uart2 equ 8000:h s2stat equ uart2+1 s2data equ uart2 crtc equ 5f00:h rom equ 0F000:h inbuf equ 0200:h inbuf2 equ 0300:h sndbuf equ 0180:h dipsw12 equ 0A001:h dipsw11 equ 0A002:h dipsw2 equ 0C000:h chrline equ 06c0:h attline equ 0760:h ;kbrd commands sendid equ 7F:h ; send kbrd id beep equ 7E:h ; ring bell clckon equ 7D:h ; key click on clckoff equ 7C:h ; key click off capson equ 7B:h ; turn caps light on capsoff equ 7A:h ; turn caps light off auton equ 79:h ; auto repeat on autoff equ 78:h ; auto repeat off lockon equ 77:h ; keyboard lock light on lockoff equ 76:h ; keyboard lock light off oflnon equ 75:h ; off line light on oflnoff equ 74:h ; off line light off ;key codes from kbrd capskey equ 8A:h ; caps lock key code spcbar equ 10001100:b ; space bar noscrol equ 10000111:b ; no-scroll key ctlnscr equ 10100111:b ; ctrl no scroll key access equ 10011111:b ; f1-f10 function lead in code break equ 10001001:b ; break key tabkey equ 10001011:b ; tab zero equ 10010000:b ; numeric kpad zero key comma equ 10011101:b ; numeric kpad comma key ;special ascii key codes ctrls equ 13:h ; control s - sent for x-off by no-scroll ctrlq equ 11:h ; control q - sent for x-on by no-scroll ctrlc equ 03:h ; control c - sent when break pressed ctrli equ 09:h ; control i - sent when tab pressed keymask equ 10011111:b ; used to mask off shift and ctrl bits morld equ 1C:h ; morrow function key lead in telld equ 01:h ; televideo type function key lead in page ;---------------------------------------------------------------------- ; variable data ;-------------- ; org ram buffull:ds 1 colmn: ds 1 ; cursor horizontal 0..79 row: ds 1 ; cursor vertical 0..23 nseq: ds 1 ; code sequence receiving if >0 send: ds 1 ; code sequence sending if >0 sqnc: ds 8 ; input code sequence storage escrcvd:ds 1 ; used when in monitor mode to indicate that escape rcv'd brkhit: ds 1 ; used to indicate that the break key was hit xonoff: ds 1 ; used to determine whether to send x-on, or x-off lb: ds 2 ; line base pointer ab: ds 2 ; line base in attribute pointer scbase: ds 2 ; screen base offset (0..2047) lb2: ds 2 ab2: ds 2 chars: ds 2 ; source for character moves chard: ds 2 ; destination for character moves tmprow: ds 1 tmpclmn:ds 1 newab: ds 2 newab2: ds 2 tempatt:ds 1 transfr:ds 2 attrib: ds 1 ; current attribute setting monitor:ds 1 ; if non-zero, display control chars graphmd:ds 1 ; if graphics mode, set to non-zero lockmd: ds 1 ; set non zero for kbrd lock nmiok: ds 1 ; must be $a5 for nmi to work temp: ds 1 ; zero page temp. temp2: ds 1 insp: ds 2 ; start of buffer for input inep: ds 2 ; end of buffer for input outsp: ds 1 ; start of output buffer outep: ds 1 ; end of output buffer keysp: ds 1 ; start of keyboard buffer keyep: ds 1 ; end of keyboard buffer dcurtyp:ds 1 ; default cursor type definv: ds 1 ; 0 => normal video screen, 1 => inverse video keyclck:ds 1 ; 0 => key click enabled number: ds 2 ; numeric buffer clrchar:ds 1 ; character to clear screen to. normally, ascii space bdreg: ds 1 ; baud register contents dbounce:ds 1 ; dip sw debounce counter newdip: ds 1 ; set to new dip value when change detected swdif: ds 1 ; if change in dip detected, then this = 0FF:h dip1: ds 1 ; dip switch 1 storage tempdip:ds 1 uartcmd:ds 1 ; last command instruction to uart caps: ds 1 ; caps lock flag =1 => shift alpha to caps kpad: ds 1 ; kpad mode 0 => normal, 0FF:h => application code: ds 2 ; jump location after code sequence rcvd keybuf: ds 16 ; keyboard buffer for incoming keys parstat:ds 1 ; status of parity - 1 => disabled bit8: ds 1 ; if parity off, this sets what 8th bit should be foreign:ds 1 ; corresponds to foreign character mode 0 => us numxlto:ds 1 ; number of codes that need xlation from kbrd numxlti:ds 1 ; number of codes that need xlation from host ; pointers to translate tables. initialized by setxlt routine xlt1: ds 2 ; search list for key codes xlt2: ds 2 ; replace list for key codes xlt3: ds 2 ; search list for input characters xlt4: ds 2 ; replace list for input characters partial:ds 1 ; used to store partials of keyboard input fncld: ds 1 ; flag indicating if f1-f10 lead-in rcv'd fncntyp:ds 1 ; type of function key sequence 0 => morrow mode mesg: ds 2 ; pointer to message to put on screen timecnt:ds 3 ; used for keeping track of the number of times through ; the timeout loop, for screen saver disupdt:ds 1 ; flag to indicate that a character has been rcvd, and that ; the screen should be turned back on disoff: ds 1 ; flag indicating the status of the screen 0 => screen on timen: ds 1 ; flag indicating that screen saver is enabled 0 => enabled page ;---------------------------------------------------------------------- ; the code ;--------- ; org rom null: rti ; null restart vector start: sei ; disable interrupts lda #0 ; disable nmi handling sta nmiok sta baud ; put kbrd in quiescent state sta bdreg cld ldx #$7f ; init stack txs clrram: sta ram,x ; clear z page dex bpl clrram lda #0FF:h ; disable keyboard buffer until init done sta lockmd ldx #16 ; clear bit 6 of status reg on 6545 stx crtc lda crtc+1 ; by reading lpen register lda crtc ; read crtc status register and #01000000:b cmp #00000000:b ; see if 6545 bne init68 ; if not 6545, then init as 6845 init: ldx #15 ; init crtc (6545) inilp1: stx crtc lda setup65,x sta crtc+1 dex bpl inilp1 jmp warmtst init68: ldx #15 ; init crtc (6845) inilp2: stx crtc lda setup68,x sta crtc+1 dex bpl inilp2 warmtst:lda #' ' ; set to clear screen to spaces sta clrchar jsr clrscr ; clear screen jsr slftst ; test for kbrd, and test ram ; re-init after dip switch change starts here warm: jsr getsw ; get dip switch setting jsr iniuart ; init baud port and usart jsr initbuf ; fill in and out buffers with 0ffh lda #2 ; init pointers for input buffer sta inep+1 sta insp+1 jsr setxlt ; set up pointers for xlation lda #0 ; set function key sequence type ldy dip1 ; depends on switch 8 of dip switch bmi morrow ; if 1, then morrow function sequence lda #0FF:h ; else, set for televideo lead in morrow: sta fncntyp ; set function type lda #0 ; clear escrcvd flag (used in monitor mode) sta escrcvd ; initialize attributes to [all off] jsr invoff ; set inverse video mode lda #' ' ; set to clear to spaces sta clrchar jsr clrscr ; clear the screen jsr setcur ; put cursor on screen lda #2 ; set default attribute for bright/dim sta definv lda #0 ; set default cursor sta dcurtyp jsr curst2 ; set cursor type to what's in a reg cli lda #clckon ; turn on key click jsr kbrdout lda #capsoff ; turn on caps lock light jsr kbrdout lda #auton ; turn on auto repeat jsr kbrdout lda #lockoff ; turn off kbrd lock led jsr kbrdout lda #oflnoff ; turn off off line led jsr kbrdout lda #beep ; beep!! jsr kbrdout ldy #0 i1: lda #20:h ; put spaces in ram where bottom 2 lines sta chrline,y ; are stored lda #2 ; put normal attribute in ram sta attline,y iny cpy #160 bne i1 lda #0 ; turn keyboard buffer on now sta lockmd lda #0A5:h sta nmiok cli ; enable usart interrupts page ;---------------------------------------------------------------------- ; the main loop ;-------------- ; main: jsr sendc ; send a character if uart rdy, and ; send buffer has a char to send jsr process ; if input characters pending, process jsr process jsr process jsr process jsr kyhndlr ; if keyboard input pending, handle a key jsr chkdip ; if dip switch changed, timeout, then re-init jsr savscrn ; update screen saver timeout jmp main ; start again ;---------------------------------------------------------------------- ; send a character ;----------------- ; sendc: lda s1stat ; get status of uart and #00000001:b ; check if txrdy is true beq notrdy ; jump if uart is not ready to xmit jsr sndrem ; else, try to get a char from send buffer cmp #0FF:h beq notrdy ; if no character, then not ready ldx parstat ; check status of parity (on/off) bne parok ; if non-zero, then parity is generated ora #10000000:b ; assume mark for eight bit ldx bit8 ; check whether bit 8 is mark or space beq parok ; if mark, then branch and #7F:h ; else, clear msb parok: sta s1data ; else, xmit the character notrdy: rts page ;---------------------------------------------------------------------- ; process pending input characters ;--------------------------------- ; process:lda buffull beq notful lda #beep jsr kbrdout lda #0 sta buffull notful: jsr inrem ; see if any characters pending cmp #0FF:h beq noinput ; if no chars, then no input ldx #0FF:h stx disupdt ; set screen update flag jmp outc ; else, handle the char noinput equ $ nokey: rts ;---------------------------------------------------------------------- ; handle pending keyboard input ;------------------------------ ; kyhndlr:ldx keyep ; see if key buffer empty cpx keysp beq nokey ; if start of buffer = end, then no keys to process lda #0FF:h ; else, set to turn reset timeout counter sta disupdt jsr keyrem ; remove a key from the buffer ldx disoff ; see if display off bne nokey ; if screen is on then keep the character tax ; save the key bmi notalfa ; branch if not ascii alpha char jsr xltout ; translate for foreign jmp sndins ; and send the character notalfa:lda fncld ; if in lead in, then not caps bne notcaps ; so jump txa and #keymask ; mask out shift and control bits cmp #capskey ; see if caps lock key bne notcaps ; if not caps lock, then branch ldx #capson ; assume caps lock to be turned on lda caps ; see what current state of caps lock is eor #0FF:h ; toggle it sta caps bne sndcaps ; if caps lock being turned on, send caps lock ldx #capsoff ; else, prepare to turn off caps lock sndcaps:txa jmp kbrdout ; send the proper code for caps lock on/off notcaps:txa ; get back the character ldx fncld ; see if function key lead in rcv'd beq chkaccs ; if not, then see if this is it jmp fnum ; else, this is an fn key, so send code chkaccs:cmp #access ; see if this is the lead in code for fn keys bne notldin ; if not, then branch lda #0FF:h ; else, set flag to indicate that next key..... sta fncld ; .....is a fn key rts notcscr:tax ; save the character again and #keymask ; mask out shift and control cmp #spcbar ; see if space bar bne notspc ; if not space bar, branch lda #' ' ; if spacebar, then send ascii space jmp sndins notspc: cmp #noscrol ; see if no scroll key bne notscrl ; if not no scroll, then branch ldx xonoff ; check whether to send x-on or x-off beq sndxoff ; if 0, then send x-off inc xonoff ; set flag to send x-off next time through lda #ctrlq ; send x-on jmp sndins sndxoff:dec xonoff ; set flag to send x-on next time through lda #ctrls ; else, send a control s to stop scrolling jmp sndins notldin:cmp #ctlnscr ; check for control no scroll bne notcscr lda uartcmd ; issue break command ora #8 sta s1stat ldy #100 xx: ldx #255 jsr kdly ; delay 2.6 milliseconds dey ; do it 100 times for 260 ms delay bne xx lda uartcmd ; reset uart with original command sta s1stat rts notscrl:cmp #break ; see if break key bne notbrk ; branch if not lda #ctrlc ; else, send a control c to host jsr sndins lda #0FF:h ; set brkhit flag to prevent more than 1 ^c sta brkhit rts notbrk: cmp #tabkey ; see if tab key bne nottab ; if not, branch txa ; else, see what we need to send cmp #tabkey ; see if shift or ctrl tab bne fnctn ; jump if shift or control tab lda #ctrli ; else, send a tab jmp sndins fnctn: txa ; get back character jmp fncnout ; and send the function code sequence nottab: cmp #zero ; see if kpad zero key bcc fnctn ; branch if not krom kpad cmp #comma+1 ; check other range of kpad bcs fnctn ; branch if not from kpad lda kpad ; see if kpad applications mode bne fnctn ; branch if kpad applications mode txa ; else, get back character and convert to ascii and #00011111:b ; ignore all other bits ora #00100000:b ; convert it to numeric cmp #':' ; see if numeric bcc nmber ; branch if it is cmp #3A:h ; else, see if it's the period bne notper ; if not, branch lda #"." ; else, send a period nmber: jmp sndins notper: cmp #3B:h ; see if enter key bne notentr ; branch if not lda #0D:h ; else, send a cr jmp sndins notentr:cmp #3C:h ; see if minus bne iscomma ; if not, then branch lda #2D:h ; send a minus jmp sndins iscomma:lda #2C:h ; its a comma, so send one jmp sndins ;---------------------------------------------------------------------- ; check the dip switch settings ;------------------------------ ; chkdip: lda dipsw11 ; get dip switch settings asl a sta tempdip lda dipsw12 and #01 ora tempdip sta tempdip ; save it temporarily cmp dip1 ; see if switch changed bne change ; if (dip switch unchanged) then rts ; return change: lda swdif ; else, beq setdif ; if (different flag = true) then lda newdip ; get new dip setting cmp tempdip bne nodb ; if (dip sw same as last time through) then dec dbounce ; update debounce timer bne notim ; if not zero, then no timeout yet lda #0 ; else, clear, and prepare to re-init sta tempdip sta swdif jmp warm notim: rts nodb: lda #0FF:h ; else, reset debounce sta dbounce rts ; and return setdif: lda #0FF:h ; else sta swdif ; set switch different flag to true sta dbounce ; reset timeout counter lda tempdip ; set new switch value sta newdip rts ;---------------------------------------------------------------------- ; update the screen saver timeout ;-------------------------------- ; savscrn:lda timen ; check if screen timeout enabled beq timscrn ; if ( screen timeout disabled) then rts ; return timscrn:lda disupdt ; else, get display update flag bne scrnon ; if (disupdt flag = 0FF:h) then turn screen on lda disoff ; else, see if display is off bne scrnoff ; if (display not off) then jmp timeout ; update timeout counter, and turn off screen if reqd scrnoff:rts ; else, return scrnon: ldx #1 ; turn on screen stx crtc ; select horiz displayed char register of crtc ldx #80 stx crtc+1 ; set for 80 characters ldx #0 stx timecnt ; reset timeout counter stx timecnt+1 stx timecnt+2 stx disupdt ; clear update flag stx disoff rts ; and return timeout:clc ; update timeout counter lda #1 adc timecnt sta timecnt ; increment 1st byte of timeout counter lda #0 adc timecnt+1 sta timecnt+1 ; increment 2nd byte of timeout counter lda #0 adc timecnt+2 sta timecnt+2 ; increment 3rd byte of timeout counter cmp #73 ; see if time up beq timeup ; if (time not up) then rts ; return timeup: lda #0FF:h ; else, set display off flag sta disoff ldx #1 ; and turn off the display stx crtc ; select horiz char displayed register dex stx crtc+1 ; set to 0 rts page ;---------------------------------------------------------------------- ; send the character in a reg to the kbrd ;---------------------------------------- ; kbrdout:sei ; disable interrupts pha ; save char to send ldy #8 ; set to send 8 data bits retry: ldx baud ; check if kbrd trying to send bpl kbrdfre ; jump if kbrd not trying to send a char abort: jsr ftchkey ; else, handle kbrd request as an interrupt jmp retry ; now, try again kbrdfre:lda #1 ; assert attention to kbrd ora bdreg ; but without affecting other bits sta baud ldx #1 ; contention check jsr kdly ; wait 10 micro seconds nop nop nop ; pad ldx baud ; check if kbrd ack asserted bpl ack1 ; if ( keyboard ack asserted) then lda bdreg sta baud ; cancel request to keyboard, jmp abort ; and go get the char from the keyboard ack1: ldx baud ; wait for kbrd to request data bpl ack1 pla ; get char to send tax ; save it lsr a ; shift it for next time through pha ; put back on stack txa ; get bit to send and #1 ; only lsb is needed ora bdreg ; be sure not to change rest of register sta baud ; output bit to kbrd ack2: ldx baud ; wait for kbrd to ack that it got bit bmi ack2 dey ; now, adjust number of bits left to send bne ack1 ; if 8 bits not sent, then start again lda bdreg ; else, go to quiescent state sta baud pla ; restore stack cli ; re-enable interrupts rts page ;---------------------------------------------------------------------- ; buffer handling stuff ;---------------------- ; sndrem: ldx outsp ; remove a char from send buffer return it in a lda sndbuf,x ; get a char from sndbuf cmp #0FF:h beq nochar ; if ff, then no char to remove tay ; save the character removed lda #0FF:h ; mark the spot empty sta sndbuf,x inc outsp ; adjust ring pointer lda #01111111:b and outsp sta outsp tya ; get char back rts page ;---------------------------------------------------------------------- ; remove a character from the input buffer ;----------------------------------------- ; inrem: ldy #0 ; remove a char from input buffer return it in a lda (insp),y ; get a char from inbuf cmp #0FF:h beq nochar ; if ff, then no char to remove tax ; save the character removed lda #0FF:h ; mark the spot empty sta (insp),y clc ; adjust ring pointer lda #1 adc insp sta insp lda #0 adc insp+1 cmp #4 bne remdone lda #2 remdone:sta insp+1 txa ; get char back nochar: rts keyrem: ldx keyep ldy keybuf,x inx txa and #15 sta keyep tya rts page ;---------------------------------------------------------------------- ; insert a character into the send buffer ;---------------------------------------- ; sndins: tay ; insert char in a into send buffer txa ; save x register pha lda brkhit beq nothit ; if (brkhit=true) then cpy #ctrlc ; if ( char = ^c ) then beq sndfull ; return lda #0 ; else sta brkhit ; brkhit <= false ; put char in buffer if room exists nothit: ldx outep ; get end pointer of send buffer lda sndbuf,x ; see if buffer full cmp #0FF:h bne sndfull ; if not ff, then buffer is full tya sta sndbuf,x ; else, put char into buffer inc outep ; adjust ring pointer lda #01111111:b and outep sta outep sndfull:pla ; restore x register tax rts page ;---------------------------------------------------------------------- ; translate output characters ;---------------------------- ; xltout: ldy numxlto ; get number of characters to be xlated beq noxlt1 ; if 0, then no xlations needed search1:cmp (xlt1),y ; see if character is in kbrd search list beq chng1 ; if so, then change a char dey ; else, point to next character in xlation list bne search1 ; if any characters are left to check, check another noxlt1: rts ; return if character not in list chng1: lda (xlt2),y ; else, get replacement character rts ;---------------------------------------------------------------------- ; translate input characters ;--------------------------- ; xltin: ldy numxlti ; get number of characters to be xlated beq noxlt2 ; if 0, then no xlations needed search2:cmp (xlt3),y ; see if character is in kbrd search list beq chng2 ; if so, then change a char dey ; else, point to next character in xlation list bne search2 ; if any characters are left to check, check another noxlt2: rts ; return if character not in list chng2: lda (xlt4),y ; else, get replacement character rts page ;---------------------------------------------------------------------- ; function code output routine for all function keys except f1-f10 ;----------------------------------------------------------------- ; fncnout:and #7F:h ; knock off 8th bit tax ; save character cmp #00001111:b ; see if keyboard power up beq nocr ; if received, just return jsr masksc ; convert shift and control to no shift or control ldy #morld ; assume morrow lead in lda fncntyp ; see what lead in should be beq sndldin ; if (lead in not morrow) then ldy #telld ; set for televideo lead in sndldin:tya ; get lead in to a reg jsr sndins ; put in insert buffer lda ftable,x ; get function code jsr sndins ; put function code in insert buffer lda fncntyp ; see if terminating cr required beq nocr ; if ( cr required ) then lda #0D:h ; put cr in send buffer jmp sndins ; and return nocr: rts ; else, return page ;---------------------------------------------------------------------- ; function code output routine for f1-f10 keys ;--------------------------------------------- ; fnum: ldx #0 ; clear lead in flag for f1-f10 keys stx fncld tax ; save character and #00010000:b ; be sure code isn't kbrd id code cmp #00010000:b beq nocr1 jsr masksc ; convert shift and ctrl function to no shift or ctrl ldy #morld ; assume morrow lead in lda fncntyp ; see what lead in should be beq sndld ; if (lead in not morrow) then ldy #telld ; set for televideo lead in sndld: tya ; get lead in to a reg jsr sndins ; put in insert buffer txa ; get character back and #0F:h ; mask of key number sta temp2 ; save key number txa ; get char again and #60:h ; convert to proper table index lsr a ora temp2 tax lda f110tbl,x ; get function code jsr sndins ; put function code in insert buffer lda fncntyp ; see if terminating cr required beq nocr1 ; if ( cr required ) then lda #0D:h ; put cr in send buffer jmp sndins ; and return nocr1: rts ; else, return masksc: txa ; get character and #01100000:b ; check if shift and control bits both down cmp #01100000:b bne nomask ; if no, then don't change function code txa ; else, get original character and #00011111:b ; set shift and ctrl bits to zero tax ; restore as new function code nomask: rts page ;---------------------------------------------------------------------- ; include files ;-------------- ; ; includ uart1.asm ; includ init1.asm ; includ esc1.asm ; includ video1.asm ; includ intrpt1.asm ; ;---------------------------------------------------------------------- ; restart and interrupt vectors ;------------------------------ ; org 0FFF0:h dw null dw null dw null dw null dw null dw nmivec dw start dw irqvec end