Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

arch_vga.c

/* $Id: arch_vga.c,v 1.46 2009-01-28 12:59:16 potyra Exp $ 
 *
 * Copyright (C) 2004-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifdef STATE

struct {
      /* Internal Registers */
      unsigned int scanline;
      unsigned long offset;

      /* General or External Registers */
      /* p. 342 */
      unsigned char misc_output;                /* p. 343 */
      unsigned char feature_control;                  /* p. 346 */
      unsigned char input_status_0;             /* p. 346 */
      unsigned char input_status_1;             /* p. 347 */

      /* Attribute Controller */
      /* p. 404 */
      unsigned char attr_reg_03c0;                    /* p. 404 */
      unsigned char attr_reg_03c0_state;

      /*00-0f*/unsigned char attr_palette[16];        /* p. 406 */
      /*10*/      unsigned char attr_mode_control;          /* p. 408 */
      /*11*/      unsigned char attr_overscan_color;        /* p. 411 */
      /*12*/      unsigned char attr_color_plane_enable;          /* p. 413 */
      /*13*/      unsigned char attr_horizontal_pixel_panning;    /* p. 415 */
      /*14*/      unsigned char attr_color_select;          /* p. 417 */

      /* Sequencer */
      /* p. 349 */
      unsigned char seq_reg_03c4;

      /*00*/      unsigned char seq_reset;                  /* p. 349 */
      /*01*/      unsigned char seq_clocking_mode;          /* p. 351 */
      /*02*/      unsigned char seq_map_mask;               /* p. 353 */
      /*03*/      unsigned char seq_character_map_select;         /* p. 355 */
      /*04*/      unsigned char seq_memory_mode;                  /* p. 357 */

      /* Color Registers */
      /* p. 418 */
      unsigned char col_reg_03c7;                     /* p. 419 */
      unsigned char col_reg_03c7_rgb;
      unsigned char col_reg_03c8;                     /* p. 418 */
      unsigned char col_reg_03c8_rgb;
      unsigned char col_pel_mask;                     /* p. 421 */

      /* unsigned char col_colregs[256][3]; */

      /* Graphics Controller */
      /* p. 386 */
      unsigned char gr_reg_03ce;

      /*00*/      unsigned char gr_set_reset;               /* p. 388 */
      /*01*/      unsigned char gr_enable_set_reset;        /* p. 390 */
      /*02*/      unsigned char gr_color_compare;                 /* p. 390 */
      /*03*/      unsigned char gr_data_rotate;             /* p. 392 */
      /*04*/      unsigned char gr_read_map_select;         /* p. 395 */
      /*05*/      unsigned char gr_mode;                    /* p. 396 */
      /*06*/      unsigned char gr_misc;                    /* p. 401 */
      /*07*/      unsigned char gr_color_dont_care;         /* p. 402 */
      /*08*/      unsigned char gr_bit_mask;                /* p. 403 */

      unsigned char gr_latch[4];

      /* CRT Controller */
      /* p. 358 */
      unsigned char crt_reg_03d4;                     /* p. 358 */

      /*00*/      unsigned char crt_horizontal_total;       /* p. 359 */
      /*01*/      unsigned char crt_horizontal_display_end; /* p. 360 */
      /*02*/      unsigned char crt_start_horizontal_blanking;    /* p. 361 */
      /*03*/      unsigned char crt_end_horizontal_blanking;      /* p. 362 */
      /*04*/      unsigned char crt_start_horizontal_retrace;     /* p. 363 */
      /*05*/      unsigned char crt_end_horizontal_retrace; /* p. 364 */
      /*06*/      unsigned char crt_vertical_total;         /* p. 365 */
      /*07*/      unsigned char crt_overflow;               /* p. 365 */
      /*08*/      unsigned char crt_preset_row_scan;        /* p. 367 */
      /*09*/      unsigned char crt_maximum_scan_line;            /* p. 369 */
      /*0a*/      unsigned char crt_cursor_start;                 /* p. 370 */
      /*0b*/      unsigned char crt_cursor_end;             /* p. 371 */
      /*0c/0d*/unsigned short crt_top_pos;                  /* p. 371-373 */
      /*0e/0f*/unsigned short crt_cur_pos;                  /* p. 373-374 */
      /*10*/      unsigned char crt_vertical_retrace_start; /* p. 374 */
      /*11*/      unsigned char crt_vertical_retrace_end;         /* p. 375 */
      /*12*/      unsigned char crt_vertical_display_end;         /* p. 378 */
      /*13*/      unsigned char crt_offset;                 /* p. 379 */
      /*14*/      unsigned char crt_underline_location;           /* p. 379 */
      /*15*/      unsigned char crt_start_vertical_blank;         /* p. 380 */
      /*16*/      unsigned char crt_end_vertical_blank;           /* p. 381 */
      /*17*/      unsigned char crt_mode_control;                 /* p. 382 */
      /*18*/      unsigned char crt_line_compare;                 /* p. 385 */
} NAME;

#endif /* STATE */

#ifdef BEHAVIOUR

#ifndef ARCH_VGA_PORT
#error arch_vga.c needs ARCH_VGA_PORT defined
#endif
#ifndef REFRESH_CYCLES
#error arch_vga.c needs REFRESH_CYCLES defined
#endif

#define DEBUG     0

#define TILE_WIDTH 8

static const struct {
      unsigned long start;
      unsigned long end;
} NAME_(memory_location)[4] = {
      { 0xa0000, 0xbffff },
      { 0xa0000, 0xaffff },
      { 0xb0000, 0xb7fff },
      { 0xb8000, 0xbffff }
};

