[SeaBIOS] [PATCH 2/2] vgabios: implement read char in graphics mode

Paolo Bonzini pbonzini at redhat.com
Fri Jan 2 20:16:46 CET 2015



On 02/01/2015 18:43, Kevin O'Connor wrote:
> On Thu, Jan 01, 2015 at 09:27:47PM +0100, Paolo Bonzini wrote:
>> GWBasic relies on this, so implement it to enable some serious retrocomputing.
>> There is no better way to do it than trying to match all characters one by one
>> against the current font.
>>
>> This makes it possible to actually do something in SCREEN 1 and SCREEN 2
>> (without it, you can use graphics in the programs but not in direct mode).
>>
>> I couldn't find documentation for what to return as the attribute, but
>> experimenting with DOSBox suggests 0 (and GWBasic accepts it).
> 
> Your patch works fine and matches what ATI and Intel seem to do.  But,
> I couldn't help tinkering with it.  Are you okay with the patch below?
> 
> -Kevin

Sure!

Paolo

> 
> 
> commit a5d54337852f26abeed1c2baa517d1870a641174
> Author: Paolo Bonzini <pbonzini at redhat.com>
> Date:   Fri Jan 2 12:32:25 2015 -0500
> 
>     vgabios: implement read char in graphics mode
>     
>     GWBasic relies on this, so implement it to enable some serious retrocomputing.
>     There is no better way to do it than trying to match all characters one by one
>     against the current font.
>     
>     This makes it possible to actually do something in SCREEN 1 and SCREEN 2
>     (without it, you can use graphics in the programs but not in direct mode).
>     
>     I couldn't find documentation for what to return as the attribute, but
>     experimenting with DOSBox suggests 0 (and GWBasic accepts it).
>     
>     Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
>     Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
> 
> diff --git a/src/string.c b/src/string.c
> index 8556fe9..2e4e437 100644
> --- a/src/string.c
> +++ b/src/string.c
> @@ -42,6 +42,19 @@ strlen(const char *s)
>      return p-s;
>  }
>  
> +int
> +memcmp_far(u16 s1seg, const void *s1, u16 s2seg, const void *s2, size_t n)
> +{
> +    while (n--) {
> +        int d = GET_FARVAR(s1seg, *(u8*)s1) - GET_FARVAR(s2seg, *(u8*)s2);
> +        if (d)
> +            return d < 0 ? -1 : 1;
> +        s1++;
> +        s2++;
> +    }
> +    return 0;
> +}
> +
>  // Compare two areas of memory.
>  int
>  memcmp(const void *s1, const void *s2, size_t n)
> diff --git a/src/string.h b/src/string.h
> index ca751a4..a557d6a 100644
> --- a/src/string.h
> +++ b/src/string.h
> @@ -8,6 +8,7 @@
>  u8 checksum_far(u16 buf_seg, void *buf_far, u32 len);
>  u8 checksum(void *buf, u32 len);
>  size_t strlen(const char *s);
> +int memcmp_far(u16 s1seg, const void *s1, u16 s2seg, const void *s2, size_t n);
>  int memcmp(const void *s1, const void *s2, size_t n);
>  int strcmp(const char *s1, const char *s2);
>  inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
> diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c
> index 59ddc56..4bbbc16 100644
> --- a/vgasrc/vgafb.c
> +++ b/vgasrc/vgafb.c
> @@ -454,6 +454,43 @@ gfx_write_char(struct vgamode_s *vmode_g
>      }
>  }
>  
> +// Read a character from the screen in graphics mode.
> +static struct carattr
> +gfx_read_char(struct vgamode_s *vmode_g, struct cursorpos cp)
> +{
> +    u8 lines[16];
> +    int cheight = GET_BDA(char_height);
> +    if (cp.x >= GET_BDA(video_cols) || cheight > ARRAY_SIZE(lines))
> +        goto fail;
> +
> +    // Read cell from screen
> +    struct gfx_op op;
> +    init_gfx_op(&op, vmode_g);
> +    op.op = GO_READ8;
> +    op.x = cp.x * 8;
> +    op.y = cp.y * cheight;
> +    u8 i, j;
> +    for (i=0; i<cheight; i++, op.y++) {
> +        u8 line = 0;
> +        handle_gfx_op(&op);
> +        for (j=0; j<8; j++)
> +            if (op.pixels[j])
> +                line |= 0x80 >> j;
> +        lines[i] = line;
> +    }
> +
> +    // Determine font
> +    u16 car;
> +    for (car=0; car<256; car++) {
> +        struct segoff_s font = get_font_data(car);
> +        if (memcmp_far(GET_SEG(SS), lines
> +                       , font.seg, (void*)(font.offset+0), cheight) == 0)
> +            return (struct carattr){car, 0, 0};
> +    }
> +fail:
> +    return (struct carattr){0, 0, 0};
> +}
> +
>  // Draw/undraw a cursor on the framebuffer by xor'ing the cursor cell
>  void
>  gfx_set_swcursor(struct vgamode_s *vmode_g, int enable, struct cursorpos cp)
> @@ -607,23 +644,15 @@ vgafb_read_char(struct cursorpos cp)
>  {
>      struct vgamode_s *vmode_g = get_current_mode();
>      if (!vmode_g)
> -        goto fail;
> +        return (struct carattr){0, 0, 0};
>      vgafb_set_swcursor(0);
>  
> -    if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
> -        // FIXME gfx mode
> -        dprintf(1, "Read char in graphics mode\n");
> -        goto fail;
> -    }
> +    if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT)
> +        return gfx_read_char(vmode_g, cp);
>  
>      u16 *dest_far = text_address(cp);
>      u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *dest_far);
> -    struct carattr ca = {v, v>>8, 0};
> -    return ca;
> -
> -fail: ;
> -    struct carattr ca2 = {0, 0, 0};
> -    return ca2;
> +    return (struct carattr){v, v>>8, 0};
>  }
>  
>  // Draw/undraw a cursor on the screen
> 



More information about the SeaBIOS mailing list