From 92ddc7ebc1630582c6408af4448577671c918d96 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Wed, 26 Feb 2020 16:27:27 -0500 Subject: [PATCH] recipes/trs80: use grid module Not much of a gain in terms of usability (a bit of a loss in fact, things are a bit slow and glitchy), but it's a necessary move if we want to use upcoming grid-enabled userspace apps, such as a visual text editor. --- kernel/grid.asm | 67 ++++++++++++++++++++++++++++++------------ kernel/trs80/vid.asm | 47 +++++++++++++++++++++++++++-- recipes/sms/glue.asm | 3 +- recipes/trs80/glue.asm | 37 +++++++++++++---------- recipes/trs80/user.h | 2 +- 5 files changed, 118 insertions(+), 38 deletions(-) diff --git a/kernel/grid.asm b/kernel/grid.asm index 3665a88..cb0fe84 100644 --- a/kernel/grid.asm +++ b/kernel/grid.asm @@ -12,8 +12,10 @@ ; can access those cells by their (X, Y) address. In addition to this, we have ; the concept of an active cursor, which will be indicated visually if possible. ; -; Additionally, this module provides a PutC routine, suitable for plugging into -; stdio. +; This module provides PutC and GetC routines, suitable for plugging into stdio. +; PutC, for obvious reasons, GetC, for less obvious reasons: We need to wrap +; GetC because we need to update the cursor before calling actual GetC, but +; also, because we need to know when a bulk update ends. ; ; *** Defines *** ; @@ -21,7 +23,9 @@ ; GRID_ROWS: Number of rows in the grid ; GRID_SETCELL: Pointer to routine that sets cell at row D and column E with ; character in A. If C is nonzero, this cell must be displayed, -; if possible, as the cursor. +; if possible, as the cursor. This routine is never called with +; A < 0x20. +; GRID_GETC: Routine that gridGetC will wrap around. ; ; *** Consts *** .equ GRID_SIZE GRID_COLS*GRID_ROWS @@ -31,6 +35,10 @@ .equ GRID_CURX GRID_RAMSTART ; Cursor's row .equ GRID_CURY @+1 +; Whether we scrolled recently. We don't refresh the screen immediately when +; scrolling in case we have many lines being spit at once (refreshing the +; display is then very slow). Instead, we wait until the next gridGetC call +.equ GRID_SCROLLED @+1 ; Grid's in-memory buffer of the contents on screen. Because we always push to ; display right after a change, this is almost always going to be a correct ; representation of on-screen display. @@ -53,7 +61,7 @@ _gridPlaceCell: ld hl, GRID_BUF ld a, d or a - ret z + jr z, .setcol push de ; --> lvl 1 ld de, GRID_COLS .loop: @@ -61,10 +69,18 @@ _gridPlaceCell: dec a jr nz, .loop pop de ; <-- lvl 1 +.setcol: ; We're at the proper row, now let's advance to cell ld a, e jp addHL +; Ensure that A >= 0x20 +_gridAdjustA: + cp 0x20 + ret nc + ld a, 0x20 + ret + ; Push row D in the buffer onto the screen. gridPushRow: push af @@ -78,6 +94,7 @@ gridPushRow: ld b, GRID_COLS .loop: ld a, (hl) + call _gridAdjustA ; A, C, D and E have proper values call GRID_SETCELL inc hl @@ -98,11 +115,10 @@ gridClrRow: push hl ld e, 0 call _gridPlaceCell - xor a + ld a, ' ' ld b, GRID_COLS call fill call gridPushRow - pop hl pop de pop bc @@ -131,6 +147,7 @@ gridSetCur: call _gridPlaceCell pop af \ push af ; <--> lvl 1 ld (hl), a + call _gridAdjustA call GRID_SETCELL pop af ; <-- lvl 1 pop hl @@ -166,19 +183,10 @@ gridLF: push de push af ld a, (GRID_CURY) - call .incA - ld d, a - call gridClrRow - ld (GRID_CURY), a - xor a - ld (GRID_CURX), a - pop af - pop de - ret -.incA: + ; increase A inc a cp GRID_ROWS - ret nz ; no rollover + jr nz, .noscroll ; bottom reached, stay on last line and scroll screen push hl push de @@ -187,11 +195,21 @@ gridLF: ld hl, GRID_BUF+GRID_COLS ld bc, GRID_SIZE-GRID_COLS ldir + ld hl, GRID_SCROLLED + inc (hl) ; mark as scrolled pop bc pop de pop hl - call gridPushScr dec a +.noscroll: + ; A has been increased properly + ld d, a + call gridClrRow + ld (GRID_CURY), a + xor a + ld (GRID_CURX), a + pop af + pop de ret gridBS: @@ -242,3 +260,16 @@ gridPutC: call gridLF pop af ; <-- lvl 1 ret + +gridGetC: + ld a, (GRID_SCROLLED) + or a + jr z, .nopush + ; We've scrolled recently, update screen + xor a + ld (GRID_SCROLLED), a + call gridPushScr +.nopush: + ld a, ' ' + call gridSetCurH + jp GRID_GETC diff --git a/kernel/trs80/vid.asm b/kernel/trs80/vid.asm index 9ba6e7c..b58b04f 100644 --- a/kernel/trs80/vid.asm +++ b/kernel/trs80/vid.asm @@ -1,7 +1,9 @@ ; vid - TRS-80's video ; -; Implement PutC using TRS-80's SVC calls so that character it put on video -; display. +; Implement PutC and GRID_SETCELL using TRS-80's SVC calls. + +.equ TRS80_COLS 80 +.equ TRS80_ROWS 24 trs80PutC: push af @@ -14,3 +16,44 @@ trs80PutC: pop bc pop af ret + +trs80SetCell: + push af + push bc + push hl ; HL altered by @VDCTL + push de ; DE altered by @VDCTL + ex de, hl + bit 0, c + ld c, a ; save A now + jr z, .skip ; Z from BIT above. cursor not set + ; set cursor + ld a, 0x0f ; @VDCTL + ld b, 3 ; move cursor fn + rst 0x28 + ; HL altered. + ; Our Row/Col is our currently-pushed DE value. Let's take advantage of + ; that. + pop hl \ push hl ; HL altered. bring back from stack +.skip: + ld a, 0x0f ; @VDCTL + ld b, 2 ; display char + rst 0x28 + pop de + pop hl + pop bc + pop af + ret + +; This is a much faster version of gridPushScr. Use it in your glue code, but +; you need to set HL to GRID_BUF first. +trs80PushScr: + push af + push bc + ld a, 0x0f ; @VDCTL + ld b, 5 ; move from RAM to vid + ; HL is already set by caller + rst 0x28 + pop bc + pop af + cp a ; ensure Z + ret diff --git a/recipes/sms/glue.asm b/recipes/sms/glue.asm index 9836ed8..173a87d 100644 --- a/recipes/sms/glue.asm +++ b/recipes/sms/glue.asm @@ -21,10 +21,11 @@ .equ GRID_COLS VDP_COLS .equ GRID_ROWS VDP_ROWS .equ GRID_SETCELL vdpSetCell +.equ GRID_GETC padGetC .inc "grid.asm" .equ STDIO_RAMSTART GRID_RAMEND -.equ STDIO_GETC padGetC +.equ STDIO_GETC gridGetC .equ STDIO_PUTC gridPutC .inc "stdio.asm" diff --git a/recipes/trs80/glue.asm b/recipes/trs80/glue.asm index 7f8a124..45ee553 100644 --- a/recipes/trs80/glue.asm +++ b/recipes/trs80/glue.asm @@ -2,17 +2,13 @@ .equ RAMEND 0xcfff ; Address of the *CL driver. Same as in recv.asm .equ COM_DRV_ADDR 0x0238 -; in sync with user.h. Last BAS_RAMEND: 0x5705 -.equ USER_CODE 0x5800 +; in sync with user.h. Last BAS_RAMEND: 0x600b +.equ USER_CODE 0x6100 ; Free memory in TRSDOS starts at 0x3000 .org 0x3000 jp init -; The TRS-80 generates a double line feed if we give it both CR and LF. -; Has to be defined before the jump table. -.equ printcrlf printcr - ; *** Jump Table *** jp strncmp jp upcase @@ -45,7 +41,14 @@ .equ FLOPPY_RAMSTART RAMSTART .inc "trs80/floppy.asm" -.equ BLOCKDEV_RAMSTART FLOPPY_RAMEND +.equ GRID_RAMSTART FLOPPY_RAMEND +.equ GRID_ROWS TRS80_ROWS +.equ GRID_COLS TRS80_COLS +.equ GRID_SETCELL trs80SetCell +.equ GRID_GETC trs80GetC +.equ gridPushScr fastPushScr +.inc "grid.asm" +.equ BLOCKDEV_RAMSTART GRID_RAMEND .equ BLOCKDEV_COUNT 3 .inc "blockdev.asm" ; List of devices @@ -54,8 +57,9 @@ .dw blk2GetB, blk2PutB .equ STDIO_RAMSTART BLOCKDEV_RAMEND -.equ STDIO_GETC trs80GetC -.equ STDIO_PUTC trs80PutC +.equ STDIO_GETC gridGetC +.equ STDIO_PUTC gridPutC +.equ STDIO_SETCUR gridSetCurH .inc "stdio.asm" .equ FS_RAMSTART STDIO_RAMEND @@ -91,6 +95,7 @@ init: ld sp, RAMEND + call gridInit call floppyInit call fsInit call basInit @@ -103,13 +108,6 @@ init: jp basStart -printcr: - push af - ld a, CR - call STDIO_PUTC - pop af - ret - ; Receive a byte from *cl and put it in A. ; Returns A > 0xff when receiving the last byte recvCmd: @@ -172,6 +170,13 @@ basFindCmdExtra: .dw recvCmd .db 0xff ; end of table +fastPushScr: + push hl + ld hl, GRID_BUF + call trs80PushScr + pop hl + ret + ; *** blkdev 1: file handle 0 *** blk1GetB: diff --git a/recipes/trs80/user.h b/recipes/trs80/user.h index c70d16b..ea53683 100644 --- a/recipes/trs80/user.h +++ b/recipes/trs80/user.h @@ -1,4 +1,4 @@ -.org 0x5800 +.org 0x6100 .equ strncmp 0x3003 .equ upcase @+3 .equ findchar @+3