static inline unsigned char
NAME_(readb)(struct cpssp *cpssp, unsigned long pa)
{
#if 2 <= DEBUG
      faum_log(FAUM_LOG_DEBUG, "vga", "",
             "%s: pa=0x%05lx\n", __FUNCTION__, pa);
#endif
      assert(0 <= pa && pa < SZ_VIDEO_MEMORY_LOW);
      
      /* FIXME: byte/word switch in CRT-Controller Reg 0x17 Bit 6 */
      
      if (cpssp->NAME.seq_memory_mode & 0x08) {
            /* Chain 4 Mode */
            /* In this mode, the planes are made to look as if they were
             * sequential. Easiest mode for the user... */
            unsigned char i;
            
            for (i = 0; i < 4; i++) {
                  cpssp->NAME.gr_latch[i] =
                        video_readb(cpssp, (pa / 4) + (i * 0x10000));
            }
#if 1 <= DEBUG
            faum_log(FAUM_LOG_DEBUG, "vga", "",
                   "%s: pa=0x%08lx chain4 val=%02x\n",
                   __FUNCTION__,
                   (pa / 4) + ((pa % 4) * 0x10000),
                    cpssp->NAME.gr_latch[i]);
#endif
            return cpssp->NAME.gr_latch[cpssp->NAME.gr_read_map_select & 3];
            
      } else if ((cpssp->NAME.gr_mode >> 4) & 1) {
            /* Odd/even mode. */
            unsigned char i;

            pa = (pa >> 1) | ((pa & 1) << 16);
#if 0
            /* FIXME This should actually work but doesn't, could be our
             * initialization does this wrong and inits it to 1? */
            if ((cpssp->NAME.misc_output >> 5) & 1) {
                  pa += 0x20000;
            }
#endif
            for (i = 0; i < 4; i++) {
                  cpssp->NAME.gr_latch[i] =
                        video_readb(cpssp, (pa % 0x10000) + (i * 0x10000));
            }
#if 1 <= DEBUG
            faum_log(FAUM_LOG_DEBUG, "vga", "",
                   "%s: pa=0x%08lx odd/even miscout=%1d val=%02x\n",
                   __FUNCTION__, pa, (cpssp->NAME.misc_output >> 5) & 1,
                   cpssp->NAME.gr_latch[pa / 0x10000]);
#endif
            return cpssp->NAME.gr_latch[pa / 0x10000];

      } else {
            /* Sequential mode. */

            /* FIXME VOSSI */
            if (pa < 0xa0000 || 0xb0000 <= pa) {
#if 1 <= DEBUG
                  faum_log(FAUM_LOG_DEBUG, "vga", "",
                         "%s: pa=0x%04lx rmode=%1d",
                         __FUNCTION__, pa, ((cpssp->NAME.gr_mode >> 3) & 1));
#endif
#if 0
                  faum_cont(FAUM_LOG_DEBUG, "\n");
                  return;
#endif
            }

            cpssp->NAME.gr_latch[0] = video_readb(cpssp, pa + 0x00000);
            cpssp->NAME.gr_latch[1] = video_readb(cpssp, pa + 0x10000);
            cpssp->NAME.gr_latch[2] = video_readb(cpssp, pa + 0x20000);
            cpssp->NAME.gr_latch[3] = video_readb(cpssp, pa + 0x30000);
            if ((cpssp->NAME.gr_mode >> 3) & 1) {
                  /*
                   * Read Mode 1
                   */
                  unsigned char val0;
                  unsigned char val1;
                  unsigned char val2;
                  unsigned char val3;
                  unsigned char cmp;
                  unsigned char res;
                  int i;

                  res = 0x00;
                  val0 = cpssp->NAME.gr_latch[0];
                  val1 = cpssp->NAME.gr_latch[1];
                  val2 = cpssp->NAME.gr_latch[2];
                  val3 = cpssp->NAME.gr_latch[3];
                  for (i = 0; i < 8; i++) {
                        res <<= 1;
                        cmp = ((val3 & 0x80) >> 4)
                            | ((val2 & 0x80) >> 5)
                            | ((val1 & 0x80) >> 6)
                            | ((val0 & 0x80) >> 7);
                        if ((cmp & cpssp->NAME.gr_color_dont_care)
                         == (cpssp->NAME.gr_color_compare
                             & cpssp->NAME.gr_color_dont_care)) {
                              res |= 0x01;
                        }
                        val0 <<= 1;
                        val1 <<= 1;
                        val2 <<= 1;
                        val3 <<= 1;
                  }

#if 1 <= DEBUG
                  faum_cont(FAUM_LOG_DEBUG, " val=0x%02x\n", res);
#endif
                  return res;

            } else {
                  /*
                   * Read Mode 0
                   */
#if 1 <= DEBUG
                  faum_cont(FAUM_LOG_DEBUG, " val=0x%02x\n",
                          cpssp->NAME.gr_latch[cpssp->NAME.gr_read_map_select & 3]);
#endif
                  return cpssp->NAME.gr_latch[cpssp->NAME.gr_read_map_select & 3];
            }
      }
}

