[SeaBIOS] [PATCH 2/7] vgabios: Split vgafb_scroll() into separate move and clear functions.

Kevin O'Connor kevin at koconnor.net
Mon Apr 7 01:00:11 CEST 2014


Rewrite the low-level scroll code so that it is implemented using two
basic operations: move text and clear text.  This simplifies the
low-level code as it no longer needs to handle up scrolling vs down
scrolling.  Determining the direction of the scroll is now done in the
higher level (vgabios.c) code.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 vgasrc/vgabios.c |  63 ++++++++++++---
 vgasrc/vgabios.h |   6 +-
 vgasrc/vgafb.c   | 231 +++++++++++++++++++++++++++++--------------------------
 3 files changed, 178 insertions(+), 122 deletions(-)

diff --git a/vgasrc/vgabios.c b/vgasrc/vgabios.c
index 040a7ae..d0efc11 100644
--- a/vgasrc/vgabios.c
+++ b/vgasrc/vgabios.c
@@ -215,9 +215,20 @@ write_teletype(struct cursorpos *pcp, struct carattr ca)
     u16 nbrows = GET_BDA(video_rows);
     if (pcp->y > nbrows) {
         pcp->y--;
-        struct cursorpos ul = {0, 0, pcp->page};
-        struct cursorpos lr = {GET_BDA(video_cols)-1, nbrows, pcp->page};
-        vgafb_scroll(1, -1, ul, lr);
+
+        struct vgamode_s *vmode_g = get_current_mode();
+        if (!vmode_g)
+            return;
+
+        struct cursorpos dest = {0, 0, pcp->page};
+        struct cursorpos src = {0, 1, pcp->page};
+        struct cursorpos size = {GET_BDA(video_cols), nbrows};
+        vgafb_move_chars(vmode_g, dest, src, size);
+
+        struct cursorpos clr = {0, nbrows, pcp->page};
+        struct carattr attr = {' ', 0, 0};
+        struct cursorpos clrsize = {GET_BDA(video_cols), 1};
+        vgafb_clear_chars(vmode_g, clr, attr, clrsize);
     }
 }
 
@@ -415,18 +426,48 @@ verify_scroll(struct bregs *regs, int dir)
     u16 nbcols = GET_BDA(video_cols);
     if (lrx >= nbcols)
         lrx = nbcols - 1;
-
-    if (ulx > lrx || uly > lry)
+    int wincols = lrx - ulx + 1, winrows = lry - uly + 1;
+    if (wincols <= 0 || winrows <= 0)
         return;
 
-    int nblines = regs->al;
-    if (!nblines || nblines > lry - uly + 1)
-        nblines = lry - uly + 1;
+    struct vgamode_s *vmode_g = get_current_mode();
+    if (!vmode_g)
+        return;
 
     u8 page = GET_BDA(video_page);
-    struct cursorpos ul = {ulx, uly, page};
-    struct cursorpos lr = {lrx, lry, page};
-    vgafb_scroll(dir * nblines, regs->bh, ul, lr);
+    int clearlines = regs->al, movelines = winrows - clearlines;
+    if (!clearlines || movelines <= 0) {
+        // Clear whole area.
+        struct cursorpos clr = {ulx, uly, page};
+        struct carattr attr = {' ', regs->bh, 1};
+        struct cursorpos clrsize = {wincols, winrows};
+        vgafb_clear_chars(vmode_g, clr, attr, clrsize);
+        return;
+    }
+
+    if (dir > 0) {
+        // Normal scroll
+        struct cursorpos dest = {ulx, uly, page};
+        struct cursorpos src = {ulx, uly + clearlines, page};
+        struct cursorpos size = {wincols, movelines};
+        vgafb_move_chars(vmode_g, dest, src, size);
+
+        struct cursorpos clr = {ulx, uly + movelines, page};
+        struct carattr attr = {' ', regs->bh, 1};
+        struct cursorpos clrsize = {wincols, clearlines};
+        vgafb_clear_chars(vmode_g, clr, attr, clrsize);
+    } else {
+        // Scroll down
+        struct cursorpos dest = {ulx, uly + clearlines, page};
+        struct cursorpos src = {ulx, uly, page};
+        struct cursorpos size = {wincols, movelines};
+        vgafb_move_chars(vmode_g, dest, src, size);
+
+        struct cursorpos clr = {ulx, uly, page};
+        struct carattr attr = {' ', regs->bh, 1};
+        struct cursorpos clrsize = {wincols, clearlines};
+        vgafb_clear_chars(vmode_g, clr, attr, clrsize);
+    }
 }
 
 static void
