[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