static inline void
NAME_(writeb)(struct cpssp *cpssp, unsigned long pa, unsigned char val)
{
#if 2 <= DEBUG
      faum_log(FAUM_LOG_DEBUG, "vga", "",
             "%s: pa=0x%05lx, val=0x%02x\n",
             __FUNCTION__, pa, val);
#endif
      assert(0 <= pa && pa < SZ_VIDEO_MEMORY_LOW);

      if ((cpssp->NAME.seq_memory_mode >> 3) & 1) {
            /* Chain 4 Mode */
            pa = ((pa >> 2) & 0xffff) | ((pa & 3) << 16);
#if 1 <= DEBUG
            faum_log(FAUM_LOG_DEBUG, "vga", "",
                   "%s: pa=0x%08lx chain4 val=%02x\n",
                   __FUNCTION__, pa, val);
#endif
            if (cpssp->NAME.seq_map_mask & (1 << (pa / 0x10000))) {
                  video_writeb(cpssp, pa, val);
            }

      } else if (!((cpssp->NAME.seq_memory_mode >> 2) & 1)
            && ((cpssp->NAME.gr_mode >> 4) & 1)) {
            /* Odd/even mode. */
            pa = ((pa >> 1) & 0xffff) | ((pa & 1) << 16);
#if 0
            /* FIXME This should actually work but doesn't! */
            pa |= (((cpssp->NAME.misc_output >> 5) & 1) << 17);
#endif
#if 2 <= DEBUG
            faum_log(FAUM_LOG_DEBUG, "vga", "",
                   "%s: odd/even -> 0x%05lx, bitplane %swriteable\n",
                   __FUNCTION__, pa,
                   (cpssp->NAME.seq_map_mask & (1 << (pa / 0x10000)))
                    ? "" : "not ");
#endif
            /* we still are bound to obey the map_mask register!
             * (PC Intern 3.0, p. 405) */
            if (cpssp->NAME.seq_map_mask & (1 << (pa / 0x10000))) {
                  video_writeb(cpssp, pa, val);
            }

      } else {
            /* Sequential mode. */
            unsigned char val0;
            unsigned char val1;
            unsigned char val2;
            unsigned char val3;

            /* FIXME VOSSI */
            if (/* pa < 0x00000000 || */ 0x00010000 <= pa) {
#if 1 <= DEBUG
                  faum_log(FAUM_LOG_WARNING, "vga", "",
                         "WARNING: %s: pa=0x%08lx\n",
                         __FUNCTION__, pa);
#endif
                  return;
            }

            /* Rotate */
            if (((cpssp->NAME.gr_mode & 3) == 0)
             || ((cpssp->NAME.gr_mode & 3) == 3)) {
                  val = (val >> (cpssp->NAME.gr_data_rotate & 7))
                      | (val << (8 - (cpssp->NAME.gr_data_rotate & 7)));
            }

            switch (cpssp->NAME.gr_mode & 3) {
            case 0:
                  /*
                   * Write Mode 0
                   */
                  /* Set/Reset */
                  if (cpssp->NAME.gr_enable_set_reset & 0x01) {
                        if (cpssp->NAME.gr_set_reset & 0x01) {
                              val0 = 0xff;
                        } else {
                              val0 = 0x00;
                        }
                  } else {
                        val0 = val;
                  }
                  if (cpssp->NAME.gr_enable_set_reset & 0x02) {
                        if (cpssp->NAME.gr_set_reset & 0x02) {
                              val1 = 0xff;
                        } else {
                              val1 = 0x00;
                        }
                  } else {
                        val1 = val;
                  }
                  if (cpssp->NAME.gr_enable_set_reset & 0x04) {
                        if (cpssp->NAME.gr_set_reset & 0x04) {
                              val2 = 0xff;
                        } else {
                              val2 = 0x00;
                        }
                  } else {
                        val2 = val;
                  }
                  if (cpssp->NAME.gr_enable_set_reset & 0x08) {
                        if (cpssp->NAME.gr_set_reset & 0x08) {
                              val3 = 0xff;
                        } else {
                              val3 = 0x00;
                        }
                  } else {
                        val3 = val;
                  }
                  break;

            case 1:
                  /*
                   * Write Mode 1
                   */
                  val0 = cpssp->NAME.gr_latch[0];
                  val1 = cpssp->NAME.gr_latch[1];
                  val2 = cpssp->NAME.gr_latch[2];
                  val3 = cpssp->NAME.gr_latch[3];
                  break;

            case 2:
                  /*
                   * Write Mode 2
                   */
                  if (val & 0x01) {
                        val0 = 0xff;
                  } else {
                        val0 = 0x00;
                  }
                  if (val & 0x02) {
                        val1 = 0xff;
                  } else {
                        val1 = 0x00;
                  }
                  if (val & 0x04) {
                        val2 = 0xff;
                  } else {
                        val2 = 0x00;
                  }
                  if (val & 0x08) {
                        val3 = 0xff;
                  } else {
                        val3 = 0x00;
                  }
                  break;

            case 3:
                  /*
                   * Write Mode 3
                   */
                  if (cpssp->NAME.gr_set_reset & 0x01) {
                        val0 = 0xff;
                  } else {
                        val0 = 0x00;
                  }
                  if (cpssp->NAME.gr_set_reset & 0x02) {
                        val1 = 0xff;
                  } else {
                        val1 = 0x00;
                  }
                  if (cpssp->NAME.gr_set_reset & 0x04) {
                        val2 = 0xff;
                  } else {
                        val2 = 0x00;
                  }
                  if (cpssp->NAME.gr_set_reset & 0x08) {
                        val3 = 0xff;
                  } else {
                        val3 = 0x00;
                  }

                  break;

            default:
                  assert(0);
            }

            /* ALU */
            if (((cpssp->NAME.gr_mode & 3) == 0)
             || ((cpssp->NAME.gr_mode & 3) == 2)) {
                  switch ((cpssp->NAME.gr_data_rotate >> 3) & 3) {
                  case 0:     /* NOP */
                        /* nothing to do... */
                        break;
                  case 1:     /* AND */
                        val0 &= cpssp->NAME.gr_latch[0];
                        val1 &= cpssp->NAME.gr_latch[1];
                        val2 &= cpssp->NAME.gr_latch[2];
                        val3 &= cpssp->NAME.gr_latch[3];
                        break;
                  case 2:     /* OR */
                        val0 |= cpssp->NAME.gr_latch[0];
                        val1 |= cpssp->NAME.gr_latch[1];
                        val2 |= cpssp->NAME.gr_latch[2];
                        val3 |= cpssp->NAME.gr_latch[3];
                        break;
                  case 3:     /* XOR */
                        val0 ^= cpssp->NAME.gr_latch[0];
                        val1 ^= cpssp->NAME.gr_latch[1];
                        val2 ^= cpssp->NAME.gr_latch[2];
                        val3 ^= cpssp->NAME.gr_latch[3];
                        break;
                  default: /* Cannot happen */
                        assert(0);
                  }
            }

            /* Bit Mask */
            if ((cpssp->NAME.gr_mode & 3) == 0
             || (cpssp->NAME.gr_mode & 3) == 2) {
                  val0 = (val0 & cpssp->NAME.gr_bit_mask)
                       | (cpssp->NAME.gr_latch[0] & ~cpssp->NAME.gr_bit_mask);
                  val1 = (val1 & cpssp->NAME.gr_bit_mask)
                       | (cpssp->NAME.gr_latch[1] & ~cpssp->NAME.gr_bit_mask);
                  val2 = (val2 & cpssp->NAME.gr_bit_mask)
                       | (cpssp->NAME.gr_latch[2] & ~cpssp->NAME.gr_bit_mask);
                  val3 = (val3 & cpssp->NAME.gr_bit_mask)
                       | (cpssp->NAME.gr_latch[3] & ~cpssp->NAME.gr_bit_mask);
            } else if ((cpssp->NAME.gr_mode & 3) == 3) {
                  val = val & cpssp->NAME.gr_bit_mask;
                  val0 = (val0 & val)
                       | (cpssp->NAME.gr_latch[0] & ~val);
                  val1 = (val1 & val)
                       | (cpssp->NAME.gr_latch[1] & ~val);
                  val2 = (val2 & val)
                       | (cpssp->NAME.gr_latch[2] & ~val);
                  val3 = (val3 & val)
                       | (cpssp->NAME.gr_latch[3] & ~val);
            }

            /* Plane Select determines to which planes the result
             * gets written */
            if (cpssp->NAME.seq_map_mask & 0x01) {
                  video_writeb(cpssp, pa + 0x00000, val0);
            }
            if (cpssp->NAME.seq_map_mask & 0x02) {
                  video_writeb(cpssp, pa + 0x10000, val1);
            }
            if (cpssp->NAME.seq_map_mask & 0x04) {
                  video_writeb(cpssp, pa + 0x20000, val2);
            }
            if (cpssp->NAME.seq_map_mask & 0x08) {
                  video_writeb(cpssp, pa + 0x30000, val3);
            }
#if 3 <= DEBUG
            faum_log(FAUM_LOG_DEBUG, "vga", "",
                        "%s: "
                        "bit_mask=0x%02x"
                        " map_mask=0x%02x"
                        " rot=%1d,%1d"
                        " val0=0x%02x"
                        " val1=0x%02x"
                        " val2=0x%02x"
                        " val3=0x%02x"
                        " wrmode=%1d"
                        "\n",
                        __FUNCTION__,
                        cpssp->NAME.gr_bit_mask,
                        cpssp->NAME.seq_map_mask,
                        (cpssp->NAME.gr_data_rotate & 7),
                        ((cpssp->NAME.gr_data_rotate >> 3) & 3),
                        val0,
                        val1,
                        val2,
                        val3,
                        (cpssp->NAME.gr_mode & 3)
            );
#endif
      }
}

static inline int
NAME_(read)(struct cpssp *cpssp, unsigned long pa, void *_to, int len)
{
      unsigned char *to = (unsigned char *) _to;
      unsigned int mm;
      unsigned long start;
      unsigned long end;

      mm = (cpssp->NAME.gr_misc >> 2) & 3;
      start = NAME_(memory_location)[mm].start;
      end = NAME_(memory_location)[mm].end;

      if (start <= pa && pa <= end) {
            /*
             * Low VGA memory
             *
             * Simulate access.
             */
            pa -= start;

            while (0 < len) {
                  *to = NAME_(readb)(cpssp, pa);
                  pa++;
                  to++;
                  len--;
            }

            return 0;

      } else {
            /* Don't know... */
            return 1;
      }
}

static inline int
NAME_(write)(struct cpssp *cpssp, unsigned long pa, const void *_from, int len)
{
      const unsigned char *from = (const unsigned char *) _from;
      unsigned int mm;
      unsigned long start;
      unsigned long end;

      mm = (cpssp->NAME.gr_misc >> 2) & 3;
      start = NAME_(memory_location)[mm].start;
      end = NAME_(memory_location)[mm].end;

      if (start <= pa && pa <= end) {
            /*
             * Low VGA memory
             *
             * Simulate access.
             */
            pa -= start;

            while (0 < len) {
                  NAME_(writeb)(cpssp, pa, *from);
                  pa++;
                  from++;
                  len--;
            }

            return 0;

      } else {
            /* Don't know... */
            return 1;
      }
}

