From 2efe25fdb9ae89754d726fb58dade035c6251d16 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sun, 4 Apr 2021 20:22:43 -0400 Subject: [PATCH] terminal emulator experiments. --- boot.S | 100 ++++++++++ link.S | 21 ++ makefile | 24 +++ modem.s | 237 ++++++++++++++++++++++ scc.s | 142 ++++++++++++++ vt52.S | 589 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1113 insertions(+) create mode 100644 boot.S create mode 100644 link.S create mode 100644 makefile create mode 100644 modem.s create mode 100644 scc.s create mode 100644 vt52.S diff --git a/boot.S b/boot.S new file mode 100644 index 0000000..83e87e2 --- /dev/null +++ b/boot.S @@ -0,0 +1,100 @@ +* +* boot block. +* +* loaded at $0800 + + xc + xc + rel + +SLOT equ $00 +CMD equ $42 +UNIT equ $43 +BUFFER equ $44 +BLOCK equ $46 + + ext init +boot + mx %11 + + db $01 ; prodos boot id + +* slot 5 = x = $50, a = $3178 +* slot 6 = x = $60, a = $8401 +* stx :unit +* txa +* lsr +* lsr +* lsr +* lsr +* ora #$c0 + + + stx UNIT + txa + lsr + lsr + lsr + lsr + ora #$c0 + sta :prodos+2 + + stz SLOT + sta SLOT+1 + + ldy #1 + lda (SLOT),y + cmp #$20 + bne noboot + ldy #3 + lda (SLOT),y + bne noboot + ldy #5 + lda (SLOT),y + cmp #$03 + bne noboot + + ldy #$ff + lda (SLOT),y + sta :prodos+1 + + + lda #1 + sta CMD + sta BLOCK + stz BLOCK+1 + stz BUFFER + lda #$a0 ; $0800+512 + sta BUFFER+1 + +:read + jsr :prodos ; block 1 + bcs noboot + + inc BLOCK + inc BUFFER+1 + inc BUFFER+1 + lda BLOCK + cmp #6 + bcc :read + bra :ok + +:prodos jmp $0000 + + +:ok + + clc + xce + cli + + jsr init + +noboot +:loop wai + bra :loop + + + + + sav boot.L \ No newline at end of file diff --git a/link.S b/link.S new file mode 100644 index 0000000..30352d0 --- /dev/null +++ b/link.S @@ -0,0 +1,21 @@ + +* binary link + lkv 0 + org $0800 + + ovr all +* if boot.S + asm boot.S + +* if vt52.S + asm vt52.S + + + lnk boot.L + lnk vt52.L + + pos eof + sav vt52.bin + ent + + end diff --git a/makefile b/makefile new file mode 100644 index 0000000..26d603c --- /dev/null +++ b/makefile @@ -0,0 +1,24 @@ + + +scc.po: scc.bin + dd bs=1024 count=800 if=/dev/zero of=scc.po + dd bs=512 if=scc.bin of=scc.po conv=notrunc + +modem.po: modem.bin + dd bs=1024 count=800 if=/dev/zero of=modem.po + dd bs=512 if=modem.bin of=modem.po conv=notrunc + +vt52.po: vt52.bin + dd bs=1024 count=800 if=/dev/zero of=vt52.po + dd bs=512 if=vt52.bin of=vt52.po conv=notrunc + +vt52.bin: vt52.S boot.S link.S + iix qlink link.S + + +scc.bin: scc.s + iix qasm scc.s + +modem.bin: modem.s + iix qasm modem.s + diff --git a/modem.s b/modem.s new file mode 100644 index 0000000..13ba4c7 --- /dev/null +++ b/modem.s @@ -0,0 +1,237 @@ + + lst off + exp off + +* +* read modem port +* +* + + +cmdb equ $c038 +cmda equ $c039 +datab equ $c03a +dataa equ $c03b +cout equ $fded + + +read mac + ldx #]1 + if 3=]1 + stx cmda + lda cmda + else + stx cmdb + lda cmdb + fin + sta buffer,x + <<< + + lst on + org $0800 + + mx %11 + + db $01 ; prodos boot id + +boot +* clc +* xce +* cli + sei + + ldx #24 + lda #$80+$0d +:cs jsr cout + dex + bpl :cs + + +* just in case. + lda cmdb + lda cmdb + + +init +* reset channel b + ldx #9 + lda #%01010001 + stx cmdb + sta cmdb + nop + nop + +* x16 clock mode, 1 stop bit, no parity + ldx #4 + lda #%01000100 + stx cmdb + sta cmdb + +* 8 bits/char, rx disabled. + ldx #3 + lda #%11000000 + stx cmdb + sta cmdb + +* 8 data bits, RTS + ldx #5 + lda #%01100010 + stx cmdb + sta cmdb + + ldx #11 + lda #%01010000 + stx cmdb + sta cmdb + +* 9600 baud + ldx #12 + lda #10 + stx cmdb + sta cmdb + +* 9600 baud + ldx #13 + lda #0 + stx cmdb + sta cmdb + + +* disable baud rate generator + ldx #14 + lda #0 + stx cmdb + sta cmdb + +* enable baud rate generator + ldx #14 + lda #%00000001 + stx cmdb + sta cmdb + + + +* 8 bits/char, rx enabled. + ldx #3 + lda #%11000001 + stx cmdb + sta cmdb + + +* 8 data bits, tx enabled, RTS + ldx #5 + lda #%01101010 + stx cmdb + sta cmdb + +* disable interrupts + ldx #15 + lda #0 + stx cmdb + sta cmdb + +* reset ext/status interrupts + ldx #0 + lda #%00010000 + stx cmdb + sta cmdb + +* disable interrupts + ldx #1 + lda #0 + stx cmdb + sta cmdb + +* reset ch b ptr to 0? + lda cmdb + + +* status, visible, master interrupts disabled + ldx #9 + lda #%00010001 + stx cmdb + sta cmdb + nop + nop + + + + +* read registers - 0, 1, 2, 3, 8, 10, 12, 13, 15 +* 3 is channel A only. +loop + + + read 0 + read 1 + read 2 + read 3 + read 8 + read 10 + read 12 + read 13 + read 15 + + ldx #15 +:cmp lda buffer,x + cmp prev,x + bne :delta + dex + bpl :cmp + + bra wailoop + +:delta + + ldx #0 + +:print + lda buffer,x + phx + pha + lsr + lsr + lsr + lsr + tax + lda hex,x + jsr cout + pla + and #$0f + tax + lda hex,x + jsr cout + lda #" " + jsr cout + plx + inx + cpx #16 + bcc :print + lda #$80+$0d + jsr cout + +* store prev. values. + ldx #15 +:copy lda buffer,x + sta prev,x + dex + bpl :copy + +wailoop +* wai + brl loop + + nop + nop + stp + + +hex asc "0123456789abcdef" +buffer ds 16 +prev ds 16 + + lst off +* ds \ + ds 1024+$0800-* + + sav modem.bin \ No newline at end of file diff --git a/scc.s b/scc.s new file mode 100644 index 0000000..d65c8dc --- /dev/null +++ b/scc.s @@ -0,0 +1,142 @@ + + lst off + exp off + +* +* read slot 7 ssc card. +* +* + + +cmdb equ $c038 +cmda equ $c039 +datab equ $c03a +dataa equ $c03b +cout equ $fded + + +read mac + ldx #]1 + if 3=]1 + stx cmda + lda cmda + else + stx cmdb + lda cmdb + fin + sta buffer,x + <<< + + lst on + org $0800 + + mx %11 + + db $01 ; prodos boot id + +boot +* clc +* xce +* cli + sei + + ldx #24 + lda #$80+$0d +:cs jsr cout + dex + bpl :cs + + + +SSC equ $c088+$70 + +init +* command register - DTR+, IRQ-, TX IRQ-, ECHO-, PARITY- + lda #%0000_1011 + sta SSC+2 +*control - 9600, BRG, /1 + lda #%0_00_1_1110 + sta SSC+3 + + + +* read 4 registers +loop + + ; status first + lda SSC+1 + sta buffer+1 + + lda SSC+0 + sta buffer+0 + + lda SSC+2 + sta buffer+2 + + lda SSC+3 + sta buffer+3 + + + ldx #3 +:cmp lda buffer,x + cmp prev,x + bne :delta + dex + bpl :cmp + + bra wailoop + +:delta + + ldx #0 + +:print + lda buffer,x + phx + pha + lsr + lsr + lsr + lsr + tax + lda hex,x + jsr cout + pla + and #$0f + tax + lda hex,x + jsr cout + lda #" " + jsr cout + plx + inx + cpx #4 + bcc :print + lda #$80+$0d + jsr cout + +* store prev. values. + ldx #3 +:copy lda buffer,x + sta prev,x + dex + bpl :copy + +wailoop +* wai + brl loop + + nop + nop + stp + + +hex asc "0123456789abcdef" +buffer ds 16 +prev ds 16 + + lst off +* ds \ + ds 1024+$0800-* + + sav scc.bin \ No newline at end of file diff --git a/vt52.S b/vt52.S new file mode 100644 index 0000000..1db2fb9 --- /dev/null +++ b/vt52.S @@ -0,0 +1,589 @@ + lst off + xc + xc + rel + +* vt52 emulator. +* not supported - graphics, screen hold. +* +* +* +* + + +SET80VID equ $c00d +SETALTCHAR equ $c00f +TXTSET equ $c051 + + + ent init + + + dum 0 +text00 adrl 0 +text01 adrl 0 +state dw 0 +mode dw 0 +x dw 0 +y dw 0 + +* cursor + +cursor_ptr adrl 0 +cursor_saved_char dw 0 +cursor_state dw 0 + + + dend + +init + sep #$30 + sta TXTSET + sta SET80VID + sta SETALTCHAR + rep #$30 + + stz x + stz y + stz mode + stz state + + lda #$0400 + sta text00 + stz text00+2 + + sta text01 + lda #$0001 + sta text01+2 + + jmp clear_all + + +cc mac + ldx #38 +]loop sta ]1,x + stal $010000+]1,x + dex + dex + bpl ]loop + <<< + +cp mac + ldx #38 +]loop lda ]1,x + sta ]2,x + ldal $010000+]1,x + stal $010000+]2,x + dex + dex + bpl ]loop + <<< + + + +clear_eol + sep #$20 + lda x + lsr + tay + lda #" " + bcc :even + + sta [text01],y + iny +:even + cpy #80/2 + bcs :rts + sta (text00),y + sta [text01],y + iny + cpy #40 + bra :even +:rts rep #$20 + rts + +clear_eos + lda x + ora y + beq clear_all + + lda x + beq :x0 + jsr clear_eol + lda y + inc + bra :x1 +:x0 + lda y +:x1 cmp #23 + bcs :rts + asl + tax + lda #" " + jmp (clear_table,x) + +:rts rts + +clear_all + lda #" " ; high bit +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 + + rts + +clear_table + dw c00,c01,c02,c03,c04,c05,c06,c07,c08,c09 + dw c10,c11,c12,c13,c14,c15,c16,c17,c18,c19 + dw c20,c21,c22,c23 + + +scroll_up + + cp $0480;$0400 + cp $0500;$0480 + cp $0580;$0500 + cp $0600;$0580 + cp $0680;$0600 + cp $0700;$0680 + cp $0780;$0700 + cp $0428;$0780 + cp $04a8;$0428 + cp $0528;$04a8 + cp $05a8;$0528 + cp $0628;$05a8 + cp $06a8;$0628 + cp $0728;$06a8 + cp $07a8;$0728 + cp $0450;$07a8 + cp $04d0;$0450 + cp $0550;$04d0 + cp $05d0;$0550 + cp $0650;$05d0 + cp $06d0;$0650 + cp $0750;$06d0 + cp $07d0;$0750 + + lda #" " + cc $07d0 + rts + +scroll_down + + cp $0750;$07d0 + cp $06d0;$0750 + cp $0650;$06d0 + cp $05d0;$0650 + cp $0550;$05d0 + cp $04d0;$0550 + cp $0450;$04d0 + cp $07a8;$0450 + cp $0728;$07a8 + cp $06a8;$0728 + cp $0628;$06a8 + cp $05a8;$0628 + cp $0528;$05a8 + cp $04a8;$0528 + cp $0428;$04a8 + cp $0780;$0428 + cp $0700;$0780 + cp $0680;$0700 + cp $0600;$0680 + cp $0580;$0600 + cp $0500;$0580 + cp $0480;$0500 + cp $0400;$0480 + + lda #" " + cc $0400 + rts + + +draw_char + ; a = char to draw + ora #$80 + tax + lda y + lsr + tay + txa + bcs :x1 + + sep #$20 + sta (text00),y + rep #$20 + inc x + jmp update_cursor + +:x1 + sep #$20 + sta [text01],y + rep #$20 + lda x + cmp #79 + bcs :rts + inc x +:rts jmp update_cursor + + + + +text + dw $0400 + dw $0480 + dw $0500 + dw $0580 + dw $0600 + dw $0680 + dw $0700 + dw $0780 + dw $0428 + dw $04a8 + dw $0528 + dw $05a8 + dw $0628 + dw $06a8 + dw $0728 + dw $07a8 + dw $0450 + dw $04d0 + dw $0550 + dw $05d0 + dw $0650 + dw $06d0 + dw $0750 + dw $07d0 + + + + +* based on testing, control handling happens first. ESC within an ESC Y sequence resets to ESC state. + + +vt52 + cmp #' ' + bcs :normal + asl + tax + jmp (ctrl_table,x) +:normal + ldx state + jmp (st_table,x) + +st_table + dw state_0,state_1,state_2,state_3 + + +state_0 + and #$7f + cmp #$7f + beq :rts + jsr draw_char +:rts + rts + +state_1 ; ESC encountered + +:MIN equ '<' +:MAX equ '\' + + stz state + and #$7f + cmp #:MIN + bcc :rts + + cmp #:MAX+1 + bcs :rts + sec + sbc #:MIN + asl + tax + jmp (:table,x) +:rts + rts + +: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 + dw esc_[ ; [ + dw esc_\ ; \ + + + +state_2 ; ESC Y encountered, part 1 +* out of bounds line is ignored. + inc state + inc state + + and #$7f + sec + sbc #' ' + cmp #24 + bcs :rts + sta y + jmp update_cursor +:rts rts + +state_3 ; ESC Y encountered, part 2 +* out of bounds column is ignored. +* vt52 doc claims it moves to the rightmost column but this +* doesn't reflect actual behavior. + + stz state + + and #$7f + sec + sbc #' ' + cmp #80 + bcs :rts + sta x + jmp update_cursor +:rts rts + + + +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 +ctrl_06 +ctrl_0b +ctrl_0c +ctrl_0e +ctrl_0f +ctrl_10 +ctrl_11 +ctrl_12 +ctrl_13 +ctrl_14 +ctrl_15 +ctrl_16 +ctrl_17 +ctrl_18 +ctrl_19 +ctrl_1a +ctrl_1c +ctrl_1d +ctrl_1e +ctrl_1f + rts + +ctrl_07 ; ring the bell. + rts + +ctrl_1b ; escape - + lda #2 + sta state + rts + +ctrl_09 ; tab + + lda x + cmp #73 + bcs :one + + clc + adc #8 + and #$07!$ff + sta x + bra :update +:one + cmp #79 + bcs :rts + inc x + +:update + jmp update_cursor +:rts rts + +ctrl_0a ; line feed - cursor down w/ scroll + + lda y + cmp #23 + blt :simple + jmp scroll_down + +:simple + iny + jmp update_cursor + +ctrl_0d ; carriage return - cursor to column 0. + stz x + jmp update_cursor + +esc_A ; cursor up w/o scroll + + lda y + beq :rts + dec y + jmp update_cursor +:rts rts + +esc_B ; cursor down w/o scroll + + lda y + inc + cmp #24 + bcs :rts + inc y + jmp update_cursor +:rts rts + +esc_C ; cursor right w/o wrap + + lda x + inc + cmp #79 + bcs :rts + inc x + jmp update_cursor +:rts rts + + +esc_D ; cursor left w/o wrap +ctrl_08 ; back space - cursor left w/o wrap + + lda x + beq :rts + dec x + jmp update_cursor +:rts rts + + +esc_F ; enter graphics mode + lda #%0010 + tsb mode + rts +esc_G ; exit graphics mode + lda #%0010 + trb mode + rts + +esc_H ; cursor home + stz x + stz y + jmp update_cursor + +esc_I ; reverse line feed - cursor up w/ scroll + + lda y + bne :simple + jmp scroll_up +:simple + dec y + jmp update_cursor + + + +esc_J ; erase to end of screen + jmp clear_eos + +esc_K ; erase to end-of-line + jmp clear_eol + +esc_Y ; direct cursor addressing + lda #4 + sta state + rts + +esc_Z ; identify terminal. + ; return ESC / K + rts + +esc_[ ; enter hold screen mode + lda #%0100 + tsb mode + rts + +esc_\ ; exit hold screen mode + lda #%0100 + trb mode + rts + +esc_eq ; enter alternate keypad mode + lda #%0001 + tsb mode + rts +esc_gt ; exit alternate keypad mode + lda #%0001 + trb mode + rts + + +esc_lt ; vt100 - enter ANSI mode (exit vt52 mode). + rts + + + +update_cursor + rts + + +* lst on +* sym on + sav vt52.L +