diff --git a/vgasrc/vgabios.h b/vgasrc/vgabios.h
index 6949560..de6ae59 100644
--- a/vgasrc/vgabios.h
+++ b/vgasrc/vgabios.h
@@ -87,8 +87,10 @@ struct vgamode_s *get_current_mode(void);
 int vga_set_mode(int mode, int flags);
 
 // vgafb.c
-void vgafb_scroll(int nblines, int attr
-                  , struct cursorpos ul, struct cursorpos lr);
+void vgafb_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                      , struct cursorpos src, struct cursorpos movesize);
+void vgafb_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                       , struct carattr ca, struct cursorpos movesize);
 void vgafb_write_char(struct cursorpos cp, struct carattr ca);
 struct carattr vgafb_read_char(struct cursorpos cp);
 void vgafb_write_pixel(u8 color, u16 x, u16 y);
diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c
index 7c2570f..5a2c4c8 100644
--- a/vgasrc/vgafb.c
+++ b/vgasrc/vgafb.c
@@ -17,12 +17,16 @@
  * Screen scrolling
  ****************************************************************/
 
-static inline void *
-memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
+static inline void
+memmove_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
 {
+    if (src < dst) {
+        dst += stride * (lines - 1);
+        src += stride * (lines - 1);
+        stride = -stride;
+    }
     for (; lines; lines--, dst+=stride, src+=stride)
         memcpy_far(seg, dst, seg, src, copylen);
-    return dst;
 }
 
 static inline void
@@ -40,163 +44,172 @@ memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
 }
 
 static void
-scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
-           , struct cursorpos ul, struct cursorpos lr)
+planar_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                  , struct cursorpos src, struct cursorpos movesize)
 {
     if (!CONFIG_VGA_STDVGA_PORTS)
         return;
     int cheight = GET_BDA(char_height);
     int cwidth = 1;
     int stride = GET_BDA(video_cols) * cwidth;
-    void *src_far, *dest_far;
-    if (nblines >= 0) {
-        dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
-        src_far = dest_far + nblines * cheight * stride;
-    } else {
-        // Scroll down
-        nblines = -nblines;
-        dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
-        src_far = dest_far - nblines * cheight * stride;
-        stride = -stride;
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
+    void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth);
+    int i;
+    for (i=0; i<4; i++) {
+        stdvga_planar4_plane(i);
+        memmove_stride(SEG_GRAPH, dest_far, src_far
+                       , movesize.x * cwidth, stride, movesize.y * cheight);
     }
-    if (attr < 0)
-        attr = 0;
-    int cols = lr.x - ul.x + 1;
-    int rows = lr.y - ul.y + 1;
+    stdvga_planar4_plane(-1);
+}
+
+static void
+planar_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                   , struct carattr ca, struct cursorpos clearsize)
+{
+    if (!CONFIG_VGA_STDVGA_PORTS)
+        return;
+    int cheight = GET_BDA(char_height);
+    int cwidth = 1;
+    int stride = GET_BDA(video_cols) * cwidth;
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
     int i;
     for (i=0; i<4; i++) {
         stdvga_planar4_plane(i);
-        void *dest = dest_far;
-        if (nblines < rows)
-            dest = memcpy_stride(SEG_GRAPH, dest, src_far, cols * cwidth
-                                 , stride, (rows - nblines) * cheight);
-        u8 pixels = (attr & (1<<i)) ? 0xff : 0x00;
-        memset_stride(SEG_GRAPH, dest, pixels, cols * cwidth
-                      , stride, nblines * cheight);
+        u8 attr = (ca.attr & (1<<i)) ? 0xff : 0x00;
+        memset_stride(SEG_GRAPH, dest_far, attr
+                      , clearsize.x * cwidth, stride, clearsize.y * cheight);
     }
     stdvga_planar4_plane(-1);
 }
 
 static void
-scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
-            , struct cursorpos ul, struct cursorpos lr)
+cga_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+               , struct cursorpos src, struct cursorpos movesize)
 {
     int cheight = GET_BDA(char_height) / 2;
     int cwidth = GET_GLOBAL(vmode_g->depth);
     int stride = GET_BDA(video_cols) * cwidth;
-    void *src_far, *dest_far;
-    if (nblines >= 0) {
-        dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
-        src_far = dest_far + nblines * cheight * stride;
-    } else {
-        // Scroll down
-        nblines = -nblines;
-        dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
-        src_far = dest_far - nblines * cheight * stride;
-        stride = -stride;
-    }
-    if (attr < 0)
-        attr = 0;
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
+    void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth);
+    memmove_stride(SEG_CTEXT, dest_far, src_far
+                   , movesize.x * cwidth, stride, movesize.y * cheight);
+    memmove_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000
+                   , movesize.x * cwidth, stride, movesize.y * cheight);
+}
+
+static void
+cga_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                , struct carattr ca, struct cursorpos clearsize)
+{
+    int cheight = GET_BDA(char_height) / 2;
+    int cwidth = GET_GLOBAL(vmode_g->depth);
+    int stride = GET_BDA(video_cols) * cwidth;
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
+    u8 attr = ca.attr;
     if (cwidth == 1)
         attr = (attr&1) | ((attr&1)<<1);
     attr &= 3;
     attr |= (attr<<2) | (attr<<4) | (attr<<6);
-    int cols = lr.x - ul.x + 1;
-    int rows = lr.y - ul.y + 1;
-    if (nblines < rows) {
-        memcpy_stride(SEG_CTEXT, dest_far+0x2000, src_far+0x2000, cols * cwidth
-                      , stride, (rows - nblines) * cheight);
-        dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols * cwidth
-                                 , stride, (rows - nblines) * cheight);
-    }
-    memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols * cwidth
-                  , stride, nblines * cheight);
-    memset_stride(SEG_CTEXT, dest_far, attr, cols * cwidth
-                  , stride, nblines * cheight);
+    memset_stride(SEG_CTEXT, dest_far, attr
+                  , clearsize.x * cwidth, stride, clearsize.y * cheight);
+    memset_stride(SEG_CTEXT, dest_far + 0x2000, attr
+                  , clearsize.x * cwidth, stride, clearsize.y * cheight);
 }
 
 static void
-scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr
-           , struct cursorpos ul, struct cursorpos lr)
+packed_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                  , struct cursorpos src, struct cursorpos movesize)
 {
     int cheight = GET_BDA(char_height);
     int cwidth = 8;
     int stride = GET_BDA(video_cols) * cwidth;
-    void *src_far, *dest_far;
-    if (nblines >= 0) {
-        dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
-        src_far = dest_far + nblines * cheight * stride;
-    } else {
-        // Scroll down
-        nblines = -nblines;
-        dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
-        src_far = dest_far - nblines * cheight * stride;
-        stride = -stride;
-    }
-    if (attr < 0)
-        attr = 0;
-    int cols = lr.x - ul.x + 1;
-    int rows = lr.y - ul.y + 1;
-    if (nblines < rows)
-        dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols * cwidth
-                                 , stride, (rows - nblines) * cheight);
-    memset_stride(SEG_GRAPH, dest_far, attr, cols * cwidth
-                  , stride, nblines * cheight);
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
+    void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth);
+    memmove_stride(SEG_GRAPH, dest_far, src_far
+                   , movesize.x * cwidth, stride, movesize.y * cheight);
 }
 
 static void
-scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
-            , struct cursorpos ul, struct cursorpos lr)
+packed_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                   , struct carattr ca, struct cursorpos clearsize)
+{
+    int cheight = GET_BDA(char_height);
+    int cwidth = 8;
+    int stride = GET_BDA(video_cols) * cwidth;
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
+    memset_stride(SEG_GRAPH, dest_far, ca.attr
+                  , clearsize.x * cwidth, stride, clearsize.y * cheight);
+}
+
+static void
+text_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                , struct cursorpos src, struct cursorpos movesize)
 {
     int cheight = 1;
     int cwidth = 2;
     int stride = GET_BDA(video_cols) * cwidth;
-    void *src_far, *dest_far = (void*)(GET_BDA(video_pagesize) * ul.page);
-    if (nblines >= 0) {
-        dest_far += ul.y * cheight * stride + ul.x * cwidth;
-        src_far = dest_far + nblines * cheight * stride;
-    } else {
-        // Scroll down
-        nblines = -nblines;
-        dest_far += lr.y * cheight * stride + ul.x * cwidth;
-        src_far = dest_far - nblines * cheight * stride;
-        stride = -stride;
-    }
-    if (attr < 0)
-        attr = 0x07;
-    attr = (attr << 8) | ' ';
-    int cols = lr.x - ul.x + 1;
-    int rows = lr.y - ul.y + 1;
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
+    void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth);
+    u32 pageoffset = GET_BDA(video_pagesize) * dest.page;
+    u16 seg = GET_GLOBAL(vmode_g->sstart);
+    memmove_stride(seg, dest_far + pageoffset, src_far + pageoffset
+                   , movesize.x * cwidth, stride, movesize.y * cheight);
+}
+
+static void
+text_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                , struct carattr ca, struct cursorpos clearsize)
+{
+    int cheight = 1;
+    int cwidth = 2;
+    int stride = GET_BDA(video_cols) * cwidth;
+    void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth);
+    u16 attr = ((ca.use_attr ? ca.attr : 0x07) << 8) | ca.car;
+    u32 pageoffset = GET_BDA(video_pagesize) * dest.page;
     u16 seg = GET_GLOBAL(vmode_g->sstart);
-    if (nblines < rows)
-        dest_far = memcpy_stride(seg, dest_far, src_far, cols * cwidth
-                                 , stride, (rows - nblines) * cheight);
-    memset16_stride(seg, dest_far, attr, cols * cwidth
-                    , stride, nblines * cheight);
+    memset16_stride(seg, dest_far + pageoffset, attr
+                    , clearsize.x * cwidth, stride, clearsize.y * cheight);
 }
 
 void
-vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
+vgafb_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                 , struct cursorpos src, struct cursorpos movesize)
 {
-    // Get the mode
-    struct vgamode_s *vmode_g = get_current_mode();
-    if (!vmode_g)
-        return;
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case MM_TEXT:
+        text_move_chars(vmode_g, dest, src, movesize);
+        break;
+    case MM_PLANAR:
+        planar_move_chars(vmode_g, dest, src, movesize);
+        break;
+    case MM_CGA:
+        cga_move_chars(vmode_g, dest, src, movesize);
+        break;
+    case MM_PACKED:
+        packed_move_chars(vmode_g, dest, src, movesize);
+        break;
+    default:
+        break;
+    }
+}
 
-    // FIXME gfx mode not complete
+void
+vgafb_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+                 , struct carattr ca, struct cursorpos movesize)
+{
     switch (GET_GLOBAL(vmode_g->memmodel)) {
     case MM_TEXT:
-        scroll_text(vmode_g, nblines, attr, ul, lr);
+        text_clear_chars(vmode_g, dest, ca, movesize);
         break;
     case MM_PLANAR:
-        scroll_pl4(vmode_g, nblines, attr, ul, lr);
+        planar_clear_chars(vmode_g, dest, ca, movesize);
         break;
     case MM_CGA:
-        scroll_cga(vmode_g, nblines, attr, ul, lr);
+        cga_clear_chars(vmode_g, dest, ca, movesize);
         break;
-    case MM_DIRECT:
     case MM_PACKED:
-        scroll_lin(vmode_g, nblines, attr, ul, lr);
+        packed_clear_chars(vmode_g, dest, ca, movesize);
         break;
     default:
         break;
-- 
1.9.0




More information about the SeaBIOS mailing list