static inline int
NAME_(map)(
      struct cpssp *cpssp,
      unsigned long pa,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p
)
{
      if (PA_VIDEO_MEMORY_LOW <= pa
       && pa <= PA_VIDEO_MEMORY_LOW + SZ_VIDEO_MEMORY_LOW - 1) {
            /*
             * Low VGA memory
             *
             * Simulate access.
             */
            *haddr_mr_p = NULL;
            *haddr_mw_p = NULL;
            return 0;

      } else {
            /* Don't know... */
            return 1;
      }
}

static inline unsigned char
NAME_(_inb)(struct cpssp *cpssp, unsigned short port)
{
      unsigned char value;

#if 1 <= DEBUG
      fprintf(stderr, "%s: port=0x%04x\n", __FUNCTION__, port + 0x03c0);
#endif

      switch (port + 0x03c0) {
      case 0x03c0:
      case 0x03c1:
            /* Attribute Controller Data Read */
            switch (cpssp->NAME.attr_reg_03c0 & 0x1f) {
            case 0x00 ... 0x0f:     /* palette */
                  value = cpssp->NAME.attr_palette[cpssp->NAME.attr_reg_03c0 & 0x0f];
                  break;
            case 0x10:  /* mode control */
                  value = cpssp->NAME.attr_mode_control;
                  break;
            case 0x11:  /* overscan color */
                  value = cpssp->NAME.attr_overscan_color;
                  break;
            case 0x12:  /* color plane enable */
                  value = cpssp->NAME.attr_color_plane_enable;
                  break;
            case 0x13:  /* horizontal pixel panning */
                  value = cpssp->NAME.attr_horizontal_pixel_panning;
                  break;
            case 0x14:  /* color select */
                  value = cpssp->NAME.attr_color_select;
                  break;
            case 0x15 ... 0x1f:
#if 1 <= DEBUG
                  fprintf(stderr, "WARNING: %s: port 0x03c0=0x%02x\n",
                              __FUNCTION__, cpssp->NAME.attr_reg_03c0);
#endif
                  value = 0x00;
                  break;
            default:
                  assert(0);
                  value = 0;  /* to make gcc happy */
                  break;
            }
            break;

      case 0x03c2:
            /* Input Status #0 Register */
            /* p. 346 */
            value = cpssp->NAME.input_status_0;
            cpssp->NAME.input_status_0 ^= 0x80; /* toggle vertical retrace */
            break;

      case 0x03c4:
            /* Sequencer Index */
            value = cpssp->NAME.seq_reg_03c4;
            break;

      case 0x03c5:
            /* Sequencer Data Register */
            switch (cpssp->NAME.seq_reg_03c4) {
            case 0x00:  /* reset */
                        /* p. 349 */
                  value = cpssp->NAME.seq_reset;
                  break;
            case 0x01:  /* clocking mode */
                        /* p. 351 */
                  value = cpssp->NAME.seq_clocking_mode;
                  break;
            case 0x02:  /* map mask */
                        /* p. 353 */
                  value = cpssp->NAME.seq_map_mask;
                  break;
            case 0x03:  /* character map select */
                        /* p. 355 */
                  value = cpssp->NAME.seq_character_map_select;
                  break;
            case 0x04:  /* memory mode */
                        /* p. 357 */
                  value = cpssp->NAME.seq_memory_mode;
                  break;
            default:
#if 1 <= DEBUG
                  fprintf(stderr, "WARNING: %s: port 0x03c4=0x%02x\n",
                              __FUNCTION__, cpssp->NAME.seq_reg_03c4);
#endif
                  value = 0x00;
                  break;
            }
            break;

      case 0x03c6:
            /* PEL Mask Register */
            /* p. 421 */
            value = cpssp->NAME.col_pel_mask;
            break;

      case 0x03c7:
            /* DAC State Register */
            /* p. 420 */
            goto unknown;

      case 0x03c9:
            /* PEL Data Read Register */
            /* p. 419 */
            value = video_col_get(cpssp, cpssp->NAME.col_reg_03c7, cpssp->NAME.col_reg_03c7_rgb) >> 2;
            cpssp->NAME.col_reg_03c7_rgb++;
            if (cpssp->NAME.col_reg_03c7_rgb == 3) {
                  cpssp->NAME.col_reg_03c7_rgb = 0;
                  cpssp->NAME.col_reg_03c7++;
            }
            break;

      case 0x03ca:
            /* Feature Control */
            /* p. 346 */
            value = cpssp->NAME.feature_control;
            break;

      case 0x03cc:
            /* Misc Output Read (VGA only) */
            /* p. 343 */
            value = cpssp->NAME.misc_output;
            break;

      case 0x03ce:
            /* Graphics Controller Index */
            value = cpssp->NAME.gr_reg_03ce & 0x3f;
            break;

      case 0x03cf:
            /* Graphics Controller Data Register */
            switch (cpssp->NAME.gr_reg_03ce) {
            case 0x00:  /* set/reset */
                  value = cpssp->NAME.gr_set_reset;
                  break;
            case 0x01:  /* enable set/reset */
                  value = cpssp->NAME.gr_enable_set_reset;
                  break;
            case 0x02:  /* color compare */
                  value = cpssp->NAME.gr_color_compare;
                  break;
            case 0x03:  /* data rotate */
                  value = cpssp->NAME.gr_data_rotate;
                  break;
            case 0x04:  /* read map select */
                  value = cpssp->NAME.gr_read_map_select;
                  break;
            case 0x05:  /* mode */
                  value = cpssp->NAME.gr_mode;
                  break;
            case 0x06:  /* misc */
                  value = cpssp->NAME.gr_misc;
                  break;
            case 0x07:  /* color don't care */
                  value = cpssp->NAME.gr_color_dont_care;
                  break;
            case 0x08:  /* bit mask */
                  value = cpssp->NAME.gr_bit_mask;
                  break;
            case 0x09 ... 0x3f:
                  value = 0x00;
                  break;
            default:
                  assert(0);  /* Cannot happen. */
            }

            break;

      case 0x03d4:
            /* CRT Controller Index Register */
            /* p. 358 */
            value = cpssp->NAME.crt_reg_03d4;
            break;

      case 0x03d5:
            /* CRT Controller Data Register */
            /* p. 358 */
            switch (cpssp->NAME.crt_reg_03d4) {
            case 0x00:
                  value = cpssp->NAME.crt_horizontal_total;
                  break;
            case 0x01:
                  value = cpssp->NAME.crt_horizontal_display_end;
                  break;
            case 0x02:
                  value = cpssp->NAME.crt_start_horizontal_blanking;
                  break;
            case 0x03:
                  value = cpssp->NAME.crt_end_horizontal_blanking;
                  break;
            case 0x04:
                  value = cpssp->NAME.crt_start_horizontal_retrace;
                  break;
            case 0x05:
                  value = cpssp->NAME.crt_end_horizontal_retrace;
                  break;
            case 0x06:
                  value = cpssp->NAME.crt_vertical_total;
                  break;
            case 0x07:
                  value = cpssp->NAME.crt_overflow;
                  break;
            case 0x08:
                  value = cpssp->NAME.crt_preset_row_scan;
                  break;
            case 0x09:
                  value = cpssp->NAME.crt_maximum_scan_line;
                  break;
            case 0x0a:
                  value = cpssp->NAME.crt_cursor_start;
                  break;
            case 0x0b:
                  value = cpssp->NAME.crt_cursor_end;
                  break;
            case 0x0c:
                  value = cpssp->NAME.crt_top_pos >> 8;
                  break;
            case 0x0d:
                  value = cpssp->NAME.crt_top_pos >> 0;
                  break;
            case 0x0e:
                  value = cpssp->NAME.crt_cur_pos >> 8;
                  break;
            case 0x0f:
                  value = cpssp->NAME.crt_cur_pos >> 0;
                  break;
            case 0x10:
                  value = cpssp->NAME.crt_vertical_retrace_start;
                  break;
            case 0x11:
                  value = cpssp->NAME.crt_vertical_retrace_end;
                  break;
            case 0x12:
                  value = cpssp->NAME.crt_vertical_display_end;
                  break;
            case 0x13:
                  value = cpssp->NAME.crt_offset;
                  break;
            case 0x14:
                  value = cpssp->NAME.crt_underline_location;
                  break;
            case 0x15:
                  value = cpssp->NAME.crt_start_vertical_blank;
                  break;
            case 0x16:
                  value = cpssp->NAME.crt_end_vertical_blank;
                  break;
            case 0x17:
                  value = cpssp->NAME.crt_mode_control;
                  break;
            case 0x18:
                  value = cpssp->NAME.crt_line_compare;
                  break;
            default:
#if 1 <= DEBUG
                  fprintf(stderr, "WARNING: %s: port 0x03d4=0x%02x\n",
                              __FUNCTION__, cpssp->NAME.crt_reg_03d4);
#endif
                  value = 0x00;
                  break;
            }
            break;

      case 0x03da:
            /* Input Status #1 Register */
            /* p. ????? - FIXME VOSSI */
            cpssp->NAME.attr_reg_03c0_state = 0;

            /* p. 347 */
#if 0
            vga_tick();
#else
            /*
             * toggle between
             * - display mode
             * - horizontal retrace time
             * - vertical retrace time
             */
            switch (cpssp->NAME.input_status_1 & 0x09) {
            case 0x00: /* display mode */
                  cpssp->NAME.input_status_1 ^= 0x01;
                  break;
            case 0x01: /* horizontal retrace time */
                  cpssp->NAME.input_status_1 ^= 0x08;
                  break;
            case 0x09: /* vertical retrace time */
                  cpssp->NAME.input_status_1 ^= 0x09;
                  break;
            default:
                  assert(0);
            }
#endif
            value = cpssp->NAME.input_status_1;
            break;

      default:
      unknown:
#if 1 <= DEBUG
            fprintf(stderr, "WARNING: %s: port=0x%04x\n",
                        __FUNCTION__, port + 0x03c0);
#endif
            value = 0x00;
      }

#if 1 <= DEBUG
      fprintf(stderr, "%s: port=0x%04x value=0x%02x\n",
                  __FUNCTION__, port + 0x03c0, value);
#endif

      return value;
}

