diff --git a/screen.S b/screen.S new file mode 100644 index 0000000..b9990cb --- /dev/null +++ b/screen.S @@ -0,0 +1,198 @@ + + rel + mx %11 + + ent erase_line + ent erase_line_0 + ent erase_line_1 + ent erase_line_2 + +erase_line +; a = 0 - erase x - eol (inclusive) +; a = 1 - erase 0 - x (inclusive) +; a = 2 - erase 0 - eol + cmp #2 + bcs :rts + asl + tax + jmp (:table,x) +:rts rts + +:table + dw erase_line_0 + dw erase_line_1 + dw erase_line_2 + +erase_line_2 +* erase entire line. + php + rep #$30 + ldy #38 + lda #" " +:loop + sta [text01],y + sta (text00),y + dey + dey + bpl :loop + plp + rts + + mx %11 + +erase_line_0 +* erase to eol + + lda x + lsr + tay + lda #" " + bcs :half +:loop + sta [text01],y +:half sta (text00),y + iny + cpy #40 + bcc :loop + rts + +erase_line_1 +* erase to x (inclusive) + + lda x + lsr + tay + lda #" " + bcc :half + +:loop + sta (text00),y +:half sta [text01],y + dey + bpl :loop + rts + + +erase_screen ent +; a = 0 - erase [cursor, end] (inclusive) +; a = 1 - erase [start, cursor] (inclusive) +; a = 2 - erase [start, end] + cmp #2 + bcs :rts + asl + tax + jmp (:table,x) +:rts rts + +:table + dw erase_screen_0 + dw erase_screen_1 + dw erase_screen_2 + +erase_screen_2 ent +* erase the entire screen. + php + rep #$30 + lda #" " ; high bit set. + +c00 cc $0400 +c01 cc $0480 +c02 cc $0500 +c03 cc $0580 +c04 cc $0600 +c05 cc $0680 +c06 cc $0700 +c07 cc $0780 +c08 cc $0428 +c09 cc $04a8 +c10 cc $0528 +c11 cc $05a8 +c12 cc $0628 +c13 cc $06a8 +c14 cc $0728 +c15 cc $07a8 +c16 cc $0450 +c17 cc $04d0 +c18 cc $0550 +c19 cc $05d0 +c20 cc $0650 +c21 cc $06d0 +c22 cc $0750 +c23 cc $07d0 + plp + rts + + mx %11 + +erase_screen_0 ent +* erase from cursor to the end. + mx %11 + ldx #0 ; for jmp (,x) + lda x + ora y + beq :all + + lda x + beq :x0 + jsr erase_line_0 + lda y + inc + bra :x1 +:x0 + lda y +:x1 cmp #23 + bcs :rts + asl + tax +:all php ; clear_table will plp. + rep #$30 + lda #" " + jmp (clear_table,x) + +:rts rts + + +erase_screen_1 ent +* erase from start to cursor. + jsr erase_line_1 + lda y + bne :ok + rts +:ok + php + rep #$30 + lda y + dey + asl + tax + lda #" " + jmp (:clear_table,x) +:clear_table + + +c23 cc $07d0 +c22 cc $0750 +c21 cc $06d0 +c20 cc $0650 +c19 cc $05d0 +c18 cc $0550 +c17 cc $04d0 +c16 cc $0450 +c15 cc $07a8 +c14 cc $0728 +c13 cc $06a8 +c12 cc $0628 +c11 cc $05a8 +c10 cc $0528 +c09 cc $04a8 +c08 cc $0428 +c07 cc $0780 +c06 cc $0700 +c05 cc $0680 +c04 cc $0600 +c03 cc $0580 +c02 cc $0500 +c01 cc $0480 +c00 cc $0400 + plp + rts \ No newline at end of file diff --git a/table.py b/table.py new file mode 100644 index 0000000..e11e9c3 --- /dev/null +++ b/table.py @@ -0,0 +1,73 @@ + + +import sys + + +special = { +} +for x in range(0,0x20): special[chr(x)] = '^' + chr(0x40 + x) + +cmap = { + '\'': '\'', + '\"': '\"', + '?': '?', + '\\': '\\', + 'a': '\a', + 'b': '\b', + 'f': '\f', + 'n': '\n', + 'r': '\r', + 't': '\t', + 'v': '\v', +} + + + +argv = sys.argv[1:] + +chars = [] +for arg in argv: + # ^X is a control character + if len(arg) == 2 and arg[0] == '^': + c = chr(ord(arg[1]) & 0x1f) + chars.append(c) + continue + # \X is an escaped character + if len(arg) == 2 and arg[0] == '\\': + c = arg[1] + if c in cmap: chars.append(cmap[c]) + continue + + # X-Y is a range of characters. + if len(arg) == 4 and arg[1] == '-': + a = arg[0] + b = arg[2] + for c in range(ord(a),ord(b)+1): + chars.append(chr(c)) + continue + + chars.extend(arg) + +chars = list(set(chars)) +chars.sort() + +if not chars: exit(1) + +mmin = ord(chars[0]) +mmax = ord(chars[-1]) + +print(":MIN\tequ {}".format(mmin)) +print(":MAX\tequ {}".format(mmax)) +print() + + + + +print(":table") +for x in range(mmin, mmax+1): + c = chr(x) + print("\tdw $0\t; {}".format(special.get(c, c))) + +# for c in chars: +# x = ord(c) +# print("\tdw $0\t; {}".format(special.get(c, c))) diff --git a/vt.equ.S b/vt.equ.S new file mode 100644 index 0000000..9d13b58 --- /dev/null +++ b/vt.equ.S @@ -0,0 +1,60 @@ + +st_vt52 equ 0 +st_vt52_esc equ 2 +st_vt52_dca equ 4 +st_vt100 equ 6 +st_vt100_esc equ 8 +st_vt100_csi equ 10 +st_vt100_csi_2 equ 12 +st_vt100_esc_pound equ 14 ; # +st_vt100_esc_lparen equ 16 ; ( +st_vt100_esc_rparen equ 18 ; ) + +st_vt100_esc_bad equ 20 +st_vt100_csi_bad equ 22 + +ESC equ $1b + + + dum 0 +state ds 2 +x ds 2 +y ds 2 +DECTM ds 2 ; top margin +DECBM ds 2 ; bottom margin + +LOCAL ds 2 ; local mode +DECANM ds 2 ; ansi/vt52 +DECKPAM ds 2 ; alternate keypad +DECCKM ds 2 ; cursor key modes +DECOM ds 2 ; origin +DECSCNM ds 2 ; screen mode +DECAWM ds 2 ; wrap +DECARM ds 2 ; auto repeat + + +LNM ds 2 ; new line +SGR ds 2 ; graphics, bit 1 = bold, 4 = underscore, 5 = blink, 7 = inverse + +* not supported + +*CHARSET ds 2 ; +*GRAPHICS ds 2 ; + +*DECCOLM ds 2 ; character per line (80/132) +*DECINLM ds 2 ; interlace +*DECSCLM ds 2 ; scroll mode + +* DECDHL - double height line +* DECDWL - double width line + + +* parameters +MAX_PCOUNT equ 8 +pcount ds 2 +parms ds MAX_PCOUNT +pmod ds 2 + +r0 ds 2 + + dend diff --git a/vt100.S b/vt100.S new file mode 100644 index 0000000..0cfbf3a --- /dev/null +++ b/vt100.S @@ -0,0 +1,177 @@ + + + +vt100 + mx %11 + and #$7f + cmp #' ' + bcs :notctrl + asl + tax + jmp (ctrl,x) +:notctrl + ldx state + jmp (:state_table,x) + + + +:state_table + ext vt52_esc,vt52_dca + ext vt100_esc,vt100_csi,vt100_csi_2 + ext vt100_esc_pound,vt100_esc_lparen,vt100_esc_rparen + + dw char + dw vt52_esc + dw vt52_dca + dw char + dw vt100_esc + dw vt100_csi + dw vt100_csi_2 + dw vt100_esc_pound + dw vt100_esc_lparen + dw vt100_esc_rparen + + + + + +vt100_csi_bad ent + cmp #'@' + blt :rts + ldx #st_vt100 + stx state +:rts rts + + + + +esc_csi + stz pcount + stz params + stz params+1 + stz csi_private + lda #st_csi + sta state + rts + + +csi + inc state + inc state + cmp #'?' + bne csi0 + lda #$80 + sta csi_private + rts + +csi0 + cmp #';' + beq :semi + cmp #'0' + bcc csi_final + cmp #'9'+1 + bcs csi_final +:num + and #$0f ; 0-9 + tay ; save + ldx pcount + lda params,x + asl ; x 2 + sta params,x + asl ; x 4 + asl ; x 8 + clc + adc params,x + sta params,x + tya + clc + adc params,x + sta params,x + rts + + +:semi + ldx pcount + inx + cpx #MAX_PCOUNT + bcs :srts + stx pcount + stz params,x + +:srts + rts + + +csi_final +* c, h, l have private modes. + bit csi_private + bmi :priv + + cmp #:MIN_FINAL + bcc :rts + cmp #:MAX_FINAL+1 + bcs :rts + asl + tax + jmp (:table,x) +:rts rts + +:priv + cmp #:MIN_FINAL_PRIV + bcc :rts + cmp #:MAX_FINAL_PRIV+1 + bcs :rts + asl + tax + jmp (:table_priv,x) + + +csi +* +* ESC [ encountered. +* +* ? -> DEC private +* 0-9 -> parameter value +* ; parameter delim +* other - final character. + + cmp #'0' + blt :notnum + cmp #'9'+1 + bge :notnum + + sep #$30 + and #$0f + tay + ldx pcount + lda parms,x + asl + pha + asl + asl + clc + adc 1,s + sta 1,s + tya + adc 1,s + ply + sta parms,x + sep #$30 +]rts rts +:notnum + cmp #';' + bne :notsemi + ldx pcount + cpx #MAXPCOUNT + bge ]rts + inx + stx pcount + stz parms, + stz parms+1,x +]rts rts +:notsemi + cmp #'?' + bne :final + sta ptype + rts +:final \ No newline at end of file diff --git a/vt100.csi.S b/vt100.csi.S new file mode 100644 index 0000000..3280282 --- /dev/null +++ b/vt100.csi.S @@ -0,0 +1,413 @@ + + + + rel + xc + xc + + use vt.equ + + +vt100_csi ent + inc state + inc state + + stz pcount + stz parms + stz parms+1 ; some assume 2 parms. + stz pmod + + tay ; save for modifier + cmp #:MIN + blt :bad + cmp #:MAX+1 + bge :bad + sec + sbc #:MIN + asl + tax + jmp (:table,x) +:bad + ldx #st_vt100 + stx state +:rts rts + +:table + +* 0123456789;ycnlhgrqJKmABCDHf + +* based on testing - +* everything except '0' - '?' and control chars +* will finish. +* '?' only matters for h/l +* a misplaced ? (or anything in '0' - '?', except 0-9;) +* will cancel the sequence AFTER it's finished. +* < = > ? are allowed as an initial modifier but only '?' is private +* a mis-placed < = > ? will prevent 0x20-0x2f from terminating the sequence. + +:MIN equ 48 +:MAX equ 121 +:table + dw :digit ; 0 + dw :digit ; 1 + dw :digit ; 2 + dw :digit ; 3 + dw :digit ; 4 + dw :digit ; 5 + dw :digit ; 6 + dw :digit ; 7 + dw :digit ; 8 + dw :digit ; 9 + dw digit ; : + dw semi + dw :rts ; < + dw :rts ; = + dw :rts ; > + dw :modifier ; ? + dw $0 ; @ + dw $0 ; A + dw $0 ; B + dw $0 ; C + dw $0 ; D + dw $0 ; E + dw $0 ; F + dw $0 ; G + dw $0 ; H + dw $0 ; I + dw $0 ; J + dw $0 ; K + dw $0 ; L + dw $0 ; M + dw $0 ; N + dw $0 ; O + dw $0 ; P + dw $0 ; Q + dw $0 ; R + dw $0 ; S + dw $0 ; T + dw $0 ; U + dw $0 ; V + dw $0 ; W + dw $0 ; X + dw $0 ; Y + dw $0 ; Z + dw $0 ; [ + dw $0 ; \ + dw $0 ; ] + dw $0 ; ^ + dw $0 ; _ + dw $0 ; ` + dw $0 ; a + dw $0 ; b + dw $0 ; c + dw $0 ; d + dw $0 ; e + dw $0 ; f + dw $0 ; g + dw $0 ; h + dw $0 ; i + dw $0 ; j + dw $0 ; k + dw $0 ; l + dw $0 ; m + dw $0 ; n + dw $0 ; o + dw $0 ; p + dw $0 ; q + dw $0 ; r + dw $0 ; s + dw $0 ; t + dw $0 ; u + dw $0 ; v + dw $0 ; w + dw $0 ; x + dw $0 ; y + + +:digit + lsr ; undo asl + sta parms + rts +:modifier + ldx #$40 ; bit -> v + stx pmod + rts + + +vt100_csi_2 ent + + ; if < '0' and invalid modifier, don't terminate. + bit pmod + bmi :badmod + cmp #'@' + blt :0 + ldx #st_vt100 + stx state + +:0 cmp #:MIN + blt :bad + cmp #:MAX+1 + bge :bad + sec + sbc #:MIN + jmp (:table,x) + +:badmod + cmp #'@' + blt :rts + +:bad + ldx #st_vt100 + stx state +:rts rts + +:MIN equ 48 +:MAX equ 121 +:table + dw digit ; 0 + dw digit ; 1 + dw digit ; 2 + dw digit ; 3 + dw digit ; 4 + dw digit ; 5 + dw digit ; 6 + dw digit ; 7 + dw digit ; 8 + dw digit ; 9 + dw digit ; : + dw semi + dw :modifier ; < + dw :modifier ; = + dw :modifier ; > + dw :modifier ; ? + +:modifier + lda #$80 + sta pmod + rts + +semi + ldx pcount + cpx #MAX_PCOUNT + bge :rts + + inx + stx pcount + stz parms,x +:rts rts + +* parameter digit. clamped to 255 (250+ rounds up to 255) +* in 132 is the largest valid parameter so this is ok. +digit + lsr ; undo asl + sta r0 + ldx pcount + lda parms,x +* cmp #255 +* beq :rts + cmp #25 + bge :v + + tay + lda :table,y +* clc ; cleared via cmp + adc r1 + sta parms,x + + +:rts + rts +:v + lda #$255 + sta parms,x + rts + +:table da 0,10,20,30,40,50,60,70,80,90 + da 100,110,120,130,140,150,160,170,180,190 + da 200,210,220,230,240,250 + + + + + +set_mode + ; esc [ ... h (vt100) + ; esc [ ? ... h (private) + ldy #$80 + bra mode_common + +reset_mode + ; esc [ ... l (vt100) + ; esc [ ? ... l (private) + ldy #0 + +mode_common + inc pcount + ldx #0 +:loop lda parms,x + cmp #:MIN + blt :next + cmp #:MAX+1 + bgt :next + phx + asl + tax + jsr (:table,x) + plx + +:next inx + cpx pcount + blt :loop +:rts rts + +:MIN equ 0 +:MAX equ 20 +:table + dw :rts ; error + dw mode_DECCKM + dw mode_DECANM + dw :rts ; DECCOLM + dw :rts ; DECSCLM + dw mode_DECSCNM + dw mode_DECOM + dw mode_DECAWM + dw mode_DECARM + dw :rts ; DECINLM + dw :rts ; 10 + dw :rts ; 11 + dw :rts ; 12 + dw :rts ; 13 + dw :rts ; 14 + dw :rts ; 15 + dw :rts ; 16 + dw :rts ; 17 + dw :rts ; 18 + dw :rts ; 19 + dw mode_LNM +*:mask dw 0,$40,$40,$40,$40,$40,$40,$40,$40,$40 +* dw 0,0,0,0,0,0,0,0,0,0,0 + + +mode_DECCKM + bit pmod + bvc :rts + + sty DECCKM +:rts rts + +mode_DECANM + bit pmod + bvc :rts + + sty DECANM + cpy #0 + bne :rts +* switch to vt52 mode + ldx #st_vt52 + stx state +:rts rts + + +*mode_DECCOLM +* sty DECCOLM +* rts + + +mode_DECSCNM + bit pmod + bvc :rts + +* todo - invert on-screen characters? + sty DECSCNM +:rts rts + +mode_DECOM + bit pmod + bvc :rts + + sty DECOM + ; move to the new home position + stz x + stz y + cpy #0 + beq :rts + lda #DECTM + sta y + + phy + jsr update_cursor + ply + +:rts rts + +mode_DECAWM + bit pmod + bvc :rts + + sty DECAWM +:rts rts + +mode_DECARM + bit pmod + bvc :rts + + sty DECARM +:rts rts + +mode_LNM + bit pmod + bvs :rts + + sty LNM +:rts rts + + +char_attr +* esc [ ... m + inc pcount + ldx #0 +:loop lda parms,x + cmp #8 + bge :next + tay + lda SGR + and :and,y + ora :or,y + lda :table,y + sta SGR + +:next inx + cpx pcount + blt :loop +:rts rts + + +:and db $00,$ff,$ff,$ff,$ff,$ff,$ff,$ff + +:or db %0000_0000,%0000_0010,%0000_0000,%0000_0000 + db %0001_0000,%0010_0000,%0000_0000,%1000_0000 + + + +reset_tab +* ESC H - set tab at current column [vt100.s] +* ESC [ g, ESC [ 0 g - clear tab at column +* ESC [ 3 g - clear all tabs + + lda parm + beq :0 + cmp #3 + beq :3 + rts +:0 + ldx x + stz tabs,x + rts +:3 + ldx #80-1 +:loop stz tabs,x + dex + bpl :loop + rts + + sav vt100.csi.L diff --git a/vt100.ctrl.S b/vt100.ctrl.S new file mode 100644 index 0000000..5a2a166 --- /dev/null +++ b/vt100.ctrl.S @@ -0,0 +1,103 @@ + + +*control chars + ext draw_char,update_cursor + +control ent + + asl + tax + jmp (:table,x) + +:table + dw :rts ; ^@ + dw :rts ; ^A + dw :rts ; ^B + dw :rts ; ^C + dw :rts ; ^D + dw enq ; ^E + dw :rts ; ^F + dw bel ; ^G + dw bs ; ^H + dw tab ; ^I + dw lf ; ^J + dw vt ; ^K + dw ff ; ^L + dw cr ; ^M + dw so ; ^N + dw si ; ^O + dw :rts ; ^P + dw xon ; ^Q + dw :rts ; ^R + dw xoff ; ^S + dw :rts ; ^T + dw :rts ; ^U + dw :rts ; ^V + dw :rts ; ^W + dw can ; ^X + dw :rts ; ^Y + dw sub ; ^Z + dw esc ; ^[ + dw :rts ; ^\ + dw :rts ; ^] + dw :rts ; ^^ + dw :rts ; ^_ + +:rts rts + +enq +* send answer back message. +* answer back message is a user-controllable string of text sent as-is +* (with no specific terminator character) + rts +bel +* todo - trigger nice ensoniq beep. + rts + + +bs +* backspace, no wrap + lda x + beq :rts + dec x + jmp update_cursor +:rts rts + +tab +* go to next tab stop + rts + +lf +vt +ff +* vt and ff interpreted as lf +* LNM: also do cr. + bit LNM + bpl :lnm + stz x +:lnm + lda y + cmp BM ; bottom margin + bne :iny + jmp scroll_up +:iny inc y + jmp update_cursor + +cr + stz x + jmp update_cursor + +xon +xoff +* flow control... + rts +can +sub +* cancel esc sequence and display error character + stz state + rts + +esc + lda #st_esc + sta state + rts \ No newline at end of file diff --git a/vt100.esc.S b/vt100.esc.S new file mode 100644 index 0000000..415d719 --- /dev/null +++ b/vt100.esc.S @@ -0,0 +1,164 @@ + + + rel + xc + xc + + use vt.equ + +vt100_esc ent +* #[()=>cH78DEM +* based on testing, unspecified chars in the 0x20-0x2f range cause it to gobble +* chars until 0x30- terminator (which ends the sequence but does not take an action) + +* esc 1 -> hangs? [undocumented] + + + ldx #st_vt100 + stx state + + cmp #:MIN + blt :bad + cmp #:MAX+1 + bge :rts + sec + sbc #:MIN + asl + tax + jmp (:table,x) + +:bad + ldx #st_vt100_esc_bad + stx state +:rts + rts + +:MIN equ 35 +:MAX equ 99 + +:table + dw :pound ; # + dw :bad ; $ + dw :bad ; % + dw :bad ; & + dw :bad ; ' + dw :lparen ; ( + dw :rparen ; ) + dw :bad ; * + dw :bad ; + + dw :bad ; , + dw :bad ; - + dw :bad ; . + dw :bad ; / + dw :rts ; 0 + dw :rts ; 1 + dw :rts ; 2 + dw :rts ; 3 + dw :rts ; 4 + dw :rts ; 5 + dw :rts ; 6 + dw esc_7 ; 7 + dw esc_8 ; 8 + dw :rts ; 9 + dw :rts ; : + dw :rts ; ; + dw :rts ; < + dw esc_eq ; = + dw esc_gt ; > + dw :rts ; ? + dw :rts ; @ + dw :rts ; A + dw :rts ; B + dw :rts ; C + dw esc_D ; D + dw esc_E ; E + dw :rts ; F + dw :rts ; G + dw esc_H ; H + dw :rts ; I + dw :rts ; J + dw :rts ; K + dw :rts ; L + dw esc_M ; M + dw :rts ; N + dw :rts ; O + dw :rts ; P + dw :rts ; Q + dw :rts ; R + dw :rts ; S + dw :rts ; T + dw :rts ; U + dw :rts ; V + dw :rts ; W + dw :rts ; X + dw :rts ; Y + dw :rts ; Z + dw :rts ; [ + dw :rts ; \ + dw :rts ; ] + dw :rts ; ^ + dw :rts ; _ + dw :rts ; ` + dw :rts ; a + dw :rts ; b + dw esc_c ; c + + + +:lparen + ldx #st_vt100_esc_lparen + stx state + rts + +:rparen + ldx #st_vt100_esc_rparen + stx state + rts + +:pound + ldx #st_vt100_esc_pound + stx state + rts + + +esc_7 ; save cursor position, graphic rendition, and character set. + rts +esc_8 ; restore cursor position, graphic rendition, and character set. + rts + +esc_eq ; enter alternate keypad mode + lda #$80 + sta DECKPAM + rts +esc_gt ; exit alternate keypad mode + stz DECKPAM + rts + +esc_H ; set tab stop + ext set_tab + ldx x + jmp set_tab + +esc_E ; next line + stz x + ; drop through +esc_D ; index + rts + +esc_M ; reverse index + rts + +esc_c ; reset terminal. + rts + + +vt100_esc_bad ent + cmp #'0' + blt :rts + ldx #st_vt100 + stx state +:rts + rts + + + sav vt100.esc.L diff --git a/vt100.link.S b/vt100.link.S new file mode 100644 index 0000000..6276036 --- /dev/null +++ b/vt100.link.S @@ -0,0 +1,22 @@ + + ovr all + +* binary linker + lkv 0 + org $6000 + + asm boot.S + asm vt100.ctrl.S + + + + lnk boot.S + pos ; reset + + + pos EMU_SIZE +EMU_SIZE ext +EMU_BLOCKS geq EMU_SIZE+511\512 + + + sav vt100.bin \ No newline at end of file diff --git a/vt100.main.S b/vt100.main.S new file mode 100644 index 0000000..3a2123a --- /dev/null +++ b/vt100.main.S @@ -0,0 +1,147 @@ +vt100 + mx %11 + and #$7f + cmp #' ' + bcs :notctrl + asl + tax + jmp (:ctrl_table,x) +:notctrl + ldx state + jmp (:state_table,x) + + + +:state_table + ext vt52_esc,vt52_dca_1,vt52_dca_2 + ext vt100_esc,vt100_csi,vt100_csi_2 + ext vt100_esc_pound,vt100_esc_lparen,vt100_esc_rparen + + dw char + dw vt52_esc + dw vt52_dca_1 + dw vt52_dca_2 + dw char + dw vt100_esc + dw vt100_csi + dw vt100_csi_2 + dw vt100_esc_pound + dw vt100_esc_lparen + dw vt100_esc_rparen + + +:ctrl_table + dw ctrl_00,ctrl_01,ctrl_02,ctrl_03 + dw ctrl_04,ctrl_05,ctrl_06,ctrl_07 + dw ctrl_08,ctrl_09,ctrl_0a,ctrl_0b + dw ctrl_0c,ctrl_0d,ctrl_0e,ctrl_0f + dw ctrl_10,ctrl_11,ctrl_12,ctrl_13 + dw ctrl_14,ctrl_15,ctrl_16,ctrl_17 + dw ctrl_18,ctrl_19,ctrl_1a,ctrl_1b + dw ctrl_1c,ctrl_1d,ctrl_1e,ctrl_1f + + + +ctrl_00 +ctrl_01 +ctrl_02 +ctrl_03 +ctrl_04 +ctrl_05 ; answer ENQ +ctrl_06 +ctrl_0e ; G1 character set +ctrl_0f ; G0 character set +ctrl_10 +ctrl_11 ; XON +ctrl_12 +ctrl_13 ; XOFF +ctrl_14 +ctrl_15 +ctrl_16 +ctrl_17 +ctrl_19 +ctrl_1c +ctrl_1d +ctrl_1e +ctrl_1f + rts + + +ctrl_07 ; ring the bell. + rts + +ctrl_1b ; escape - +* vt100 - aborts current escape sequence and starts a new one. +* vt52 - esc esc aborts and starts new +* vt50 - esc esc aborts + lda DECANM + bne :vt52 + lda #st_vt100_esc + sta state + rts + +:vt52 + lda #st_vt52_esc + sta state + rts + +ctrl_18 +ctrl_1a +* vt100 - abort current escape sequence +* and display error character. + lda DECANM + bne :vt52 + lda #st_vt100 + sta state + rts + +:vt52 + lda #st_vt52 + sta state + rts + + +ctrl_09 ; tab +* vt100 has adjustable tabs. + ext tab_table + + ldx x +lp: + cpx #79 + bcs :rts + lda tab_table,x + bne :hit + inx + bra :lp + + stx x + + jmp update_cursor +:rts rts + +ctrl_0a ; line feed - cursor down w/ scroll +ctrl_0b ; vertical tab +ctrl_0c ; form feed. + +* if LNM is active, equivalent to CR, LF + + lda #LNM + bne :lnm + stz x +:lnm + + lda y + cmp #23 + blt :simple + + lda #" " + sta cursor_saved_char + jmp scroll_down + +:simple + inc y + jmp update_cursor + +ctrl_0d ; carriage return - cursor to column 0. + stz x + jmp update_cursor diff --git a/vt100.tabs.S b/vt100.tabs.S new file mode 100644 index 0000000..5e21e12 --- /dev/null +++ b/vt100.tabs.S @@ -0,0 +1,77 @@ + + + rel + xc + xc + + use vt.equ + + +init_tabs ent + + + ldx #80 +:loop stz tabs,x + dex + bpl :loop + + lda #72 + ldy #$80 +:tloop tax + sty tabs,x + sec + sbc #8 + bne :tloop + + rts +*:table db 8*1,8*2,8*3,8*4,8*5,8*6,8*7,8*8*,8*9 + +set_tab ent +* input x = x + +* ldx x + cpx #80 + bge :rts + lda #$80 + sta tabs,x +:rts rts + +reset_tab ent +* input x = x + +* ldx x + cpx #80 + bge :rts + stz tabs,x +:rts rts + + +reset_all_tabs ent + + ldx #80-1 +:loop stz tabs,x + dex + bpl :loop + rts + +next_tab_stop ent +* input x = x + +* ldx x + cpx 79 + bge :80 + +:loop bit tabs,x + bmi :rts + inx + cpx #80 + bcc :loop + + +:80 ldx #80 +:rts rts + + +tabs ds 80 + + sav vt100.tabs.L diff --git a/vt100.vt52.S b/vt100.vt52.S new file mode 100644 index 0000000..1fd464e --- /dev/null +++ b/vt100.vt52.S @@ -0,0 +1,228 @@ +* +* vt52 emulation for the vt100 +* +* ESC < exits + + lst off + + rel + xc + xc + + use vt.equ + + ext update_cursor,write_modem,draw_char + + + +vt52_esc ent +* ABCDFGHIJKYZ<>= + + + ldx #st_vt52 + stx state + + cmp #:MIN + blt :rts + cmp #:MAX+1 + bge :rts + sec + sbc #:MIN + asl + tax + jmp (:table,x) + +:rts + rts + + +:MIN equ 60 +:MAX equ 90 +:table + dw esc_lt ; < + dw esc_eq ; = + dw esc_gt ; > + dw :rts ; ? + dw :rts ; @ + dw esc_A ; A + dw esc_B ; B + dw esc_C ; C + dw esc_D ; D + dw :rts ; E + dw esc_F ; F + dw esc_G ; G + dw esc_H ; H + dw esc_I ; I + dw esc_J ; J + dw esc_K ; K + dw :rts ; L + dw :rts ; M + dw :rts ; N + dw :rts ; O + dw :rts ; P + dw :rts ; Q + dw :rts ; R + dw :rts ; S + dw :rts ; T + dw :rts ; U + dw :rts ; V + dw :rts ; W + dw :rts ; X + dw esc_Y ; Y + dw esc_Z ; Z + + + +esc_lt +* based on testing, this also resets graphics mode +* (which we don't support anyhow.) + lda #$80 + sta DECANM + lda #st_vt100 + sta state + rts + + +esc_eq ; enter alternate keypad mode + lda #$80 + sta DECKPAM + rts + +esc_gt ; exit alternate keypad mode + stz DECKPAM + rts + +* cursor movement respects the scrolling region. +esc_A ; cursor up. + lda y + beq :rts + cmp DECTM + beq :rts + dec y + jmp update_cursor + +:rts rts + + +esc_B ; cursor down + lda y + cmp #79 + beq :rts + cmp DECBM + beq :rts + iny y + jmp update_cursor + +:rts rts + + +esc_C ; cursor right + + lda x + cmp #79 + bcs :rts + inc x + jmp update_cursor +:rts rts + +esc_D ; cursor left + + lda x + beq :rts + dec x + jmp update_cursor +:rts rts + +esc_I ; cursor up w/ line scroll +* based on testing, scrolling only occurs within the +* scroll region. + rts +esc_J rts +esc_K rts + + +esc_H ; cursor home + ; based on testing, does not respect scrolling region but does + ; respect origin mode. + stz x +* stz y +* bit DECOM +* bpl :go + lda DECTM + sta y + +:go jmp update_cursor + + +esc_F ; enter graphics mode +* lda #%0010 +* tsb mode + rts +esc_G ; exit graphics mode +* lda #%0010 +* trb mode + rts + +esc_Y ; direct cursor address +* vt100 - does not take effect until the end. +* based on testing, there is internal state information, +* so esc Y a esc B esc Y b is equivalent to esc Y a b +* +* if width exceeded, clamps at right margin. +* if height exceeded, does not change. + lda #st_vt52_dca + sta state + rts + +esc_Z ; terminal identity. + ; return ESC / Z + ; based on testing, no display in local mode + bit LOCAL + bmi :local + lda #ESC + jsr write_modem + lda #'/' + jsr write_modem + lda #'Z' + jmp write_modem + +:local rts +* lda #'Z' +* jmp draw_char + + + +vta52_dca ent +* this differs from esc [ H in that invalid +* values are ignored rather than clamped. +* based on testing, does not respect DECOM. +* based on testing, state is saved if ESC aborts, even +* if switching to vt100 mode and back or ^X to cancel. + + sec + sbc #' ' + + bit :tmp + bmi :go + ora #$80 + sta :tmp + rts + +:go ; a = x + cmp #80 + bge :y + sta x +:y lda :tmp + and #$7f + cmp #24 + bge :update + sta y +:update + stz :tmp + jmp update_cursor + + +:tmp ds 2 + + + sav vt100.vt52.L