From 55220e41c17b8e9dd140f1c770d4885e317d160b Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Tue, 7 Apr 2026 06:14:30 -0400 Subject: Shave a few bytes from complete.c. 6991 bytes free. --- doc/dynamic-screens.txt | 104 ++++++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 43 deletions(-) (limited to 'doc') diff --git a/doc/dynamic-screens.txt b/doc/dynamic-screens.txt index 63d2f7c..065f28c 100644 --- a/doc/dynamic-screens.txt +++ b/doc/dynamic-screens.txt @@ -102,8 +102,8 @@ Line - 42 bytes of memory that store 40 characters (one GR.0 line) of (bottom-most points to the 2nd-to-bottom, etc, and the top one in a screen points to the End Marker). Lines in the free list are also stored as a linked list, associated with the pool, not any screen. - A single line cannot cross a 4K boundary, because ANTIC wouldn't - be able to display it properly. + Lines can cross 4K boundaries because they're not directly displayed + by ANTIC. Free Line - a line that isn't being used by any screen. All the free lines in a pool are a linked list: initializing the pool @@ -212,42 +212,31 @@ and add the screen's line count to the pool's free line count. Displaying the screen: -All the screens share the same display list, which lives in main memory. - -The display list has an LMS for every line. The top 23 lines are for -the screen, the bottom two are the status bar or edit box (always the -same address; stored in main menory). - -The LMS operands get set like so: +All the screens share the same display list, which lives in main +memory. This display list is 23 lines of GR.0 text, with an LMS at the +top, and 2 lines at the bottom which are either the edit box (2 GR.0 +lines) or the status bar (one GR.0 line, one GR.1). The top LMS points +to a 920-byte (23 line) buffer in main (non-bankable) memory. This +buffer gets line data copied to it from the screen's lines. Switch to the screen's bank, then... -Starting at the screen's 'head' line, and the last LMS (bottom of -23-line area of the DL), walk the linked list of lines (which are in -bottom-first order) and the display list (backwards). - -If we're scrolled up, just keep walking as many lines as we're -scrolled up (e.g. 23 for one chunk). +Starting at the screen's 'head' line, walk the linked list [scroll +height] times (0 if we're not scrolled up, 23 if we're scrolled up +one chunk, etc). This brings us to the first line that should be +displayed. When we've walked to the first (bottom-most) line to display (which will -be the 'head' one, if we weren't scrolled back), write its address as -the current LMS's 16-bit operand, then move on to the next line -and the next LMS... - -Repeat until we hit the end of the screen (the line count), or we -hit 23 LMSes. At this point, we're done. +be the 'head' one, if we weren't scrolled back), copy its data to the +bottom line of the buffer, then move on to the next line of the screen +and the next line of the buffer. -Ideally, we'll double-buffer the display list (2 of them, one -displaying while the other's being rewritten), and switch to the newly -modified one during the next VBLANK (just update SDLSTL/H and let -the OS do it). Note that we *don't* have to deal with banking in the -display list: we can only show one screen at a time, so we don't need -to bankswitch. - -Switching screens, or scrolling back the current screen, will require -rebuilding the display list. There's no need to rebuild it every -frame (there'll be a 'dirty' flag that gets set when switching or -scrolling). +Repeat until we've done 23 lines. Remember that the last (oldest, +topmost) line of the screen points to the end marker, which points +to itself. If we're scrolled up past the last real line, we just get +copies of the marker line data in the top lines of the buffer (which +will likely consist of an inverse ~ and 39 blanks, at least during +testing, so we can see it). Scrolling the screen up (or down) is just a matter of setting the screen's scroll height. It should *never* be set higher than the @@ -258,8 +247,28 @@ one chunk will show lines 1 to 7 at the bottom, then the rest of the display (the top 2/3s or so) will all be the End Marker line, which appears blank. At that point, it won't be possible to scroll again: We're at 23, adding another 23 would exceed the height of 30 lines, -so the attempt is just ignored). - +so the attempt is just ignored. + +One wrinkle: while writing new text to the current-displayed screen, +when scroll height is 0 (we're not scrolled back), both the screen's +line and the bottom line of the buffer need to get the data written to +them. This avoids recopying the whole 23-line screen to the buffer on +every printed character (which would be painfully slow). We won't have +to recreate the whole buffer until we reach the end of the line. + +Refreshing the buffer involves writing 960 bytes to it, so it won't be +all that fast, but it'll be faster than the current fixed-screen code +(which scrolls 50 or 73 lines every time, 2000 or 2920 bytes, even in +screens that aren't currently displayed). + +It would potentially be faster to do without the buffer, and just have +a DL with an LMS for each line... but then we'd be displaying screen +memory straight from extended banks, and we'd have to have some fancy +synchronization going on when we're displaying a screen in one bank +and writing to one that lives in another bank (would have to copy data +only during the time ANTIC isn't reading screen memory). I may revisit +this at some point, but using a buffer in main memory is much simpler +(though it costs about 1K). Memory layouts for typical machine sizes... @@ -340,6 +349,13 @@ Milestones: things that will have to happen to make this a reality. 6. Add support for more banks (detection and use). +TODO: should there be a way to move a screen from one pool to another? +Imagine, user with 128K opens a bunch of screens, then happens to +close all the ones in e.g. bank 2. The screens in banks 0/1/3/4 are +still competing for lines, and we have a whole empty bank we don't +use until another screen gets opened... it would be an expensive +operation, and when exactly would we check for it? + Rest of the file is C structs that define the stuff above. This is just hypothetical code (final implementation may look different). @@ -352,7 +368,8 @@ just hypothetical code (final implementation may look different). /* with 512K, we get one screen per pool. with 256K, up to 2 screens per pool. with 128K, up to 4. - with 64K, we only get 1 large pool and a couple small ones. + with 64K, we only get 1 large pool. + with 48K, we only get 1 pool. */ #define MAX_SCREENS 32 @@ -369,17 +386,19 @@ typedef struct line_s { typedef struct { char title[25]; char status; - char pool; + char pool; /* this could be a pool_t * instead */ int line_count; /* can be above 255 */ - int scrollback_pos; line_t *line_list; /* head of a linked list */ + int scrollback_pos; /* also can be >255 */ } screen_t; screen_t screens[MAX_SCREENS]; /* array is 1023 bytes */ typedef struct { - u16 start; /* 0 = not in use */ - u16 end; + // I don't think we even need these: + // u16 start; /* 0 = not in use */ + // u16 end; + char screen_count; /* maybe set to $ff for "not in use" */ u8 bank; /* probably this is just the PORTB value */ line_t *free_list; /* when this is null, the pool has no free lines */ } pool_t; @@ -389,8 +408,7 @@ typedef struct { will live in the config segment. */ pool_t pools[MAX_POOLS]; -/* this function is responsible for counting the usable lines (the ones - that don't cross a 4K boundary) and arranging them in a linked list - that includes all the usable ones. I suppose it should bzero() the - memory first. */ +/* this function is responsible for counting the lines and arranging + them in a linked list. it zeroes the 40 character bytes in each + line and sets the other 2 as a pointer to the next. */ void add_pool(u8 bank, u16 start, u16 end); -- cgit v1.2.3