// TODO:
-// * remove recursion from biosfn_write_teletype()
// * review correctness of converted asm by comparing with RBIL
// * refactor redundant code into sub-functions
// * See if there is a method to the in/out stuff that can be encapsulated.
#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
-
-// ===================================================================
-//
-// Video Utils
-//
-// ===================================================================
-
-// -------------------------------------------------------------------
inline void
call16_vgaint(u32 eax, u32 ebx)
{
: "cc", "memory");
}
-
-// ===================================================================
-//
-// BIOS functions
-//
-// ===================================================================
-
-// -------------------------------------------------------------------
static void
biosfn_perform_gray_scale_summing(u16 start, u16 count)
{
vgahw_screen_enable();
}
-// -------------------------------------------------------------------
static void
biosfn_set_cursor_shape(u8 CH, u8 CL)
{
return GET_BDA(cursor_type);
}
-// -------------------------------------------------------------------
static void
-biosfn_set_cursor_pos(u8 page, u16 cursor)
+set_cursor_pos(struct cursorpos cp)
{
// Should not happen...
- if (page > 7)
+ if (cp.page > 7)
return;
// Bios cursor pos
- SET_BDA(cursor_pos[page], cursor);
+ SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
// Set the hardware cursor
u8 current = GET_BDA(video_page);
- if (page != current)
+ if (cp.page != current)
return;
// Get the dimensions
u16 nbcols = GET_BDA(video_cols);
u16 nbrows = GET_BDA(video_rows) + 1;
- u8 xcurs = cursor & 0x00ff;
- u8 ycurs = (cursor & 0xff00) >> 8;
-
// Calculate the address knowing nbcols nbrows and page num
- u16 address = SCREEN_IO_START(nbcols, nbrows, page) + xcurs + ycurs * nbcols;
+ u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
+ + cp.x + cp.y * nbcols);
vgahw_set_cursor_pos(address);
}
-u16
-biosfn_get_cursor_pos(u8 page)
+struct cursorpos
+get_cursor_pos(u8 page)
{
- if (page > 7)
- return 0;
+ if (page == 0xff)
+ // special case - use current page
+ page = GET_BDA(video_page);
+ if (page > 7) {
+ struct cursorpos cp = { 0, 0, 0xfe };
+ return cp;
+ }
// FIXME should handle VGA 14/16 lines
- return GET_BDA(cursor_pos[page]);
+ u16 xy = GET_BDA(cursor_pos[page]);
+ struct cursorpos cp = {xy, xy>>8, page};
+ return cp;
}
-// -------------------------------------------------------------------
static void
biosfn_set_active_page(u8 page)
{
return;
// Get pos curs pos for the right page
- u16 cursor = biosfn_get_cursor_pos(page);
+ struct cursorpos cp = get_cursor_pos(page);
u16 address;
- if (GET_GLOBAL(vmode_g->class) == TEXT) {
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
// Get the dimensions
u16 nbcols = GET_BDA(video_cols);
u16 nbrows = GET_BDA(video_rows) + 1;
dprintf(1, "Set active page %02x address %04x\n", page, address);
// Display the cursor, now the page is active
- biosfn_set_cursor_pos(page, cursor);
+ set_cursor_pos(cp);
}
-static void
-biosfn_set_video_mode(u8 mode)
-{ // mode: Bit 7 is 1 if no clear screen
- if (CONFIG_CIRRUS)
- cirrus_set_video_mode(mode);
-
- if (CONFIG_VBE)
- if (vbe_has_vbe_display())
- dispi_set_enable(VBE_DISPI_DISABLED);
-
- // The real mode
- u8 noclearmem = mode & 0x80;
- mode = mode & 0x7f;
-
- // find the entry in the video modes
- struct vgamode_s *vmode_g = find_vga_entry(mode);
- dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
- if (!vmode_g)
- return;
-
- // Read the bios mode set control
- u8 modeset_ctl = GET_BDA(modeset_ctl);
-
- // Then we know the number of lines
-// FIXME
-
- // if palette loading (bit 3 of modeset ctl = 0)
- if ((modeset_ctl & 0x08) == 0) { // Set the PEL mask
- vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
-
- // From which palette
- u8 *palette_g = GET_GLOBAL(vmode_g->dac);
- u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
-
- // Always 256*3 values
- vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
- u16 i;
- for (i = palsize; i < 0x0100; i++) {
- static u8 rgb[3] VAR16;
- vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
- }
+static struct cursorpos
+check_scroll(struct cursorpos cp)
+{
+ // Get the dimensions
+ u16 nbrows = GET_BDA(video_rows) + 1;
+ u16 nbcols = GET_BDA(video_cols);
- if ((modeset_ctl & 0x02) == 0x02)
- biosfn_perform_gray_scale_summing(0x00, 0x100);
+ // Do we need to wrap ?
+ if (cp.x == nbcols) {
+ cp.x = 0;
+ cp.y++;
}
-
- struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
- vgahw_set_mode(vparam_g);
-
- if (noclearmem == 0x00)
- clear_screen(vmode_g);
-
- // Set CRTC address VGA or MDA
- u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
- if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
- crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
-
- // Set the BIOS mem
- u16 cheight = GET_GLOBAL(vparam_g->cheight);
- SET_BDA(video_mode, mode);
- SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
- SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
- SET_BDA(crtc_address, crtc_addr);
- SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
- SET_BDA(char_height, cheight);
- SET_BDA(video_ctl, (0x60 | noclearmem));
- SET_BDA(video_switches, 0xF9);
- SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
-
- // FIXME We nearly have the good tables. to be reworked
- SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now
- SET_BDA(video_savetable_ptr, (u32)video_save_pointer_table);
- SET_BDA(video_savetable_seg, get_global_seg());
-
- // FIXME
- SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
- SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
-
- // Set cursor shape
- if (GET_GLOBAL(vmode_g->class) == TEXT)
- biosfn_set_cursor_shape(0x06, 0x07);
- // Set cursor pos for page 0..7
- int i;
- for (i = 0; i < 8; i++)
- biosfn_set_cursor_pos(i, 0x0000);
-
- // Set active page 0
- biosfn_set_active_page(0x00);
-
- // Write the fonts in memory
- if (GET_GLOBAL(vmode_g->class) == TEXT) {
- call16_vgaint(0x1104, 0);
- call16_vgaint(0x1103, 0);
+ // Do we need to scroll ?
+ if (cp.y == nbrows) {
+ // Get the mode
+ struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+ if (!vmode_g)
+ return cp;
+
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+ biosfn_scroll(0x01, 0x07, 0, 0, nbrows - 1, nbcols - 1, cp.page,
+ SCROLL_UP);
+ else
+ biosfn_scroll(0x01, 0x00, 0, 0, nbrows - 1, nbcols - 1, cp.page,
+ SCROLL_UP);
+ cp.y--;
}
- // Set the ints 0x1F and 0x43
- SET_IVT(0x1f, get_global_seg(), (u32)&vgafont8[128 * 8]);
- switch (cheight) {
- case 8:
- SET_IVT(0x43, get_global_seg(), (u32)vgafont8);
- break;
- case 14:
- SET_IVT(0x43, get_global_seg(), (u32)vgafont14);
- break;
- case 16:
- SET_IVT(0x43, get_global_seg(), (u32)vgafont16);
- break;
- }
+ return cp;
}
-// -------------------------------------------------------------------
-static void
-biosfn_write_teletype(u8 car, u8 page, u8 attr, u8 flag)
-{ // flag = WITH_ATTR / NO_ATTR
- // special case if page is 0xff, use current page
- if (page == 0xff)
- page = GET_BDA(video_page);
-
- // Get the mode
- struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
- if (!vmode_g)
- return;
-
- // Get the cursor pos for the page
- u16 cursor = biosfn_get_cursor_pos(page);
- u8 xcurs = cursor & 0x00ff;
- u8 ycurs = (cursor & 0xff00) >> 8;
-
- // Get the dimensions
- u16 nbrows = GET_BDA(video_rows) + 1;
- u16 nbcols = GET_BDA(video_cols);
-
- switch (car) {
+static struct cursorpos
+write_teletype(struct cursorpos cp, struct carattr ca)
+{
+ switch (ca.car) {
case 7:
//FIXME should beep
break;
case 8:
- if (xcurs > 0)
- xcurs--;
+ if (cp.x > 0)
+ cp.x--;
break;
case '\r':
- xcurs = 0;
+ cp.x = 0;
break;
case '\n':
- ycurs++;
+ cp.y++;
break;
case '\t':
do {
- biosfn_write_teletype(' ', page, attr, flag);
- cursor = biosfn_get_cursor_pos(page);
- xcurs = cursor & 0x00ff;
- ycurs = (cursor & 0xff00) >> 8;
- } while (xcurs % 8 == 0);
+ struct carattr dummyca = {' ', ca.attr, ca.use_attr};
+ vgafb_write_char(cp, dummyca);
+ cp.x++;
+ cp = check_scroll(cp);
+ } while (cp.x % 8);
break;
default:
- if (flag == WITH_ATTR)
- biosfn_write_char_attr(car, page, attr, 1);
- else
- biosfn_write_char_only(car, page, attr, 1);
- xcurs++;
+ vgafb_write_char(cp, ca);
+ cp.x++;
}
- // Do we need to wrap ?
- if (xcurs == nbcols) {
- xcurs = 0;
- ycurs++;
- }
- // Do we need to scroll ?
- if (ycurs == nbrows) {
- if (GET_GLOBAL(vmode_g->class) == TEXT)
- biosfn_scroll(0x01, 0x07, 0, 0, nbrows - 1, nbcols - 1, page,
- SCROLL_UP);
- else
- biosfn_scroll(0x01, 0x00, 0, 0, nbrows - 1, nbcols - 1, page,
- SCROLL_UP);
- ycurs -= 1;
- }
- // Set the cursor for the page
- cursor = ycurs;
- cursor <<= 8;
- cursor += xcurs;
- biosfn_set_cursor_pos(page, cursor);
+ return check_scroll(cp);
}
static void
-biosfn_write_string(u8 flag, u8 page, u8 attr, u16 count, u8 row, u8 col,
- u16 seg, u8 *offset_far)
+write_string(struct cursorpos cp, u8 flag, u8 attr, u16 count,
+ u16 seg, u8 *offset_far)
{
- // Read curs info for the page
- u16 oldcurs = biosfn_get_cursor_pos(page);
-
// if row=0xff special case : use current cursor position
- if (row == 0xff) {
- col = oldcurs & 0x00ff;
- row = (oldcurs & 0xff00) >> 8;
- }
-
- u16 newcurs = row;
- newcurs <<= 8;
- newcurs += col;
- biosfn_set_cursor_pos(page, newcurs);
+ if (cp.y == 0xff)
+ cp = get_cursor_pos(cp.page);
while (count-- != 0) {
u8 car = GET_FARVAR(seg, *offset_far);
offset_far++;
}
- biosfn_write_teletype(car, page, attr, WITH_ATTR);
+ struct carattr ca = {car, attr, 1};
+ cp = write_teletype(cp, ca);
}
- // Set back curs pos
- if ((flag & 0x01) == 0)
- biosfn_set_cursor_pos(page, oldcurs);
+ if (flag & 0x01)
+ set_cursor_pos(cp);
}
static void
* VGA int 10 handler
****************************************************************/
+// set video mode
static void
handle_1000(struct bregs *regs)
{
- // XXX - inline
- biosfn_set_video_mode(regs->al);
- switch(regs->al & 0x7F) {
- case 6:
- regs->al = 0x3F;
- break;
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 7:
+ u8 noclearmem = regs->al & 0x80;
+ u8 mode = regs->al & 0x7f;
+
+ // Set regs->al
+ if (mode > 7)
+ regs->al = 0x20;
+ else if (mode == 6)
+ regs->al = 0x3f;
+ else
regs->al = 0x30;
+
+ if (CONFIG_CIRRUS)
+ cirrus_set_video_mode(mode);
+
+ if (CONFIG_VBE)
+ if (vbe_has_vbe_display())
+ dispi_set_enable(VBE_DISPI_DISABLED);
+
+ // find the entry in the video modes
+ struct vgamode_s *vmode_g = find_vga_entry(mode);
+ dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
+ if (!vmode_g)
+ return;
+
+ // Read the bios mode set control
+ u8 modeset_ctl = GET_BDA(modeset_ctl);
+
+ // Then we know the number of lines
+// FIXME
+
+ // if palette loading (bit 3 of modeset ctl = 0)
+ if ((modeset_ctl & 0x08) == 0) { // Set the PEL mask
+ vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
+
+ // From which palette
+ u8 *palette_g = GET_GLOBAL(vmode_g->dac);
+ u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
+
+ // Always 256*3 values
+ vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
+ u16 i;
+ for (i = palsize; i < 0x0100; i++) {
+ static u8 rgb[3] VAR16;
+ vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
+ }
+
+ if ((modeset_ctl & 0x02) == 0x02)
+ biosfn_perform_gray_scale_summing(0x00, 0x100);
+ }
+
+ struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+ vgahw_set_mode(vparam_g);
+
+ if (noclearmem == 0x00)
+ clear_screen(vmode_g);
+
+ // Set CRTC address VGA or MDA
+ u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+ if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
+ crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+ // Set the BIOS mem
+ u16 cheight = GET_GLOBAL(vparam_g->cheight);
+ SET_BDA(video_mode, mode);
+ SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
+ SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
+ SET_BDA(crtc_address, crtc_addr);
+ SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
+ SET_BDA(char_height, cheight);
+ SET_BDA(video_ctl, (0x60 | noclearmem));
+ SET_BDA(video_switches, 0xF9);
+ SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
+
+ // FIXME We nearly have the good tables. to be reworked
+ SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now
+ SET_BDA(video_savetable_ptr, (u32)video_save_pointer_table);
+ SET_BDA(video_savetable_seg, get_global_seg());
+
+ // FIXME
+ SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
+ SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
+
+ // Set cursor shape
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+ biosfn_set_cursor_shape(0x06, 0x07);
+ // Set cursor pos for page 0..7
+ int i;
+ for (i = 0; i < 8; i++) {
+ struct cursorpos cp = {0, 0, i};
+ set_cursor_pos(cp);
+ }
+
+ // Set active page 0
+ biosfn_set_active_page(0x00);
+
+ // Write the fonts in memory
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
+ call16_vgaint(0x1104, 0);
+ call16_vgaint(0x1103, 0);
+ }
+ // Set the ints 0x1F and 0x43
+ SET_IVT(0x1f, get_global_seg(), (u32)&vgafont8[128 * 8]);
+
+ switch (cheight) {
+ case 8:
+ SET_IVT(0x43, get_global_seg(), (u32)vgafont8);
+ break;
+ case 14:
+ SET_IVT(0x43, get_global_seg(), (u32)vgafont14);
+ break;
+ case 16:
+ SET_IVT(0x43, get_global_seg(), (u32)vgafont16);
break;
- default:
- regs->al = 0x20;
}
}
static void
handle_1002(struct bregs *regs)
{
- biosfn_set_cursor_pos(regs->bh, regs->dx);
+ struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+ set_cursor_pos(cp);
}
static void
handle_1003(struct bregs *regs)
{
regs->cx = biosfn_get_cursor_shape(regs->bh);
- regs->dx = biosfn_get_cursor_pos(regs->bh);
+ struct cursorpos cp = get_cursor_pos(regs->bh);
+ regs->dl = cp.x;
+ regs->dh = cp.y;
}
// Read light pen pos (unimplemented)
static void
handle_1008(struct bregs *regs)
{
- // XXX - inline
- biosfn_read_char_attr(regs->bh, ®s->ax);
+ struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
+ regs->al = ca.car;
+ regs->ah = ca.attr;
+}
+
+static void
+write_chars(u8 page, struct carattr ca, u16 count)
+{
+ struct cursorpos cp = get_cursor_pos(page);
+ while (count--) {
+ vgafb_write_char(cp, ca);
+ cp.x++;
+ }
}
static void
handle_1009(struct bregs *regs)
{
- // XXX - inline
- biosfn_write_char_attr(regs->al, regs->bh, regs->bl, regs->cx);
+ struct carattr ca = {regs->al, regs->bl, 1};
+ write_chars(regs->bh, ca, regs->cx);
}
static void
handle_100a(struct bregs *regs)
{
- // XXX - inline
- biosfn_write_char_only(regs->al, regs->bh, regs->bl, regs->cx);
+ struct carattr ca = {regs->al, regs->bl, 0};
+ write_chars(regs->bh, ca, regs->cx);
}
{
// Ralf Brown Interrupt list is WRONG on bh(page)
// We do output only on the current page !
- biosfn_write_teletype(regs->al, 0xff, regs->bl, NO_ATTR);
+ struct carattr ca = {regs->al, regs->bl, 0};
+ struct cursorpos cp = get_cursor_pos(0xff);
+ cp = write_teletype(cp, ca);
+ set_cursor_pos(cp);
}
static void
handle_1013(struct bregs *regs)
{
// XXX - inline
- biosfn_write_string(regs->al, regs->bh, regs->bl, regs->cx
- , regs->dh, regs->dl, regs->es, (void*)(regs->bp + 0));
+ struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+ write_string(cp, regs->al, regs->bl, regs->cx
+ , regs->es, (void*)(regs->bp + 0));
}