static inline void
NAME_(_outb)(struct cpssp *cpssp, unsigned char value, unsigned short port)
{
#if 1 <= DEBUG
      fprintf(stderr, "%s: port=0x%04x value=0x%02x\n",
                  __FUNCTION__, port + 0x03c0, value);
#endif

      switch (port + 0x03c0) {
      case 0x03c0:
      case 0x03c1:
            /* Attribute Controller Index & Data Write */
            switch (cpssp->NAME.attr_reg_03c0_state) {
            case 0:
                  cpssp->NAME.attr_reg_03c0 = value;
                  cpssp->NAME.attr_reg_03c0_state = 1;
                  break;
            case 1:
                  switch (cpssp->NAME.attr_reg_03c0 & 0x1f) {
                  case 0x00 ... 0x0f: /* palette - p. 406 */
                        cpssp->NAME.attr_palette[cpssp->NAME.attr_reg_03c0 & 0x0f]
                              = value & 0x3f;
                        break;
                  case 0x10:  /* mode control - p. 408 */
                        cpssp->NAME.attr_mode_control = value & 0xef;
                        break;
                  case 0x11:  /* overscan color - p. 411 */
                        cpssp->NAME.attr_overscan_color = value & 0x3f;
                        break;
                  case 0x12:  /* color plane enable - p. 413 */
                        cpssp->NAME.attr_color_plane_enable = value & 0x3f;
                        break;
                  case 0x13:  /* horizontal pixel panning - p. 415 */
                        cpssp->NAME.attr_horizontal_pixel_panning = value & 0x0f;
                        break;
                  case 0x14:  /* color select - p. 417 */
                        cpssp->NAME.attr_color_select = value & 0x0f;
                        break;
                  case 0x15 ... 0x1f:
#if 1 <= DEBUG
                        fprintf(stderr, "WARNING: %s: port 0x03c0=0x%02x\n",
                                    __FUNCTION__, cpssp->NAME.attr_reg_03c0);
#endif
                        break;
                  default:
                        assert(0);
                        break;
                  }
                  cpssp->NAME.attr_reg_03c0_state = 0;
                  break;
            default:
                  assert(0);
            }
            break;

      case 0x03c2:
            /* Misc Output Write Register */
            /* p. 343 */
            cpssp->NAME.misc_output = value;
            break;

      case 0x03c3:
            goto unknown;

      case 0x03c4:
            /* Sequencer Index */
            cpssp->NAME.seq_reg_03c4 = value;
            break;

      case 0x03c5:
            /* Sequencer Data */
            switch (cpssp->NAME.seq_reg_03c4) {
            case 0x00:  /* reset - p. 349 */
                  cpssp->NAME.seq_reset = value & 0x03;
                  break;
            case 0x01:  /* clocking mode - p. 351 */
                  cpssp->NAME.seq_clocking_mode = value & 0x3f;
                  break;
            case 0x02:  /* map mask - p. 349 */
                  cpssp->NAME.seq_map_mask = value & 0x0f;
                  break;
            case 0x03:  /* character map select - p. 355 */
                  cpssp->NAME.seq_character_map_select = value & 0x3f;
                  break;
            case 0x04:  /* memory mode - p. 357 */
                  cpssp->NAME.seq_memory_mode = value & 0x0f;
                  break;
            default:
#if 1 <= DEBUG
                  fprintf(stderr, "WARNING: %s: port 0x03c4=0x%02x\n",
                              __FUNCTION__, cpssp->NAME.seq_reg_03c4);
#endif
                  break;
            }
            break;

      case 0x03c6:
            /* PEL Mask Register */
            /* p. 421 */
            cpssp->NAME.col_pel_mask = value;
            break;

      case 0x03c7:
            /* PEL Read Index Register */
            /* p. 419 */
            cpssp->NAME.col_reg_03c7 = value;
            cpssp->NAME.col_reg_03c7_rgb = 0;
            break;

      case 0x03c8:
            /* PEL Write Index Register */
            /* p. 418 */
            cpssp->NAME.col_reg_03c8 = value;
            cpssp->NAME.col_reg_03c8_rgb = 0;
            break;

      case 0x03c9:
            /* PEL Data Write Register */
            /* p. 419 */
            video_col_set(cpssp, cpssp->NAME.col_reg_03c8, cpssp->NAME.col_reg_03c8_rgb,
                  value << 2);
            cpssp->NAME.col_reg_03c8_rgb++;
            if (cpssp->NAME.col_reg_03c8_rgb == 3) {
                  cpssp->NAME.col_reg_03c8_rgb = 0;
                  cpssp->NAME.col_reg_03c8++;
            }
            break;

      case 0x03ca:
            /* EGA-specific */
            /* Graphics enable processor 1 */
            goto unknown;

      case 0x03cb:
            goto unknown;

      case 0x03cd:
            goto unknown;

      case 0x03ce:
            /* Graphics Controller Index */
            cpssp->NAME.gr_reg_03ce = value & 0x3f;
            break;

      case 0x03cf:
            /* Graphics Controller Data */
            switch (cpssp->NAME.gr_reg_03ce) {
            case 0x00:  /* set/reset - p. 388 */
                  cpssp->NAME.gr_set_reset = value & 0x0f;
                  break;
            case 0x01:  /* enable set/reset - p. 390 */
                  cpssp->NAME.gr_enable_set_reset = value & 0x0f;
                  break;
            case 0x02:  /* color compare - p. 390 */
                  cpssp->NAME.gr_color_compare = value & 0x0f;
                  break;
            case 0x03:  /* data rotate - p. 392 */
                  cpssp->NAME.gr_data_rotate = value & 0x3f;
                  break;
            case 0x04:  /* read map select - p. 395 */
                  cpssp->NAME.gr_read_map_select = value & 0x03;
                  break;
            case 0x05:  /* mode - p. 396 */
                  cpssp->NAME.gr_mode = value & 0x7f;
                  break;
            case 0x06:  /* misc - p. 401 */
                  cpssp->NAME.gr_misc = value & 0x0f;
                  break;
            case 0x07:  /* color don't care - p. 402 */
                  cpssp->NAME.gr_color_dont_care = value & 0x0f;
                  break;
            case 0x08:  /* bit mask - p. 403 */
                  cpssp->NAME.gr_bit_mask = value & 0xff;
                  break;
            case 0x09 ... 0x3f:
                  /* Do nothing... */
                  break;
            default:
                  assert(0);  /* Cannot happen. */
            }
            break;

      case 0x03d4:
            /* CRT Controller Index */
            cpssp->NAME.crt_reg_03d4 = value;
            break;

      case 0x03d5:
            /* CRT Controller Data */
            switch (cpssp->NAME.crt_reg_03d4) {
            case 0x00:  /* horizontal total - p. 359 */
                  cpssp->NAME.crt_horizontal_total = value & 0xff;
                  break;
            case 0x01:  /* horizontal display end - p. 360 */
                  cpssp->NAME.crt_horizontal_display_end = value & 0xff;
                  break;
            case 0x02:  /* start_horizontal blanking - p. 361 */
                  cpssp->NAME.crt_start_horizontal_blanking = value & 0xff;
                  break;
            case 0x03:  /* end horizontal blanking - p. 362 */
                  cpssp->NAME.crt_end_horizontal_blanking = value & 0xff;
                  break;
            case 0x04:  /* start horizontal retrace - p. 363 */
                  cpssp->NAME.crt_start_horizontal_retrace = value & 0xff;
                  break;
            case 0x05:  /* end horizontal retrace - p. 364 */
                  cpssp->NAME.crt_end_horizontal_retrace = value & 0xff;
                  break;
            case 0x06:  /* vertical total - p. 365 */
                  cpssp->NAME.crt_vertical_total = value & 0xff;
                  break;
            case 0x07:  /* overflow - p. 365 */
                  cpssp->NAME.crt_overflow = value & 0xff;
                  break;
            case 0x08:  /* preset row scan - p. 367 */
                  cpssp->NAME.crt_preset_row_scan = value & 0x7f;
                  break;
            case 0x09:  /* maximum scan line - p. 369 */
                  cpssp->NAME.crt_maximum_scan_line = value & 0xff;
                  break;
            case 0x0a:  /* cursor start - p. 370 */
                  cpssp->NAME.crt_cursor_start = value & 0x3f;
                  break;
            case 0x0b:  /* cursor end - p. 371 */
                  cpssp->NAME.crt_cursor_end = value & 0x7f;
                  break;
            case 0x0c:  /* top position (high byte) - p. 371 */
                  cpssp->NAME.crt_top_pos &= 0x00ff;
                  cpssp->NAME.crt_top_pos |= ((unsigned short) value << 8);
                  break;
            case 0x0d:  /* top position (low byte) - p. 373 */
                  cpssp->NAME.crt_top_pos &= 0xff00;
                  cpssp->NAME.crt_top_pos |= ((unsigned short) value << 0);
                  break;
            case 0x0e:  /* cursor position (high byte) - p. 373 */
                  cpssp->NAME.crt_cur_pos &= 0x00ff;
                  cpssp->NAME.crt_cur_pos |= ((unsigned short) value << 8);
                  break;
            case 0x0f:  /* cursor position (low byte) - p. 374 */
                  cpssp->NAME.crt_cur_pos &= 0xff00;
                  cpssp->NAME.crt_cur_pos |= ((unsigned short) value << 0);
                  break;
            case 0x10:  /* vertical retrace start - p. 374 */
                  cpssp->NAME.crt_vertical_retrace_start = value & 0xff;
                  break;
            case 0x11:  /* vertical retrace end - p. 375 */
                  cpssp->NAME.crt_vertical_retrace_end = value & 0xff;
                  break;
            case 0x12:  /* vertical display end - p. 378 */
                  cpssp->NAME.crt_vertical_display_end = value & 0xff;
                  break;
            case 0x13:  /* offset - p. 379 */
                  cpssp->NAME.crt_offset = value & 0xff;
                  break;
            case 0x14:  /* underline location - p. 379 */
                  cpssp->NAME.crt_underline_location = value & 0x7f;
                  break;
            case 0x15:  /* start vertical blanking - p. 380 */
                  cpssp->NAME.crt_start_vertical_blank = value & 0xff;
                  break;
            case 0x16:  /* end vertical blanking - p. 381 */
                  cpssp->NAME.crt_end_vertical_blank = value & 0x7f;
                  break;
            case 0x17:  /* mode control - p. 382 */
                  cpssp->NAME.crt_mode_control = value & 0xff;
                  break;
            case 0x18:  /* line compare - p. 385 */
                  cpssp->NAME.crt_line_compare = value & 0xff;
                  break;
            default:
#if 1 <= DEBUG
                  fprintf(stderr, "WARNING: %s: port 0x03d4=0x%02x\n",
                              __FUNCTION__, cpssp->NAME.crt_reg_03d4);
#endif
                  break;
            }
            break;

      case 0x03d6:
      case 0x03d7:
      case 0x03d8:
      case 0x03d9:
            goto unknown;

      case 0x03da:
            /* Feature Control */
            /* p. 346 */
            cpssp->NAME.feature_control = value & 0x0b;
            break;

      case 0x03db:
      case 0x03dc:
      case 0x03dd:
      case 0x03de:
      case 0x03df:
            goto unknown;

      default:
unknown:    ;
#if 1 <= DEBUG
            fprintf(stderr, "WARNING: %s: value=0x%02x port=0x%04x\n",
                        __FUNCTION__, value, port + 0x03c0);
#endif
            break;
      }
}

