From 6c1d26ad2106e0799e376480025c77528494959d Mon Sep 17 00:00:00 2001 From: Henrik L Date: Tue, 2 Jan 2024 13:35:14 +0100 Subject: [PATCH] Added vt52 driver + tester application --- apps/build.py | 2 + apps/vt52drv.asm | 477 ++++++++++++++++++++++++++++++++++++++++++++++ apps/vt52test.asm | 218 +++++++++++++++++++++ config.py | 4 +- 4 files changed, 700 insertions(+), 1 deletion(-) create mode 100644 apps/vt52drv.asm create mode 100644 apps/vt52test.asm diff --git a/apps/build.py b/apps/build.py index e447d1d7..24ccdc37 100644 --- a/apps/build.py +++ b/apps/build.py @@ -30,6 +30,8 @@ def asm(self, name, src: Target = None, deps: Targets = []): "ls", "scrntest", "xrecv", + "vt52drv", + "vt52test", ]: asm(name=prog, src=("./%s.asm" % prog), deps=["./cpm65.inc", "./drivers.inc"]) diff --git a/apps/vt52drv.asm b/apps/vt52drv.asm new file mode 100644 index 00000000..778ff22f --- /dev/null +++ b/apps/vt52drv.asm @@ -0,0 +1,477 @@ +\ This file is licensed under the terms of the 2-clause BSD license. Please +\ see the COPYING file in the root project directory for the full text. + +.include "cpm65.inc" +.include "drivers.inc" + +.expand 1 + +.label entry +.label next +.label noscreen +.label SCREEN +.label par_done +.label mescdone + +ESC = 0x1b +BELL = 0x07 +BACKSPACE = 0x08 +TAB = 0x09 +CR = 0x0d +LF = 0x0a + +\ --- Resident part starts at the top of the file --------------------------- + +.bss max_x,1 +.bss max_y,1 +.bss cur_x,1 +.bss cur_y,1 +.bss mEsc, 1 +.bss parse, 1 +.bss cnt, 1 +.bss inp, 1 +.zproc start + jmp entry +.zendproc + +driver: + .word DRVID_TTY + .word strategy + .word 0 + .byte "VT52TTY", 0 + +.zproc strategy + cpy #TTY_CONOUT + .zif eq + sta inp + ldy #SCREEN_GETCURSOR + jsr SCREEN + sta cur_x + stx cur_y + lda #1 + sta parse + + lda inp + + cmp #32 + .zif cs + cmp #127 + .zif cc + lda mEsc + + cmp #0 + .zif eq + \ Regular ASCII + lda inp + ldy #SCREEN_PUTCHAR + jsr SCREEN + inc cur_x + lda cur_x + cmp max_x + .zif cs + lda #0 + sta cur_x + inc cur_y + .zendif + lda cur_x + ldx cur_y + ldy #SCREEN_SETCURSOR + jsr SCREEN + lda #0 + sta parse + jmp mescdone + .zendif + + cmp #1 + .zif eq + \ escape sequence. Do nothing + jmp mescdone + .zendif + + cmp #2 + .zif eq + \ First part of cursor adressing + lda inp + sta mEsc + lda #0 + sta parse + jmp mescdone + .zendif + + \ All other values - second part of cursor adressing + sec + lda inp + sbc #32 + sta cur_x + + sec + lda mEsc + sbc #32 + sta cur_y + + lda cur_x + ldx cur_y + ldy #SCREEN_SETCURSOR + jsr SCREEN + + lda #0 + sta parse + sta mEsc + + mescdone: + .zendif + .zendif + + lda inp + cmp #127 + .zif eq + lda #BACKSPACE + sta inp + .zendif + + lda parse + cmp #1 + .zif eq + lda inp + + cmp #CR + .zif eq + lda #0 + sta cur_x + jmp par_done + .zendif + + cmp #LF + .zif eq + inc cur_y + lda cur_y + cmp max_y + .zif cs + lda max_y + sta cur_y + ldy #SCREEN_SCROLLUP + jsr SCREEN + .zendif + jmp par_done + .zendif + + cmp #BACKSPACE + .zif eq + dec cur_x + lda cur_x + ldx cur_y + ldy #SCREEN_SETCURSOR + jsr SCREEN + lda #' ' + ldy #SCREEN_PUTCHAR + jsr SCREEN + jmp par_done + .zendif + + cmp #TAB + .zif eq + \ Tab to be implemented, need to figure out how to do mod 8 + lda cur_x + clc + adc #8 + and #0xf8 + cmp max_x + .zif cs + lda max_x + .zendif + sta cur_x + jmp par_done + .zendif + + cmp #ESC + .zif eq + \ Start of escape sequence + lda #1 + sta mEsc + jmp par_done + .zendif + + cmp #'A' + .zif eq + \ Cursor up + lda #0 + sta mEsc + + lda cur_y + .zif ne + dec cur_y + .zendif + jmp par_done + .zendif + + cmp #'B' + .zif eq + \ Cursow down + lda #0 + sta mEsc + lda cur_y + cmp max_y + .zif ne + inc cur_y + .zendif + jmp par_done + .zendif + + cmp #'C' + .zif eq + \ Cursor right + lda #0 + sta mEsc + lda cur_x + cmp max_x + .zif ne + inc cur_x + .zendif + jmp par_done + .zendif + + cmp #'D' + .zif eq + \ Cursor left + lda #0 + sta mEsc + lda cur_x + .zif ne + dec cur_x + .zendif + jmp par_done + .zendif + + cmp #'F' + .zif eq + \ Enter graphics mode, ignore + lda #0 + sta mEsc + jmp par_done + .zendif + + cmp #'G' + .zif eq + \ Exit graphics mode, ignore + lda #0 + sta mEsc + jmp par_done + .zendif + + cmp #'H' + .zif eq + \ Cursor home + lda #0 + sta mEsc + sta cur_x + sta cur_y + jmp par_done + .zendif + + cmp #'I' + .zif eq + \ Reverse line feed + lda #0 + sta mEsc + lda cur_y + .zif ne + dec cur_y + jmp par_done + .zendif + lda #0 + sta cur_y + ldy #SCREEN_SCROLLDOWN + jsr SCREEN + jmp par_done + .zendif + + cmp #'J' + .zif eq + \ Erase to end of screen + lda #0 + sta mEsc + ldy #SCREEN_CLEARTOEOL + jsr SCREEN + ldx cur_y + cpx max_y + beq par_done + inx + .zloop + stx cnt + lda #0 + ldy #SCREEN_SETCURSOR + jsr SCREEN + + ldy #SCREEN_CLEARTOEOL + jsr SCREEN + ldx cnt + inx + cpx max_y + .zbreak cs + .zendloop + jmp par_done + .zendif + + cmp #'K' + .zif eq + \ Erase to end of line + lda #0 + sta mEsc + ldy #SCREEN_CLEARTOEOL + jsr SCREEN + jmp par_done + .zendif + + cmp #'Y' + .zif eq + \ Cursor addressing + lda #2 + sta mEsc + jmp par_done + .zendif + + cmp #'[' + .zif eq + \ Enter hold screen mode, ignore + lda #0 + sta mEsc + jmp par_done + .zendif + + cmp #'\\' + .zif eq + \ Exit hold screen mode, ignore + lda #0 + sta mEsc + jmp par_done + .zendif + + cmp #'=' + .zif eq + \ Enter alternate keypad mode, ignore + lda #0 + sta mEsc + jmp par_done + .zendif + + cmp #'>' + .zif eq + \ Exit alternate keypad mode, ignore + lda #0 + sta mEsc + jmp par_done + .zendif + + + par_done: + lda cur_x + ldx cur_y + ldy #SCREEN_SETCURSOR + jsr SCREEN + + .zendif + rts + .zendif + \lda inp + jmp (next) +.zendproc + +SCREEN: + jmp 0 + +next: .word 0 + +\ --- Resident part stops here ------------------------------------------- + +.zproc entry + + ldy #BDOS_GET_BIOS + jsr BDOS + sta BIOS+1 + stx BIOS+2 + + \ Find SCREEN driver and place the jump to it in the resident part + lda #DRVID_SCREEN + ldy #BIOS_FINDDRV + jsr BIOS + + \ Print error message and exit if not found + .zif cs + lda #noscreen + ldy #BDOS_PRINTSTRING + jsr BDOS + rts + .zendif + + sta SCREEN+1 + stx SCREEN+2 + + lda #banner + ldy #BDOS_PRINTSTRING + jsr BDOS + + \ Get screen size and store in resident variables + ldy #SCREEN_GETSIZE + jsr SCREEN + sta max_x + stx max_y + + \ Initialize resident variables + lda #0 + sta mEsc + + \ Find the old TTY driver strategy routine and save it. + + lda #DRVID_TTY + ldy #BIOS_FINDDRV + jsr BIOS + .zif cc + sta next+0 + stx next+1 + + \ Register the new TTY driver. + + lda #driver + ldy #BIOS_ADDDRV + jsr BIOS + .zif cc + + \ Our driver uses no ZP, so we don't need to adjust that. But it does use + \ TPA. + + ldy #BIOS_GETTPA + jsr BIOS + clc + adc #4 \ Allocate 4 pages. We should be using entry to calculate this, but + \ the assembler can't do that yet. + ldy #BIOS_SETTPA + jsr BIOS + + \ Finished --- don't even need to warm boot. + + rts + .zendif + .zendif + + lda #failed + ldy #BDOS_PRINTSTRING + jmp BDOS + +banner: + .byte "The TTY driver is now VT52 capable", 13, 10, 0 +failed: + .byte "Failed!", 13, 10, 0 +noscreen: + .byte "SCREEN driver not found!", 13, 10, 0 +BIOS: + jmp 0 + +\ vim: sw=4 ts=4 et + + diff --git a/apps/vt52test.asm b/apps/vt52test.asm new file mode 100644 index 00000000..0abb7324 --- /dev/null +++ b/apps/vt52test.asm @@ -0,0 +1,218 @@ +\ Screen driver tester for CP/M-65 - Copyright (C) 2023 Henrik Lofgren +\ This file is licensed under the terms of the 2-clause BSD license. Please +\ see the COPYING file in the root project directory for the full text. + +.include "cpm65.inc" +.include "drivers.inc" + +.expand 1 + +.label string_init +.label string_up +.label string_down +.label string_right +.label string_left +.label string_home +.label string_rev_lf +.label string_cl_end +.label string_cl_line +.label string_cur_addr + +.zproc start + +help: + \ Print help + lda #string_init + ldy #BDOS_PRINTSTRING + jsr BDOS + +mainloop: + \ Get and parse command + ldx #0xfd + ldy #BDOS_CONIO + jsr BDOS + + \ Convert to uppercase + cmp #0x61 + bcc case_done + cmp #0x7a + bcs case_done + sec + sbc #0x20 + +case_done: + \ Cursor left + cmp #'A' + .zif eq + lda #string_left + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Cursor right + cmp #'D' + .zif eq + lda #string_right + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Cursor up + cmp #'W' + .zif eq + lda #string_up + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Cursor down + cmp #'S' + .zif eq + lda #string_down + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Cursor home + cmp #'H' + .zif eq + lda #string_home + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Reverse linefeed + cmp #'I' + .zif eq + lda #string_rev_lf + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Clear to end of screen + cmp #'J' + .zif eq + lda #string_cl_end + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Clear to end of line + cmp #'K' + .zif eq + lda #string_cl_line + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Cursor addressing + cmp #'Y' + .zif eq + lda #string_cur_addr + ldy #BDOS_PRINTSTRING + jsr BDOS + jmp mainloop + .zendif + + \ Tab + cmp #'T' + .zif eq + lda #0x09 + ldy #BDOS_CONOUT + jsr BDOS + jmp mainloop + .zendif + + \ Backspace + cmp #'B' + .zif eq + lda #0x08 + ldy #BDOS_CONOUT + jsr BDOS + jmp mainloop + .zendif + + \ CR + cmp #'C' + .zif eq + lda #0x0d + ldy #BDOS_CONOUT + jsr BDOS + jmp mainloop + .zendif + + \ LF + cmp #'L' + .zif eq + lda #0x0a + ldy #BDOS_CONOUT + jsr BDOS + jmp mainloop + .zendif + + \ Print help + cmp #'P' + beq help + + \ Quit + cmp #'Q' + .zif eq + rts + .zendif + + jmp mainloop +.zendproc + +string_init: + .byte "CP/M-65 VT52 driver tester\r\n\r\n" + .byte "W,A,S,D - Move cursor\r\n" + .byte "H - Cursor home\r\n" + .byte "I - Reverse linefeed\r\n" + .byte "J - Clear to end of screen\r\n" + .byte "K - Clear to end of line\r\n" + .byte "Y - Cursor addressing\r\n" + .byte "T - Tab\r\n" + .byte "B - Backspace\r\n" + .byte "C - Carriage return\r\n" + .byte "L - Linefeed\r\n" + .byte "P - Print this help\r\n" + .byte "Q - Quit\r\n" + .byte 0 + +string_up: + .byte 27,'A',0 +string_down: + .byte 27,'B',0 +string_right: + .byte 27,'C',0 +string_left: + .byte 27,'D',0 +string_home: + .byte 27,'H',0 +string_rev_lf: + .byte 27,'I',0 +string_cl_end: + .byte 27,'J',0 +string_cl_line: + .byte 27,'K',0 +string_cur_addr: + .byte 27,'Y',46,63,0 + diff --git a/config.py b/config.py index a2efed1c..a61c6c40 100644 --- a/config.py +++ b/config.py @@ -24,7 +24,7 @@ "0:atbasic.com": "third_party/altirrabasic", "0:objdump.com": "apps+objdump", "0:scrntest.com": "apps+scrntest", - "0:vt52term.com": "apps+vt52term", + "0:vt52term.com": "apps+vt52term", } BIG_APPS_SRCS = {} @@ -33,6 +33,8 @@ "0:cls.com": "apps+cls", "0:life.com": "apps+life", "0:qe.com": "apps+qe", + "0:vt52drv.com": "apps+vt52drv", + "0:vt52test.com": "apps+vt52test", } SCREEN_APPS_SRCS = {"0:cls.asm": "apps/cls.asm"}