static inline int
NAME_(inb)(struct cpssp *cpssp, unsigned char *valuep, unsigned short port)
{

      if (ARCH_VGA_PORT <= port
       && port < ARCH_VGA_PORT + 0x20) {
            *valuep = NAME_(_inb)(cpssp, port - ARCH_VGA_PORT);
            return 0;

      } else {
            return 1;
      }
}

static inline int
NAME_(outb)(struct cpssp *cpssp, unsigned char value, unsigned short port)
{
      if (ARCH_VGA_PORT <= port
       && port < ARCH_VGA_PORT + 0x20) {
             NAME_(_outb)(cpssp, value, port - ARCH_VGA_PORT);
             return 0;

       } else {
             return 1;
       }
}

static inline int
NAME_(outw)(struct cpssp *cpssp, unsigned short value, unsigned short port)
{
      int ret0;
      int ret1;

      ret0 = NAME_(outb)(cpssp, (value >> 0) & 0xff, port++);
      ret1 = NAME_(outb)(cpssp, (value >> 8) & 0xff, port++);

      return ret0 | ret1;
}

static inline void
NAME_(gen_text_line)(
      struct cpssp *cpssp,
      struct sig_video *video,
      unsigned int j,
      unsigned char ch,
      unsigned char attr,
      unsigned char start,
      unsigned char end
)
{
      unsigned char mapA;
      unsigned char mapB;
      unsigned char bg_col;
      unsigned char bg_r, bg_g, bg_b;
      unsigned char fg_col;
      unsigned char fg_r, fg_g, fg_b;
      unsigned char map;
      unsigned short bits;
      int i;


      mapA = (((cpssp->NAME.seq_character_map_select >> 5) & 1) << 0)
           | (((cpssp->NAME.seq_character_map_select >> 2) & 3) << 1);
      mapB = (((cpssp->NAME.seq_character_map_select >> 4) & 1) << 0)
           | (((cpssp->NAME.seq_character_map_select >> 0) & 3) << 1);

      bg_col = (attr >> 4) & 0x0f;
      fg_col = (attr >> 0) & 0x0f;

      if (mapA != mapB && (cpssp->NAME.seq_memory_mode >> 1) & 1) {
            map = ((attr >> 3) & 0x01) ? mapA : mapB;
            fg_col &= 0x07;
      } else {
            map = mapA;
      }

      if ((cpssp->NAME.attr_mode_control >> 7) & 1) {
            bg_col = cpssp->NAME.attr_palette[bg_col] & 0x0f;
            bg_col |= (cpssp->NAME.attr_color_select & 0x0f) << 4;
            fg_col = cpssp->NAME.attr_palette[fg_col] & 0x0f;
            fg_col |= (cpssp->NAME.attr_color_select & 0x0f) << 4;
      } else {
            bg_col = cpssp->NAME.attr_palette[bg_col] & 0x3f;
            bg_col |= (cpssp->NAME.attr_color_select & 0x0c) << 4;
            fg_col = cpssp->NAME.attr_palette[fg_col] & 0x3f;
            fg_col |= (cpssp->NAME.attr_color_select & 0x0c) << 4;
      }

      bg_r = video_col_get(cpssp, bg_col, 0);
      bg_g = video_col_get(cpssp, bg_col, 1);
      bg_b = video_col_get(cpssp, bg_col, 2);
      fg_r = video_col_get(cpssp, fg_col, 0);
      fg_g = video_col_get(cpssp, fg_col, 1);
      fg_b = video_col_get(cpssp, fg_col, 2);

      if (start != 0xff && start <= j && j <= end) {
            /* cursor */
            bits = 0xff;

      } else {
            /* font */
            /* read font 8x16 data */
            bits = video_readb(cpssp, 0x20000 | (map << 13) | (ch << 5) | j); 
      }

      for (i = 0; i < 8; i++) {
            if (bits & 0x80) {
                  sig_video_out(video, cpssp, fg_r, fg_g, fg_b);
            } else {
                  sig_video_out(video, cpssp, bg_r, bg_g, bg_b);
            }

            bits <<= 1;
      }

#if 0
      /* enabling this will break some experiments... */
      if ((cpssp->NAME.seq_clocking_mode & 0x01) == 0) {
            /* Generate 9th dot. */
            if (0xc0 <= ch && ch <= 0xdf && (bits & 0x0100) && (cpssp->NAME.attr_mode_control >> 2) & 1) {
                  sig_video_out(video, cpssp, fg_r, fg_g, fg_b);
            } else {
                  sig_video_out(video, cpssp, bg_r, bg_g, bg_b);
            }
      }
#endif
}

static inline void
NAME_(gen_text)(struct cpssp *cpssp, struct sig_video *video)
{
      uint32_t tv;
      int inv;
      int blink;
      unsigned int hde;
      unsigned int vde;
      unsigned int lc;
      unsigned int msl;
      unsigned int x;
      unsigned int y1;
      unsigned short offset1;
      unsigned int scan_count;

      tv = (uint32_t) time_virt();

      /* the state of blinking */
      inv = (tv >> 31) & 1;
      /* blinking turned on? */
      blink = (cpssp->NAME.attr_mode_control >> 3) & 1;

      /*
       * Get number of scan lines.
       */
      vde = cpssp->NAME.crt_vertical_display_end;
      vde |= ((cpssp->NAME.crt_overflow >> 1) & 1) << 8;
      vde |= ((cpssp->NAME.crt_overflow >> 6) & 1) << 9;
      vde++;

      /*
       * Get number of characters per row.
       */
      hde = cpssp->NAME.crt_horizontal_display_end + 1;

      /*
       * Get the line where the screen is split
       */
      lc = cpssp->NAME.crt_line_compare;
      lc |= ((cpssp->NAME.crt_overflow >> 4) & 1) << 8;
      lc |= ((cpssp->NAME.crt_maximum_scan_line >> 6) & 1) << 9;

      /*
       * Get maximum scan line.
       */
      msl = (cpssp->NAME.crt_maximum_scan_line & 0x1f) + 1;

      y1 = cpssp->NAME.scanline % msl;

      scan_count = 1 + vde / REFRESH_CYCLES;
      while (scan_count && cpssp->NAME.scanline < vde) {
            if (cpssp->NAME.scanline == lc) { 
                  y1 = 0;
                  cpssp->NAME.offset = 0x00000;
            } 

            offset1 = cpssp->NAME.offset;
            for (x = 0; x < hde; x++) {
                  unsigned char start;
                  unsigned char end;
                  unsigned char ch;
                  unsigned char attr;

                  ch = video_readb(cpssp, 0x00000 + offset1);
                  attr = video_readb(cpssp, 0x10000 + offset1);

                  /* blinking */
                  if ((attr & 0x80) && blink) {
                        if (inv) {
                              attr &= 0x70;
                              attr |= attr >> 4;
                        } else {
                              attr &= 0x7f;
                        }
                  }

                  /* cursor */
                  if (cpssp->NAME.crt_cur_pos == offset1
                   && (! ((cpssp->NAME.crt_cursor_start >> 5) & 1))
                   && inv) {
                        /* Should be 0x1f instead of 0x0f - FIXME VOSSI */
                        start = cpssp->NAME.crt_cursor_start & 0x0f;
                        end = cpssp->NAME.crt_cursor_end & 0x0f;
                  } else {
                        start = 0xff;
                        end = 0xff;
                  }

                  NAME_(gen_text_line)(cpssp, video, y1, ch, attr, start, end);

                  offset1++;
                  offset1 &= 0x3fff;      /* Correct? FIXME VOSSI */
            }

            cpssp->NAME.scanline++;
            scan_count--;
            sig_video_hor_retrace(video, cpssp);

            y1++;
            if (y1 == msl) {
                  y1 = 0;
                  cpssp->NAME.offset = offset1;
            }
      }

      if (cpssp->NAME.scanline >= vde) {
            cpssp->NAME.scanline = 0;
            cpssp->NAME.offset = cpssp->NAME.crt_top_pos;
            sig_video_vert_retrace(video, cpssp);
      }
}

static inline void
NAME_(gen_planar4_line)(
      struct cpssp *cpssp,
      struct sig_video *video,
      unsigned short offset
)
{
      uint32_t bits;
      int j;

      bits = (video_readb(cpssp, 3 * 65536 + offset) << 24)
           | (video_readb(cpssp, 2 * 65536 + offset) << 16)
           | (video_readb(cpssp, 1 * 65536 + offset) <<  8)
           | (video_readb(cpssp, 0 * 65536 + offset) <<  0);

      for (j = 0; j < TILE_WIDTH; j++) {
            unsigned char col;

            col = ((bits >> (24 + 4)) & 0x08)
                | ((bits >> (16 + 5)) & 0x04)
                | ((bits >> ( 8 + 6)) & 0x02)
                | ((bits >> ( 0 + 7)) & 0x01);
            col &= cpssp->NAME.attr_color_plane_enable;

            if ((cpssp->NAME.attr_mode_control >> 7) & 1) {
                  col = cpssp->NAME.attr_palette[col] & 0x0f;
                  col |= (cpssp->NAME.attr_color_select & 0x0f) << 4;
            } else {
                  col = cpssp->NAME.attr_palette[col] & 0x3f;
                  col |= (cpssp->NAME.attr_color_select & 0x0c) << 4;
            }

            sig_video_out(video, cpssp,
                        video_col_get(cpssp, col, 0),
                        video_col_get(cpssp, col, 1),
                        video_col_get(cpssp, col, 2));

            bits <<= 1;
      }
}

static inline void
NAME_(gen_planar4)(struct cpssp *cpssp, struct sig_video *video)
{
      unsigned int hde;
      unsigned int vde;
      unsigned int x;
      unsigned int scan_count;

      /*
       * Get number of scan lines.
       */
      vde = cpssp->NAME.crt_vertical_display_end;
      vde |= ((cpssp->NAME.crt_overflow >> 1) & 1) << 8;
      vde |= ((cpssp->NAME.crt_overflow >> 6) & 1) << 9;
      vde++;

      /*
       * Get number of characters per row.
       */
      hde = cpssp->NAME.crt_horizontal_display_end + 1;

      scan_count = 1 + vde / REFRESH_CYCLES;
      while (scan_count && cpssp->NAME.scanline < vde) {
            for (x = 0; x < hde; x++) {
                  NAME_(gen_planar4_line)(cpssp, video, cpssp->NAME.offset);
                  cpssp->NAME.offset++;
            }

            cpssp->NAME.scanline++;
            scan_count--;
            sig_video_hor_retrace(video, cpssp);
      }

      if (cpssp->NAME.scanline >= vde) {
            cpssp->NAME.scanline = 0;
            cpssp->NAME.offset = 0;
            sig_video_vert_retrace(video, cpssp);
      }
}

static inline void
NAME_(gen_256colmode)(struct cpssp *cpssp, struct sig_video *video)
{
      unsigned int hde;
      unsigned int vde;
      unsigned int x;
      unsigned int scan_count;

      /*
       * Get number of scan lines.
       */
      vde = cpssp->NAME.crt_vertical_display_end;
      vde |= ((cpssp->NAME.crt_overflow >> 1) & 1) << 8;
      vde |= ((cpssp->NAME.crt_overflow >> 6) & 1) << 9;
      vde++; /* The register contains (lines - 1) so we have to add 1 */

      /* Get number of characters per row. */
      if (((cpssp->NAME.misc_output >> 2) & 3) == 1) {
            hde = 360;
      } else {
            hde = 320;
      }

      scan_count = 1 + vde / REFRESH_CYCLES;
      while (scan_count && cpssp->NAME.scanline < vde) {
            for (x = 0; x < hde; x++) {
                  unsigned char col;

                  col = video_readb(cpssp, (cpssp->NAME.offset % 4) * 0x10000 + (cpssp->NAME.offset / 4));
                  sig_video_out(video, cpssp,
                        video_col_get(cpssp, col, 0),
                        video_col_get(cpssp, col, 1),
                        video_col_get(cpssp, col, 2));
                  sig_video_out(video, cpssp,
                        video_col_get(cpssp, col, 0),
                        video_col_get(cpssp, col, 1),
                        video_col_get(cpssp, col, 2));
                  cpssp->NAME.offset++;
            }
            if ((cpssp->NAME.crt_maximum_scan_line & 0x80) && (cpssp->NAME.scanline & 1)) {
                  /* VGA actually gerates 320x200 as 320x400 by doubling
                   * each line. */
                  cpssp->NAME.offset -= hde;
            }
            if (0x40000 <= cpssp->NAME.offset) {
                  cpssp->NAME.offset -= 0x40000;
            }

            cpssp->NAME.scanline++;
            scan_count--;
            sig_video_hor_retrace(video, cpssp);
      }

      if (cpssp->NAME.scanline >= vde) {
            cpssp->NAME.scanline = 0;
            cpssp->NAME.offset = cpssp->NAME.crt_top_pos * 4;
            sig_video_vert_retrace(video, cpssp);
      }
}

static inline void
NAME_(gen)(struct cpssp *cpssp, struct sig_video *video)
{
      int mode;
      int depth;

      /*
       * Determine video mode by register contents.
       */
      if (cpssp->NAME.gr_misc & 1) {
            /* Graphic mode. */
            if (cpssp->NAME.gr_mode & 0x40) {
                  mode = 0x13;
            } else {
                  mode = 0x12;
            }
      } else {
            /* Text mode. */
            mode = 0x03;
      }

      switch (mode) {
      /* text mode 80x25 */
      case 0x03:
            depth = 0;
            break;

      /* graphic mode 640x480x4 */
      case 0x12:
            depth = 4;
            break;
      /* graphic mode 320x200x8 */
      case 0x13:
            depth = 8;
            break;

      default:
            assert(0);  /* FIXME VOSSI */
      }

      switch (depth) {
      case 0:
            NAME_(gen_text)(cpssp, video);
            break;
      case 4:
            NAME_(gen_planar4)(cpssp, video);
            break;
      case 8:
            NAME_(gen_256colmode)(cpssp, video);
            break;
      default:
            assert(0);  /* FIXME VOSSI */
      }
}

static inline void
NAME_(init)(struct cpssp *cpssp)
{
}

static inline void
NAME_(create)(const char *name, int nr)
{
}

static inline void
NAME_(destroy)(const char *name, int nr)
{
}

#undef TILE_WIDTH
#undef DEBUG

#endif /* BEHAVIOUR */


Generated by  Doxygen 1.6.0   Back to index