/*
 * 86Box    A hypervisor and IBM PC system emulator that specializes in
 *          running old operating systems and software designed for IBM
 *          PC systems and compatibles from 1981 through fairly recent
 *          system designs based on the PCI bus.
 *
 *          This file is part of the 86Box distribution.
 *
 *          Emulation of the 8514/A-compatible Mach8 and Mach32 graphics
 *          chips from ATI for the ISA/VLB/MCA/PCI buses.
 *
 *
 *
 * Authors: TheCollector1995.
 *
 *          Copyright 2022-2024 TheCollector1995.
 */
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdatomic.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/mca.h>
#include <86box/pci.h>
#include <86box/rom.h>
#include <86box/plat.h>
#include <86box/thread.h>
#include <86box/video.h>
#include <86box/i2c.h>
#include <86box/vid_ddc.h>
#include <86box/vid_8514a.h>
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
#include <86box/vid_ati_eeprom.h>
#include <86box/vid_ati_mach8.h>

#define BIOS_MACH8_VGA_ROM_PATH  "roms/video/mach8/BIOS.BIN"
#define BIOS_MACH32_ISA_ROM_PATH "roms/video/mach32/ATi Mach32 Graphics Pro ISA.BIN"
#define BIOS_MACH32_VLB_ROM_PATH "roms/video/mach32/MACH32VLB.VBI"
#define BIOS_MACH32_MCA_ROM_PATH "roms/video/mach32/MACH32MCA_Olivetti.BIN"
#define BIOS_MACH32_PCI_ROM_PATH "roms/video/mach32/intelopt_00000.rom"

static video_timings_t timing_gfxultra_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 };
static video_timings_t timing_mach32_vlb   = { .type = VIDEO_BUS, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 };
static video_timings_t timing_mach32_mca   = { .type = VIDEO_MCA, .write_b = 4, .write_w = 5, .write_l = 10, .read_b = 5, .read_w = 5, .read_l = 10 };
static video_timings_t timing_mach32_pci   = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 };

static void     mach_accel_outb(uint16_t port, uint8_t val, void *priv);
static void     mach_accel_outw(uint16_t port, uint16_t val, void *priv);
static uint8_t  mach_accel_inb(uint16_t port, void *priv);
static uint16_t mach_accel_inw(uint16_t port, void *priv);
static uint8_t  mach_in(uint16_t addr, void *priv);

#ifdef ATI_8514_ULTRA
static void     ati8514_accel_outb(uint16_t port, uint8_t val, void *priv);
static void     ati8514_accel_outw(uint16_t port, uint16_t val, void *priv);
static void     ati8514_accel_outl(uint16_t port, uint32_t val, void *priv);
static uint8_t  ati8514_accel_inb(uint16_t port, void *priv);
static uint16_t ati8514_accel_inw(uint16_t port, void *priv);
static uint32_t ati8514_accel_inl(uint16_t port, void *priv);
#endif


static void mach32_updatemapping(mach_t *mach, svga_t *svga);

#ifdef ENABLE_MACH_LOG
int mach_do_log = ENABLE_MACH_LOG;

static void
mach_log(const char *fmt, ...)
{
    va_list ap;

    if (mach_do_log) {
        va_start(ap, fmt);
        pclog_ex(fmt, ap);
        va_end(ap);
    }
}
#else
#    define mach_log(fmt, ...)
#endif

#define WRITE8(addr, var, val)                        \
    switch ((addr) & 1) {                             \
        case 0:                                       \
            var = (var & 0xff00) | (val);             \
            break;                                    \
        case 1:                                       \
            var = (var & 0x00ff) | ((val) << 8);      \
            break;                                    \
    }

#define READ8(addr, var)                \
    switch ((addr) & 1) {               \
        case 0:                         \
            temp = (var) & 0xff;        \
            break;                      \
        case 1:                         \
            temp = ((var) >> 8) & 0xff; \
            break;                      \
    }

#define READ_PIXTRANS_BYTE_IO(cx, n) \
    if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \
        if (dev->bpp) { \
            if (n == 0) \
                mach->accel.pix_trans[(n)] = vram_w[(dev->accel.dest + (cx) + (n)) & (dev->vram_mask >> 1)] & 0xff; \
            else \
                mach->accel.pix_trans[(n)] = vram_w[(dev->accel.dest + (cx) + (n)) & (dev->vram_mask >> 1)] >> 8; \
        } else { \
            mach->accel.pix_trans[(n)] = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \
        } \
    }

#define READ_PIXTRANS_WORD(cx, n)                                                                    \
    if ((cmd == 0) || (cmd == 1) || (cmd == 5) || (mach->accel.cmd_type == -1)) { \
        if (dev->bpp) \
            temp = vram_w[((dev->accel.cy * dev->pitch) + (cx) + (n)) & (dev->vram_mask >> 1)];             \
        else { \
            temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask];             \
            temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \
        } \
    } else if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \
        if (dev->bpp) \
            temp = vram_w[((dev->accel.dest) + (cx) + (n)) & (dev->vram_mask >> 1)];                           \
        else { \
            temp = dev->vram[((dev->accel.dest) + (cx) + (n)) & dev->vram_mask];                           \
            temp |= (dev->vram[((dev->accel.dest) + (cx) + (n + 1)) & dev->vram_mask] << 8);               \
        } \
    } else if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) { \
        if (dev->bpp) \
            temp = vram_w[((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & (dev->vram_mask >> 1)]; \
        else { \
            temp = dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & dev->vram_mask]; \
            temp |= (dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n + 1)) & dev->vram_mask] << 8); \
        } \
    }

#define READ(addr, dat) \
        if (dev->bpp) \
            dat = vram_w[(addr) & (dev->vram_mask >> 1)]; \
        else \
            dat = dev->vram[(addr) & (dev->vram_mask)];

#define MIX(mixmode, dest_dat, src_dat)                                                       \
    {                                                                                         \
        switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) {    \
            case 0x00:                                                                        \
                dest_dat = ~dest_dat;                                                         \
                break;                                                                        \
            case 0x01:                                                                        \
                dest_dat = 0;                                                                 \
                break;                                                                        \
            case 0x02:                                                                        \
                dest_dat = ~0;                                                                \
                break;                                                                        \
            case 0x03:                                                                        \
                dest_dat = dest_dat;                                                          \
                break;                                                                        \
            case 0x04:                                                                        \
                dest_dat = ~src_dat;                                                          \
                break;                                                                        \
            case 0x05:                                                                        \
                dest_dat = src_dat ^ dest_dat;                                                \
                break;                                                                        \
            case 0x06:                                                                        \
                dest_dat = ~(src_dat ^ dest_dat);                                             \
                break;                                                                        \
            case 0x07:                                                                        \
                dest_dat = src_dat;                                                           \
                break;                                                                        \
            case 0x08:                                                                        \
                dest_dat = ~(src_dat & dest_dat);                                             \
                break;                                                                        \
            case 0x09:                                                                        \
                dest_dat = ~src_dat | dest_dat;                                               \
                break;                                                                        \
            case 0x0a:                                                                        \
                dest_dat = src_dat | ~dest_dat;                                               \
                break;                                                                        \
            case 0x0b:                                                                        \
                dest_dat = src_dat | dest_dat;                                                \
                break;                                                                        \
            case 0x0c:                                                                        \
                dest_dat = src_dat & dest_dat;                                                \
                break;                                                                        \
            case 0x0d:                                                                        \
                dest_dat = src_dat & ~dest_dat;                                               \
                break;                                                                        \
            case 0x0e:                                                                        \
                dest_dat = ~src_dat & dest_dat;                                               \
                break;                                                                        \
            case 0x0f:                                                                        \
                dest_dat = ~(src_dat | dest_dat);                                             \
                break;                                                                        \
            case 0x10:                                                                        \
                dest_dat = MIN(src_dat, dest_dat);                                            \
                break;                                                                        \
            case 0x11:                                                                        \
                dest_dat = dest_dat - src_dat;                                                \
                break;                                                                        \
            case 0x12:                                                                        \
                dest_dat = src_dat - dest_dat;                                                \
                break;                                                                        \
            case 0x13:                                                                        \
                dest_dat = src_dat + dest_dat;                                                \
                break;                                                                        \
            case 0x14:                                                                        \
                dest_dat = MAX(src_dat, dest_dat);                                            \
                break;                                                                        \
            case 0x15:                                                                        \
                dest_dat = (dest_dat - src_dat) / 2;                                          \
                break;                                                                        \
            case 0x16:                                                                        \
                dest_dat = (src_dat - dest_dat) / 2;                                          \
                break;                                                                        \
            case 0x17:                                                                        \
                dest_dat = (dest_dat + src_dat) / 2;                                          \
                break;                                                                        \
            case 0x18:                                                                        \
                dest_dat = MAX(0, (dest_dat - src_dat));                                      \
                break;                                                                        \
            case 0x19:                                                                        \
                dest_dat = MAX(0, (dest_dat - src_dat));                                      \
                break;                                                                        \
            case 0x1a:                                                                        \
                dest_dat = MAX(0, (src_dat - dest_dat));                                      \
                break;                                                                        \
            case 0x1b:                                                                        \
                dest_dat = MIN(0xff, (dest_dat + src_dat));                                   \
                break;                                                                        \
            case 0x1c:                                                                        \
                dest_dat = MAX(0, (dest_dat - src_dat)) / 2;                                  \
                break;                                                                        \
            case 0x1d:                                                                        \
                dest_dat = MAX(0, (dest_dat - src_dat)) / 2;                                  \
                break;                                                                        \
            case 0x1e:                                                                        \
                dest_dat = MAX(0, (src_dat - dest_dat)) / 2;                                  \
                break;                                                                        \
            case 0x1f:                                                                        \
                dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \
                break;                                                                        \
        }                                                                                     \
    }


#define WRITE(addr, dat)                                         \
    if (dev->bpp) { \
        vram_w[((addr)) & (dev->vram_mask >> 1)]                = dat; \
        dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = changeframecount; \
    } else { \
        dev->vram[((addr)) & (dev->vram_mask)]                = dat; \
        dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \
    }

static int
mach_pixel_write(mach_t *mach)
{
    if (mach->accel.dp_config & 1)
        return 1;

    return 0;
}

static int
mach_pixel_read(mach_t *mach)
{
    if (mach->accel.dp_config & 1)
        return 0;

    return 1;
}

static void
mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint32_t cpu_dat, mach_t *mach, ibm8514_t *dev)
{
    int           compare_mode;
    uint16_t      poly_src     = 0;
    uint16_t      rd_mask      = dev->accel.rd_mask;
    uint16_t      wrt_mask     = dev->accel.wrt_mask;
    uint16_t      dest_cmp_clr = dev->accel.color_cmp;
    int           frgd_sel;
    int           bkgd_sel;
    int           mono_src;
    int           compare  = 0;
    uint16_t      src_dat  = 0;
    uint16_t      dest_dat = 0;
    uint16_t      old_dest_dat;
    uint16_t     *vram_w    = (uint16_t *) dev->vram;
    uint16_t      mix       = 0;
    int16_t       clip_l    = dev->accel.clip_left & 0x7ff;
    int16_t       clip_t    = dev->accel.clip_top & 0x7ff;
    int16_t       clip_r    = dev->accel.multifunc[4] & 0x7ff;
    int16_t       clip_b    = dev->accel.multifunc[3] & 0x7ff;
    uint32_t      mono_dat0 = 0;
    uint32_t      mono_dat1 = 0;

    if (!dev->bpp) {
        rd_mask &= 0xff;
        dest_cmp_clr &= 0xff;
    }

    compare_mode = (mach->accel.dest_cmp_fn >> 3) & 7;
    frgd_sel     = (mach->accel.dp_config >> 13) & 7;
    bkgd_sel     = (mach->accel.dp_config >> 7) & 3;
    mono_src     = (mach->accel.dp_config >> 5) & 3;

    if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) {
        mach->force_busy  = 1;
        dev->force_busy   = 1;
        dev->force_busy2  = 1;
    }

    if (cpu_input) {
        if (dev->bpp) {
            if ((mach->accel.dp_config & 0x200) && (count == 2)) {
                count >>= 1;
            }
        }
    }

    if ((dev->accel_bpp == 8) || (dev->accel_bpp == 15) || (dev->accel_bpp == 16) || (dev->accel_bpp == 24)) {
        if ((cmd_type == 2) && cpu_input) {
            mach_log("RdMask=%04x, DPCONFIG=%04x, Clipping: l=%d, r=%d, t=%d, b=%d, LineDrawOpt=%04x, BPP=%d, CMDType = %d, offs=%08x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, d(%d,%d), dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monpattern = %x.\n", rd_mask, mach->accel.dp_config, clip_l, clip_r, clip_t, clip_b, mach->accel.linedraw_opt, dev->accel_bpp, cmd_type, mach->accel.ge_offset, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, dev->accel.cur_y, mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable);
        }
    }

    switch (cmd_type) {
        case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/
            if (!cpu_input) {
                dev->accel.dx = dev->accel.cur_x;
                if (dev->accel.cur_x >= 0x600)
                    dev->accel.dx |= ~0x5ff;
                dev->accel.dy = dev->accel.cur_y;
                if (dev->accel.cur_y >= 0x600)
                    dev->accel.dy |= ~0x5ff;

                dev->accel.cx = dev->accel.destx_distp;
                if (dev->accel.destx_distp >= 0x600)
                    dev->accel.cx |= ~0x5ff;
                dev->accel.cy = dev->accel.desty_axstp;
                if (dev->accel.desty_axstp >= 0x600)
                    dev->accel.cy |= ~0x5ff;

                mach->accel.width     = mach->accel.bres_count;
                dev->accel.sx         = 0;
                mach->accel.poly_fill = 0;

                mach->accel.color_pattern_idx = ((dev->accel.cx + (dev->accel.cy << 3)) & mach->accel.patt_len);

                mach->accel.stepx = (mach->accel.linedraw_opt & 0x20) ? 1 : -1;
                mach->accel.stepy = (mach->accel.linedraw_opt & 0x80) ? 1 : -1;

                mach_log("Extended bresenham, CUR(%d,%d), DEST(%d,%d), width = %d, options = %04x, dpconfig = %04x, opt_ena = %03x.\n", dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.linedraw_opt, mach->accel.dp_config, mach->accel.max_waitstates & 0x100);

                if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) {
                    if (mach_pixel_write(mach)) {
                        dev->data_available  = 0;
                        dev->data_available2 = 0;
                        return;
                    } else if (mach_pixel_read(mach)) {
                        dev->data_available  = 1;
                        dev->data_available2 = 1;
                        return;
                    }
                }
            }

            if (frgd_sel == 5) {
                for (int x = 0; x <= mach->accel.patt_len; x++) {
                    mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len];
                }

                /*The destination coordinates should match the pattern index.*/
                if (mach->accel.color_pattern_idx != mach->accel.patt_idx)
                    mach->accel.color_pattern_idx = mach->accel.patt_idx;
            }

            if (mono_src == 1) {
                count               = mach->accel.width;
                mix_dat             = mach->accel.patt_data[0x10];
                dev->accel.temp_cnt = 8;
            }

            if (mach->accel.linedraw_opt & 0x08) { /*Vector Line*/
                while (count--) {
                    switch (mono_src) {
                        case 0:
                            mix = 1;
                            break;
                        case 1:
                            if (!dev->accel.temp_cnt) {
                                dev->accel.temp_cnt = 8;
                                mix_dat >>= 8;
                            }
                            mix = (mix_dat & 0x80);
                            dev->accel.temp_cnt--;
                            mix_dat <<= 1;
                            mix_dat |= 1;
                            break;
                        case 2:
                            if (mach->accel.dp_config & 0x1000) {
                                mix = mix_dat >> 0x1f;
                                mix_dat <<= 1;
                            } else {
                                if (mach->accel.dp_config & 0x200) {
                                    mix = mix_dat & 1;
                                    mix_dat >>= 1;
                                } else {
                                    mix = mix_dat & 0x80;
                                    mix_dat <<= 1;
                                    mix_dat |= 1;
                                }
                            }
                            break;
                        case 3:
                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix);
                            }
                            mix = (mix & rd_mask) == rd_mask;
                            break;

                        default:
                            break;
                    }

                    if (((dev->accel.dx) >= clip_l) && ((dev->accel.dx) <= clip_r) && ((dev->accel.dy) >= clip_t) && ((dev->accel.dy) <= clip_b)) {
                        switch (mix ? frgd_sel : bkgd_sel) {
                            case 0:
                                src_dat = dev->accel.bkgd_color;
                                break;
                            case 1:
                                src_dat = dev->accel.frgd_color;
                                break;
                            case 2:
                                src_dat = cpu_dat;
                                break;
                            case 3:
                                if (mach_pixel_read(mach))
                                    src_dat = cpu_dat;
                                else {
                                    if (dev->bpp) {
                                        READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), src_dat);
                                    } else {
                                        READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), src_dat);
                                    }
                                    if (mono_src == 3) {
                                        src_dat = (src_dat & rd_mask) == rd_mask;
                                    }
                                }
                                break;
                            case 5:
                                if (mix) {
                                    src_dat = mach->accel.color_pattern[((dev->accel.dx) + ((dev->accel.dy) << 3)) & mach->accel.patt_len];
                                } else
                                    src_dat = 0;
                                break;

                            default:
                                break;
                        }

                        if (mach->accel.linedraw_opt & 0x02) {
                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src);
                            }
                            poly_src = ((poly_src & rd_mask) == rd_mask);
                            if (poly_src)
                                mach->accel.poly_fill = !mach->accel.poly_fill;
                        }

                        if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) {
                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                            }

                            switch (compare_mode) {
                                case 1:
                                    compare = 1;
                                    break;
                                case 2:
                                    compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 3:
                                    compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 4:
                                    compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 5:
                                    compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 6:
                                    compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 7:
                                    compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                                    break;

                                default:
                                    break;
                            }

                            if (!compare) {
                                if (mach_pixel_write(mach)) {
                                    old_dest_dat = dest_dat;
                                    MIX(mix, dest_dat, src_dat);
                                    dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                                }
                            }

                            if (mach->accel.dp_config & 0x10) {
                                if (mach->accel.linedraw_opt & 0x04) {
                                    if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) {
                                        if (dev->bpp) {
                                            WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                        } else {
                                            WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                        }
                                    }
                                } else {
                                    if (dev->bpp) {
                                        WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                    } else {
                                        WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                    }
                                }
                            }
                        }
                    }

                    if ((mono_src == 1) && !count)
                        break;
                    else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width))
                        break;

                    if (dev->bpp)
                        cpu_dat >>= 16;
                    else
                        cpu_dat >>= 8;

                    switch (mach->accel.linedraw_opt & 0xe0) {
                        case 0x00:
                            dev->accel.cx++;
                            dev->accel.dx++;
                            break;
                        case 0x20:
                            dev->accel.cx++;
                            dev->accel.dx++;
                            dev->accel.cy--;
                            dev->accel.dy--;
                            break;
                        case 0x40:
                            dev->accel.cy--;
                            dev->accel.dy--;
                            break;
                        case 0x60:
                            dev->accel.cx--;
                            dev->accel.dx--;
                            dev->accel.cy--;
                            dev->accel.dy--;
                            break;
                        case 0x80:
                            dev->accel.cx--;
                            dev->accel.dx--;
                            break;
                        case 0xa0:
                            dev->accel.cx--;
                            dev->accel.dx--;
                            dev->accel.cy++;
                            dev->accel.dy++;
                            break;
                        case 0xc0:
                            dev->accel.cy++;
                            dev->accel.dy++;
                            break;
                        case 0xe0:
                            dev->accel.cx++;
                            dev->accel.dx++;
                            dev->accel.cy++;
                            dev->accel.dy++;
                            break;

                        default:
                            break;
                    }

                    dev->accel.sx++;
                }
            } else { /*Bresenham*/
                while (count--) {
                    switch (mono_src) {
                        case 0:
                            mix = 1;
                            break;
                        case 1:
                            if (!dev->accel.temp_cnt) {
                                dev->accel.temp_cnt = 8;
                                mix_dat >>= 8;
                            }
                            mix = (mix_dat & 0x80);
                            dev->accel.temp_cnt--;
                            mix_dat <<= 1;
                            mix_dat |= 1;
                            break;
                        case 2:
                            if (mach->accel.dp_config & 0x1000) {
                                mix = mix_dat >> 0x1f;
                                mix_dat <<= 1;
                            } else {
                                if (mach->accel.dp_config & 0x200) {
                                    mix = mix_dat & 1;
                                    mix_dat >>= 1;
                                } else {
                                    mix = mix_dat & 0x80;
                                    mix_dat <<= 1;
                                    mix_dat |= 1;
                                }
                            }
                            break;
                        case 3:
                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix);
                            }
                            mix = (mix & rd_mask) == rd_mask;
                            break;

                        default:
                            break;
                    }

                    if (((dev->accel.dx) >= clip_l) && ((dev->accel.dx) <= clip_r) && ((dev->accel.dy) >= clip_t) && ((dev->accel.dy) <= clip_b)) {
                        switch (mix ? frgd_sel : bkgd_sel) {
                            case 0:
                                src_dat = dev->accel.bkgd_color;
                                break;
                            case 1:
                                src_dat = dev->accel.frgd_color;
                                break;
                            case 2:
                                src_dat = cpu_dat;
                                break;
                            case 3:
                                if (mach_pixel_read(mach))
                                    src_dat = cpu_dat;
                                else {
                                    if (dev->bpp) {
                                        READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), src_dat);
                                    } else {
                                        READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), src_dat);
                                    }
                                    if (mono_src == 3) {
                                        src_dat = (src_dat & rd_mask) == rd_mask;
                                    }
                                }
                                break;
                            case 5:
                                if (mix) {
                                    src_dat = mach->accel.color_pattern[((dev->accel.dx) + ((dev->accel.dy) << 3)) & mach->accel.patt_len];
                                } else
                                    src_dat = 0;
                                break;

                            default:
                                break;
                        }

                        if (mach->accel.linedraw_opt & 0x02) {
                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src);
                            }
                            poly_src = ((poly_src & rd_mask) == rd_mask);
                            if (poly_src)
                                mach->accel.poly_fill = !mach->accel.poly_fill;
                        }

                        if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) {
                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                            }

                            switch (compare_mode) {
                                case 1:
                                    compare = 1;
                                    break;
                                case 2:
                                    compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 3:
                                    compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 4:
                                    compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 5:
                                    compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 6:
                                    compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 7:
                                    compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                                    break;

                                default:
                                    break;
                            }

                            if (!compare) {
                                if (mach_pixel_write(mach)) {
                                    old_dest_dat = dest_dat;
                                    MIX(mix, dest_dat, src_dat);
                                    dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                                }
                            }

                            if (mach->accel.dp_config & 0x10) {
                                if (mach->accel.linedraw_opt & 0x04) {
                                    if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) {
                                        if (dev->bpp) {
                                            WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                        } else {
                                            WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                        }
                                    }
                                } else {
                                    if (dev->bpp) {
                                        WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                    } else {
                                        WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat);
                                    }
                                }
                            }
                        }
                    }

                    if ((mono_src == 1) && !count)
                        break;
                    else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width))
                        break;

                    if (dev->bpp)
                        cpu_dat >>= 16;
                    else
                        cpu_dat >>= 8;

                    if (mach->accel.linedraw_opt & 0x40) {
                        dev->accel.dy += mach->accel.stepy;
                        if ((frgd_sel == 3) || (bkgd_sel == 3))
                            dev->accel.cy += mach->accel.stepy;

                        if (dev->accel.err_term >= 0) {
                            dev->accel.err_term += dev->accel.destx_distp;
                            dev->accel.dx += mach->accel.stepx;
                            if ((frgd_sel == 3) || (bkgd_sel == 3))
                                dev->accel.cx += mach->accel.stepx;
                        } else {
                            dev->accel.err_term += dev->accel.desty_axstp;
                        }
                    } else {
                        dev->accel.dx += mach->accel.stepx;
                        if ((frgd_sel == 3) || (bkgd_sel == 3))
                            dev->accel.cx += mach->accel.stepx;

                        if (dev->accel.err_term >= 0) {
                            dev->accel.err_term += dev->accel.destx_distp;
                            dev->accel.dy += mach->accel.stepy;
                            if ((frgd_sel == 3) || (bkgd_sel == 3))
                                dev->accel.cy += mach->accel.stepy;
                        } else {
                            dev->accel.err_term += dev->accel.desty_axstp;
                        }
                    }

                    dev->accel.sx++;
                }
            }
            mach->accel.poly_fill = 0;
            dev->accel.cur_x = dev->accel.dx;
            dev->accel.cur_y = dev->accel.dy;
            break;

        case 2: /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/
            if (!cpu_input) {
                mach->accel.stepx = 0;
                mach->accel.stepy = 0;

                dev->accel.dx = dev->accel.cur_x;
                if (dev->accel.cur_x >= 0x600)
                    dev->accel.dx |= ~0x5ff;

                dev->accel.dy = dev->accel.cur_y;
                if (dev->accel.cur_y >= 0x600)
                    dev->accel.dy |= ~0x5ff;

                if (mach->accel.dp_config == 0x5211) {
                    if (mach->accel.dest_x_end == 1024) {
                        goto skip_dx;
                    }
                }
                /*Destination Width*/
                if (mach->accel.dest_x_start != dev->accel.dx)
                    mach->accel.dest_x_start = dev->accel.dx;

skip_dx:
                mach->accel.dx_start = mach->accel.dest_x_start;
                if (mach->accel.dest_x_start >= 0x600)
                    mach->accel.dx_start |= ~0x5ff;

                mach->accel.dx_end = mach->accel.dest_x_end;
                if (mach->accel.dest_x_end >= 0x600)
                    mach->accel.dx_end |= ~0x5ff;

                if (mach->accel.dx_end > mach->accel.dx_start) {
                    mach->accel.width = (mach->accel.dx_end - mach->accel.dx_start);
                    mach->accel.stepx = 1;
                } else if (mach->accel.dx_end < mach->accel.dx_start) {
                    mach->accel.width = (mach->accel.dx_start - mach->accel.dx_end);
                    mach->accel.stepx = -1;
                    if (dev->accel.dx > 0)
                        dev->accel.dx--;
                    mach_log("BitBLT: Dst Negative X, dxstart = %d, end = %d, width = %d, dx = %d, dpconfig = %04x.\n", mach->accel.dest_x_start, mach->accel.dest_x_end, mach->accel.width, dev->accel.dx, mach->accel.dp_config);
                } else {
                    mach->accel.stepx = 1;
                    mach->accel.width = 0;
                    mach_log("BitBLT: Dst Indeterminate X, dpconfig = %04x, destxend = %d, destxstart = %d.\n", mach->accel.dp_config, mach->accel.dest_x_end, mach->accel.dest_x_start);
                }

                dev->accel.sx                 = 0;
                mach->accel.poly_fill         = 0;
                mach->accel.color_pattern_idx = ((dev->accel.dx + (dev->accel.dy << 3)) & mach->accel.patt_len);
                if ((dev->accel_bpp == 24) && (mono_src != 1)) {
                    if (mach->accel.color_pattern_idx == mach->accel.patt_len)
                        mach->accel.color_pattern_idx = mach->accel.patt_data_idx;
                } else if ((dev->accel_bpp == 24) && (frgd_sel == 5) && (mono_src == 1) && (mach->accel.patt_len_reg & 0x4000))
                    mach->accel.color_pattern_idx = 0;

                /*Height*/
                mach->accel.dy_start = dev->accel.cur_y;
                if (dev->accel.cur_y >= 0x600)
                    mach->accel.dy_start |= ~0x5ff;
                mach->accel.dy_end = mach->accel.dest_y_end;
                if (mach->accel.dest_y_end >= 0x600)
                    mach->accel.dy_end |= ~0x5ff;

                if (mach->accel.dy_end > mach->accel.dy_start) {
                    mach->accel.height = (mach->accel.dy_end - mach->accel.dy_start);
                    mach->accel.stepy  = 1;
                } else if (mach->accel.dy_end < mach->accel.dy_start) {
                    mach->accel.height = (mach->accel.dy_start - mach->accel.dy_end);
                    mach->accel.stepy  = -1;
                } else {
                    mach->accel.height = 0;
                    mach->accel.stepy  = 1;
                }

                dev->accel.sy = 0;
                if (dev->bpp)
                    dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch));
                else
                    dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch));

                mach->accel.src_stepx = 0;

                /*Source Width*/
                dev->accel.cx = mach->accel.src_x;
                if (mach->accel.src_x >= 0x600)
                    dev->accel.cx |= ~0x5ff;

                dev->accel.cy = mach->accel.src_y;
                if (mach->accel.src_y >= 0x600)
                    dev->accel.cy |= ~0x5ff;

                mach->accel.sx_start = mach->accel.src_x_start;
                if (mach->accel.src_x_start >= 0x600)
                    mach->accel.sx_start |= ~0x5ff;

                mach->accel.sx_end = mach->accel.src_x_end;
                if (mach->accel.src_x_end >= 0x600)
                    mach->accel.sx_end |= ~0x5ff;

                if (mach->accel.sx_end > mach->accel.sx_start) {
                    mach->accel.src_width = (mach->accel.sx_end - mach->accel.sx_start);
                    mach->accel.src_stepx = 1;
                    mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_start, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1);
                } else if (mach->accel.sx_end < mach->accel.sx_start) {
                    mach->accel.src_width = (mach->accel.sx_start - mach->accel.sx_end);
                    mach->accel.src_stepx = -1;
                    if (dev->accel.cx > 0)
                        dev->accel.cx--;
                    mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1);
                } else {
                    mach->accel.src_stepx = 1;
                    mach->accel.src_width = 0;
                    mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1);
                }
                mach->accel.sx = 0;
                if (dev->bpp)
                    dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch));
                else
                    dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch));

                if ((dev->accel_bpp == 24) && (frgd_sel == 5))
                    mach_log("BitBLT=%04x, WH(%d,%d), SRCWidth=%d, c(%d,%d), s(%d,%d).\n", mach->accel.dp_config, mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy);
                else if (mach->accel.dp_config & 0x02)
                    mach_log("BitBLT=%04x, Pitch=%d, C(%d,%d), D(%d,%d), SRCWidth=%d, SRCXStep=%d, WH(%d,%d), clipt=%d, clipb=%d, geoffset=%08x.\n", mach->accel.dp_config, dev->ext_pitch, mach->accel.src_x, mach->accel.src_y, dev->accel.cur_x, dev->accel.cur_y, mach->accel.src_width, mach->accel.src_stepx, mach->accel.width, mach->accel.height, clip_t, clip_b, (mach->accel.ge_offset << 2));

                if (mono_src == 1) {
                    if ((mach->accel.mono_pattern_enable) && !(mach->accel.patt_len_reg & 0x4000)) {
                        mono_dat0 = mach->accel.patt_data[0x10];
                        mono_dat0 |= (mach->accel.patt_data[0x11] << 8);
                        mono_dat0 |= (mach->accel.patt_data[0x12] << 16);
                        mono_dat0 |= (mach->accel.patt_data[0x13] << 24);
                        mono_dat1 = mach->accel.patt_data[0x14];
                        mono_dat1 |= (mach->accel.patt_data[0x15] << 8);
                        mono_dat1 |= (mach->accel.patt_data[0x16] << 16);
                        mono_dat1 |= (mach->accel.patt_data[0x17] << 24);

                        for (uint8_t y = 0; y < 8; y++) {
                            for (uint8_t x = 0; x < 8; x++) {
                                uint32_t temp                      = (y & 4) ? mono_dat1 : mono_dat0;
                                mach->accel.mono_pattern[y][7 - x] = (temp >> (x + ((y & 3) << 3))) & 1;
                            }
                        }
                    }
                }

                if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) {
                    if (mach_pixel_write(mach)) {
                        dev->data_available  = 0;
                        dev->data_available2 = 0;
                        return;
                    } else if (mach_pixel_read(mach)) {
                        dev->data_available  = 1;
                        dev->data_available2 = 1;
                        return;
                    }
                }
            }

            if (mono_src == 1) {
                if (!mach->accel.mono_pattern_enable && !(mach->accel.patt_len_reg & 0x4000)) {
                    count               = mach->accel.width;
                    mix_dat             = mach->accel.patt_data[0x10] ^ ((mach->accel.patt_idx & 1) ? 0xff : 0);
                    dev->accel.temp_cnt = 8;
                }
            }

            if (frgd_sel == 5) {
                if (dev->bpp) {
                    for (int x = 0; x <= mach->accel.patt_len; x += 2) {
                        mach->accel.color_pattern_word[x + (mach->accel.color_pattern_idx & 1)] = (mach->accel.patt_data[x & mach->accel.patt_len] & 0xff);
                        mach->accel.color_pattern_word[x + (mach->accel.color_pattern_idx & 1)] |= (mach->accel.patt_data[(x + 1) & mach->accel.patt_len] << 8);
                    }
                } else {
                    if ((dev->accel_bpp == 24) && (mach->accel.patt_len < 3)) {
                        for (int x = 0; x <= mach->accel.patt_len; x++) {
                            mach->accel.color_pattern[x] = mach->accel.patt_data[x];
                            mach_log("BITBLT: Color Pattern 24bpp[%d]=%02x, dataidx=%d, pattlen=%d.\n", x, mach->accel.color_pattern[x], mach->accel.patt_data_idx, mach->accel.patt_len);
                        }
                    } else {
                        for (int x = 0; x <= mach->accel.patt_len; x++) {
                            mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len];
                        }
                    }
                }

                /*The destination coordinates should match the pattern index.*/
                if (mach->accel.color_pattern_idx != mach->accel.patt_idx)
                    mach->accel.color_pattern_idx = mach->accel.patt_idx;
            }

            if (mach->accel.dy_end == mach->accel.dy_start) {
                mach_log("No DEST.\n");
                return;
            }

            if ((mono_src == 3) || (bkgd_sel == 3) || (frgd_sel == 3)) {
                if (mach->accel.sx_end == mach->accel.sx_start) {
                    mach_log("No SRC.\n");
                    return;
                }
            }

            if (cpu_input) {
                if (mach->accel.dp_config == 0x3251) {
                    mach_log("DPCONFIG 3251: monosrc=%d, frgdsel=%d, bkgdsel=%d, pitch=%d.\n", mono_src, frgd_sel, bkgd_sel, dev->pitch);
                    if (dev->accel.sy == mach->accel.height)
                        return;
                }
            }

            while (count--) {
                switch (mono_src) {
                    case 0:
                        mix = 1;
                        break;
                    case 1:
                        if (mach->accel.mono_pattern_enable)
                            mix = mach->accel.mono_pattern[dev->accel.dy & 7][dev->accel.dx & 7];
                        else {
                            if ((dev->accel_bpp == 24) && (frgd_sel == 5) && (mach->accel.patt_len_reg & 0x4000))
                                mix = 1;
                            else {
                                if (!dev->accel.temp_cnt) {
                                    dev->accel.temp_cnt = 8;
                                    mix_dat >>= 8;
                                }
                                mix = (mix_dat & 0x80);
                                dev->accel.temp_cnt--;
                                mix_dat <<= 1;
                                mix_dat |= 1;
                            }
                        }
                        break;
                    case 2:
                        if (mach->accel.dp_config & 0x1000) {
                            mix = mix_dat >> 0x1f;
                            mix_dat <<= 1;
                        } else {
                            if (mach->accel.dp_config & 0x200) {
                                mix = mix_dat & 1;
                                mix_dat >>= 1;
                            } else {
                                mix = mix_dat & 0x80;
                                mix_dat <<= 1;
                                mix_dat |= 1;
                            }
                        }
                        break;
                    case 3:
                        READ(dev->accel.src + dev->accel.cx, mix);
                        mix = (mix & rd_mask) == rd_mask;
                        break;

                    default:
                        break;
                }

                if (((dev->accel.dx) >= clip_l) && ((dev->accel.dx) <= clip_r) && ((dev->accel.dy) >= clip_t) && ((dev->accel.dy) <= clip_b)) {
                    if ((mach->accel.dp_config & 0x02) || (mach->accel.linedraw_opt & 0x02)) {
                        READ(dev->accel.src + dev->accel.cx, poly_src);
                        poly_src = ((poly_src & rd_mask) == rd_mask);
                        if (poly_src)
                            mach->accel.poly_fill ^= 1;
                    }

                    if (mach->accel.poly_fill || !(mach->accel.dp_config & 0x02) || !(mach->accel.linedraw_opt & 0x02)) {
                        switch (mix ? frgd_sel : bkgd_sel) {
                            case 0:
                                src_dat = dev->accel.bkgd_color;
                                break;
                            case 1:
                                src_dat = dev->accel.frgd_color;
                                break;
                            case 2:
                                src_dat = cpu_dat;
                                break;
                            case 3:
                                if (mach_pixel_read(mach))
                                    src_dat = cpu_dat;
                                else {
                                    READ(dev->accel.src + dev->accel.cx, src_dat);
                                    if (mono_src == 3)
                                        src_dat = (src_dat & rd_mask) == rd_mask;
                                }
                                break;
                            case 5:
                                if (mix) {
                                    if (dev->bpp)
                                        src_dat = mach->accel.color_pattern_word[mach->accel.color_pattern_idx];
                                    else
                                        src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx];
                                } else
                                    src_dat = 0;
                                break;

                            default:
                                break;
                        }

                        if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && (mach->accel.patt_len_reg & 0x4000)) {
                            if (dev->accel.sy & 1) {
                                READ(dev->accel.dest + dev->accel.dx - dev->ext_pitch, dest_dat);
                            } else {
                                READ(dev->accel.dest + dev->accel.dx, dest_dat);
                            }
                        } else {
                            READ(dev->accel.dest + dev->accel.dx, dest_dat);
                        }

                        switch (compare_mode) {
                            case 1:
                                compare = 1;
                                break;
                            case 2:
                                compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                                break;
                            case 3:
                                compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                                break;
                            case 4:
                                compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                                break;
                            case 5:
                                compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                                break;
                            case 6:
                                compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                                break;
                            case 7:
                                compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                                break;

                            default:
                                break;
                        }

                        if (!compare) {
                            if (mach_pixel_write(mach)) {
                                old_dest_dat = dest_dat;
                                MIX(mix, dest_dat, src_dat);
                                dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                            }
                        }

                        if (mach->accel.dp_config & 0x10) {
                            if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && (mach->accel.patt_len_reg & 0x4000)) {
                                if (dev->accel.sy & 1) {
                                    WRITE(dev->accel.dest + dev->accel.dx - dev->ext_pitch, dest_dat);
                                } else {
                                    WRITE(dev->accel.dest + dev->accel.dx, dest_dat);
                                }
                            } else {
                                WRITE(dev->accel.dest + dev->accel.dx, dest_dat);
                            }
                        }
                    }
                }

                if (dev->bpp)
                    cpu_dat >>= 16;
                else
                    cpu_dat >>= 8;

                if ((mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02)) {
                    dev->accel.cx += mach->accel.src_stepx;
                    mach->accel.sx++;
                    if (mach->accel.sx >= mach->accel.src_width) {
                        mach->accel.sx = 0;
                        if (mach->accel.src_stepx == -1)
                            dev->accel.cx += mach->accel.src_width;
                        else
                            dev->accel.cx -= mach->accel.src_width;

                        dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1);
                        if (dev->bpp)
                            dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch));
                        else
                            dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch));
                    }
                }

                dev->accel.dx += mach->accel.stepx;

                if ((dev->accel_bpp == 8) || ((dev->accel_bpp == 24) && (mach->accel.patt_len >= 3) && (mono_src != 1)))
                    mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len;

                if ((dev->accel_bpp == 24) && (mach->accel.color_pattern_idx == mach->accel.patt_len) && (mach->accel.patt_len >= 3) && (mono_src != 1)) {
                    mach->accel.color_pattern_idx = mach->accel.patt_data_idx;
                } else if ((dev->accel_bpp == 24) && (mach->accel.patt_len < 3)) {
                    if (mach->accel.patt_len == 2) {
                        mach->accel.color_pattern_idx++;
                        if (mach->accel.color_pattern_idx == 3)
                            mach->accel.color_pattern_idx = 0;
                    } else
                        mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len;

                } else if ((dev->accel_bpp == 24) && (mach->accel.patt_len_reg & 0x4000) && (frgd_sel == 5)) {
                    mach->accel.color_pattern_idx++;
                    if (mach->accel.color_pattern_idx == 3)
                        mach->accel.color_pattern_idx = 0;
                }

                if (dev->bpp) {
                    mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len;
                    mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len;
                }

                dev->accel.sx++;
                if ((dev->accel.sx >= mach->accel.width) || (dev->accel.dx >= 0x600)) {
                    dev->accel.sx         = 0;
                    if (mach->accel.stepx == -1)
                        dev->accel.dx += mach->accel.width;
                    else
                        dev->accel.dx -= mach->accel.width;

                    dev->accel.dy += mach->accel.stepy;
                    dev->accel.sy++;

                    mach->accel.poly_fill = 0;
                    if (dev->bpp)
                        dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch));
                    else
                        dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch));

                    if ((mono_src == 1) && (dev->accel_bpp == 24) && (frgd_sel == 5))
                        mach->accel.color_pattern_idx = 0;
                    else
                        mach->accel.color_pattern_idx = ((dev->accel.dx + (dev->accel.dy << 3)) & mach->accel.patt_len);

                    if ((dev->accel_bpp == 24) && (mach->accel.color_pattern_idx == mach->accel.patt_len) && (mono_src != 1))
                        mach->accel.color_pattern_idx = 0;
                    if ((mono_src == 1) && !mach->accel.mono_pattern_enable && !(mach->accel.patt_len_reg & 0x4000)) {
                        dev->accel.cur_x = dev->accel.dx;
                        dev->accel.cur_y = dev->accel.dy;
                        return;
                    }
                    if (dev->accel.sy >= mach->accel.height) {
                        if ((mono_src == 2) || (mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02) || (mach->accel.linedraw_opt & 0x02))
                            return;
                        if ((mono_src == 1) && (frgd_sel == 5) && (dev->accel_bpp == 24) && (mach->accel.patt_len_reg & 0x4000))
                            return;
                        dev->accel.cur_x = dev->accel.dx;
                        dev->accel.cur_y = dev->accel.dy;
                        return;
                    }
                }
            }
            break;

        case 3: /*Direct Linedraw (Polyline) from linedraw indexes (0xfeee)*/
        case 4:
            if (!cpu_input) {
                dev->accel.cx = dev->accel.cur_x;
                dev->accel.cy = dev->accel.cur_y;

                if (dev->accel.cur_x >= 0x600) {
                    mach_log("Linedraw XOver = %d.\n", dev->accel.cur_x);
                    dev->accel.cx |= ~0x5ff;
                }
                if (dev->accel.cur_y >= 0x600) {
                    mach_log("Linedraw YOver = %d.\n", dev->accel.cur_y);
                    dev->accel.cy |= ~0x5ff;
                }

                dev->accel.dx = ABS(mach->accel.cx_end_line - dev->accel.cx) << 1;
                dev->accel.dy = ABS(mach->accel.cy_end_line - dev->accel.cy) << 1;

                mach->accel.stepx = (mach->accel.cx_end_line < dev->accel.cx) ? -1 : 1;
                mach->accel.stepy = (mach->accel.cy_end_line < dev->accel.cy) ? -1 : 1;

                dev->accel.sx = 0;

                mach_log("Linedraw: c(%d,%d), d(%d,%d), cend(%d,%d), bounds: l=%d, r=%d, t=%d, b=%d.\n", dev->accel.cur_x, dev->accel.cur_y, dev->accel.dx, dev->accel.dy, mach->accel.cx_end_line, mach->accel.cy_end_line, mach->accel.bleft, mach->accel.bright, mach->accel.btop, mach->accel.bbottom);

                if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) {
                    if (mach_pixel_write(mach)) {
                        dev->data_available  = 0;
                        dev->data_available2 = 0;
                        return;
                    } else if (mach_pixel_read(mach)) {
                        dev->data_available  = 1;
                        dev->data_available2 = 1;
                        return;
                    }
                }
            }

            if (frgd_sel == 5) {
                for (int x = 0; x <= mach->accel.patt_len; x++) {
                    mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len];
                }
            }

            if (mono_src == 1) {
                mix_dat             = mach->accel.patt_data[0x10];
                dev->accel.temp_cnt = 8;
            }

            count             = (dev->accel.dx > dev->accel.dy) ? (dev->accel.dx >> 1) : (dev->accel.dy >> 1);
            mach->accel.width = count;

            if (dev->accel.dx > dev->accel.dy) {
                mach->accel.err = (dev->accel.dy - dev->accel.dx) >> 1;
                if (mono_src == 1) {
                    while (count--) {
                        if (!dev->accel.temp_cnt) {
                            dev->accel.temp_cnt = 8;
                            mix_dat >>= 8;
                        }
                        mix = (mix_dat & 0x80);
                        dev->accel.temp_cnt--;
                        mix_dat <<= 1;
                        mix_dat |= 1;

                        if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) {
                            mach->accel.clip_overrun = 0;
                            switch (mix ? frgd_sel : bkgd_sel) {
                                case 0:
                                    src_dat = dev->accel.bkgd_color;
                                    break;
                                case 1:
                                    src_dat = dev->accel.frgd_color;
                                    break;
                                case 2:
                                    src_dat = cpu_dat;
                                    break;
                                case 3:
                                    if (mach_pixel_read(mach))
                                        src_dat = cpu_dat;
                                    else
                                        src_dat = 0;
                                    break;
                                case 5:
                                    if (mix)
                                        src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len];
                                    else
                                        src_dat = 0;
                                    break;

                                default:
                                    break;
                            }

                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            }

                            switch (compare_mode) {
                                case 1:
                                    compare = 1;
                                    break;
                                case 2:
                                    compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 3:
                                    compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 4:
                                    compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 5:
                                    compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 6:
                                    compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 7:
                                    compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                                    break;

                                default:
                                    break;
                            }

                            if (!compare) {
                                if (mach_pixel_write(mach)) {
                                    old_dest_dat = dest_dat;
                                    MIX(mix, dest_dat, src_dat);
                                    dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                                }
                            }
                            if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) {
                                if (dev->bpp) {
                                    WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                } else {
                                    WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                }
                            }
                        } else
                            mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f);

                        if (!count)
                            break;

                        if (dev->bpp)
                            cpu_dat >>= 16;
                        else
                            cpu_dat >>= 8;

                        if (mach->accel.err >= 0) {
                            dev->accel.cy += mach->accel.stepy;
                            mach->accel.err -= dev->accel.dx;
                        }
                        dev->accel.cx += mach->accel.stepx;
                        mach->accel.err += dev->accel.dy;
                    }
                } else {
                    while (count--) {
                        switch (mono_src) {
                            case 0:
                            case 3:
                                mix = 1;
                                break;
                            case 2:
                                if (mach->accel.dp_config & 0x1000) {
                                    mix = mix_dat >> 0x1f;
                                    mix_dat <<= 1;
                                } else {
                                    if (mach->accel.dp_config & 0x200) {
                                        mix = mix_dat & 1;
                                        mix_dat >>= 1;
                                    } else {
                                        mix = mix_dat & 0x80;
                                        mix_dat <<= 1;
                                        mix_dat |= 1;
                                    }
                                }
                                break;

                            default:
                                break;
                        }

                        if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) {
                            mach->accel.clip_overrun = 0;
                            if (mach->accel.linedraw_opt & 0x02) {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src);
                                if (poly_src)
                                    mach->accel.poly_fill = !mach->accel.poly_fill;
                            }

                            switch (mix ? frgd_sel : bkgd_sel) {
                                case 0:
                                    src_dat = dev->accel.bkgd_color;
                                    break;
                                case 1:
                                    src_dat = dev->accel.frgd_color;
                                    break;
                                case 2:
                                    src_dat = cpu_dat;
                                    break;
                                case 3:
                                    if (mach_pixel_read(mach))
                                        src_dat = cpu_dat;
                                    else {
                                        src_dat = 0;
                                    }
                                    break;
                                case 5:
                                    if (mix) {
                                        src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len];
                                    } else
                                        src_dat = 0;
                                    break;

                                default:
                                    break;
                            }

                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            }

                            switch (compare_mode) {
                                case 1:
                                    compare = 1;
                                    break;
                                case 2:
                                    compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 3:
                                    compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 4:
                                    compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 5:
                                    compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 6:
                                    compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 7:
                                    compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                                    break;

                                default:
                                    break;
                            }

                            if (!compare) {
                                if (mach_pixel_write(mach)) {
                                    old_dest_dat = dest_dat;
                                    if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) {
                                        MIX(mix, dest_dat, src_dat);
                                    }
                                    dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                                }
                            }

                            if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) {
                                if (mach->accel.linedraw_opt & 0x04) {
                                    if (dev->accel.sx < mach->accel.width) {
                                        if (dev->bpp) {
                                            WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                        } else {
                                            WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                        }
                                    }
                                } else {
                                    if (dev->bpp) {
                                        WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                    } else {
                                        WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                    }
                                }
                            }
                        } else
                            mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f);

                        if (dev->accel.sx >= mach->accel.width)
                            break;

                        if (dev->bpp)
                            cpu_dat >>= 16;
                        else
                            cpu_dat >>= 8;

                        if (mach->accel.err >= 0) {
                            dev->accel.cy += mach->accel.stepy;
                            mach->accel.err -= dev->accel.dx;
                        }
                        dev->accel.cx += mach->accel.stepx;
                        mach->accel.err += dev->accel.dy;

                        dev->accel.sx++;
                    }
                }
            } else {
                mach->accel.err = (dev->accel.dx - dev->accel.dy) >> 1;
                if (mono_src == 1) {
                    while (count--) {
                        if (dev->accel.temp_cnt == 0) {
                            dev->accel.temp_cnt = 8;
                            mix_dat >>= 8;
                        }
                        mix = (mix_dat & 0x80);
                        dev->accel.temp_cnt--;
                        mix_dat <<= 1;
                        mix_dat |= 1;

                        if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) {
                            mach->accel.clip_overrun = 0;
                            switch (mix ? frgd_sel : bkgd_sel) {
                                case 0:
                                    src_dat = dev->accel.bkgd_color;
                                    break;
                                case 1:
                                    src_dat = dev->accel.frgd_color;
                                    break;
                                case 2:
                                    src_dat = cpu_dat;
                                    break;
                                case 3:
                                    if (mach_pixel_read(mach))
                                        src_dat = cpu_dat;
                                    else {
                                        src_dat = 0;
                                    }
                                    break;
                                case 5:
                                    if (mix) {
                                        src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len];
                                    } else
                                        src_dat = 0;
                                    break;

                                default:
                                    break;
                            }

                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            }
                            switch (compare_mode) {
                                case 1:
                                    compare = 1;
                                    break;
                                case 2:
                                    compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 3:
                                    compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 4:
                                    compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 5:
                                    compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 6:
                                    compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 7:
                                    compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                                    break;

                                default:
                                    break;
                            }

                            if (!compare) {
                                if (mach_pixel_write(mach)) {
                                    old_dest_dat = dest_dat;
                                    MIX(mix, dest_dat, src_dat);
                                    dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                                }
                            }

                            if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) {
                                if (dev->bpp) {
                                    WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                } else {
                                    WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                }
                            }
                        } else
                            mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f);

                        if (!count)
                            break;

                        if (dev->bpp)
                            cpu_dat >>= 16;
                        else
                            cpu_dat >>= 8;

                        if (mach->accel.err >= 0) {
                            dev->accel.cx += mach->accel.stepx;
                            mach->accel.err -= dev->accel.dy;
                        }
                        dev->accel.cy += mach->accel.stepy;
                        mach->accel.err += dev->accel.dx;
                    }
                } else {
                    while (count--) {
                        switch (mono_src) {
                            case 0:
                            case 3:
                                mix = 1;
                                break;
                            case 2:
                                if (mach->accel.dp_config & 0x1000) {
                                    mix = mix_dat >> 0x1f;
                                    mix_dat <<= 1;
                                } else {
                                    if (mach->accel.dp_config & 0x200) {
                                        mix = mix_dat & 1;
                                        mix_dat >>= 1;
                                    } else {
                                        mix = mix_dat & 0x80;
                                        mix_dat <<= 1;
                                        mix_dat |= 1;
                                    }
                                }
                                break;

                            default:
                                break;
                        }

                        if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) {
                            mach->accel.clip_overrun = 0;

                            switch (mix ? frgd_sel : bkgd_sel) {
                                case 0:
                                    src_dat = dev->accel.bkgd_color;
                                    break;
                                case 1:
                                    src_dat = dev->accel.frgd_color;
                                    break;
                                case 2:
                                    src_dat = cpu_dat;
                                    break;
                                case 3:
                                    if (mach_pixel_read(mach))
                                        src_dat = cpu_dat;
                                    else {
                                        src_dat = 0;
                                    }
                                    break;
                                case 5:
                                    if (mix) {
                                        src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len];
                                    } else
                                        src_dat = 0;
                                    break;

                                default:
                                    break;
                            }

                            if (dev->bpp) {
                                READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            } else {
                                READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                            }

                            switch (compare_mode) {
                                case 1:
                                    compare = 1;
                                    break;
                                case 2:
                                    compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 3:
                                    compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 4:
                                    compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 5:
                                    compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 6:
                                    compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                                    break;
                                case 7:
                                    compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                                    break;

                                default:
                                    break;
                            }

                            if (!compare) {
                                if (mach_pixel_write(mach)) {
                                    old_dest_dat = dest_dat;
                                    MIX(mix, dest_dat, src_dat);
                                    dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                                }
                            }

                            if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) {
                                if (mach->accel.linedraw_opt & 0x04) {
                                    if (dev->accel.sx < mach->accel.width) {
                                        if (dev->bpp) {
                                            WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                        } else {
                                            WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                        }
                                    }
                                } else {
                                    if (dev->bpp) {
                                        WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                    } else {
                                        WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat);
                                    }
                                }
                            }
                        } else
                            mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f);

                        if (dev->accel.sx >= mach->accel.width)
                            break;

                        if (dev->bpp)
                            cpu_dat >>= 16;
                        else
                            cpu_dat >>= 8;

                        if (mach->accel.err >= 0) {
                            dev->accel.cx += mach->accel.stepx;
                            mach->accel.err -= dev->accel.dy;
                        }
                        dev->accel.cy += mach->accel.stepy;
                        mach->accel.err += dev->accel.dx;

                        dev->accel.sx++;
                    }
                }
            }
            mach->accel.poly_fill = 0;
            mach->accel.line_array[(cmd_type == 4) ? 4 : 0] = dev->accel.cx;
            mach->accel.line_array[(cmd_type == 4) ? 5 : 1] = dev->accel.cy;
            dev->accel.cur_x                                = mach->accel.line_array[(cmd_type == 4) ? 4 : 0];
            dev->accel.cur_y                                = mach->accel.line_array[(cmd_type == 4) ? 5 : 1];
            break;

        case 5: /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/
            if (!cpu_input) {
                mach->accel.stepx = 0;
                mach->accel.stepy = 0;

                dev->accel.dx = dev->accel.cur_x;
                if (dev->accel.cur_x >= 0x600)
                    dev->accel.dx |= ~0x5ff;
                dev->accel.dy = dev->accel.cur_y;
                if (dev->accel.cur_y >= 0x600)
                    dev->accel.dy |= ~0x5ff;

                /*Destination Width*/
                mach->accel.dx_start = dev->accel.cur_x;
                if (dev->accel.cur_x >= 0x600)
                    mach->accel.dx_start |= ~0x5ff;
                mach->accel.dx_end = mach->accel.scan_to_x;
                if (mach->accel.scan_to_x >= 0x600)
                    mach->accel.dx_end |= ~0x5ff;

                if (mach->accel.dx_end > mach->accel.dx_start) {
                    mach->accel.width = (mach->accel.dx_end - mach->accel.dx_start);
                    mach->accel.stepx = 1;
                } else if (mach->accel.dx_end < mach->accel.dx_start) {
                    mach->accel.width = (mach->accel.dx_start - mach->accel.dx_end);
                    mach->accel.stepx = -1;
                    if (dev->accel.dx > 0)
                        dev->accel.dx--;
                } else {
                    mach->accel.stepx = 1;
                    mach->accel.width = 0;
                }

                dev->accel.sx = 0;
                if ((dev->accel_bpp == 24) && (mach->accel.patt_len < 0x17))
                    mach->accel.color_pattern_idx = 0;

                /*Step Y*/
                mach->accel.dy_start = dev->accel.cur_y;
                if (dev->accel.cur_y >= 0x600)
                    mach->accel.dy_start |= ~0x5ff;
                mach->accel.dy_end = mach->accel.dest_y_end;
                if (mach->accel.dest_y_end >= 0x600)
                    mach->accel.dy_end |= ~0x5ff;

                if (mach->accel.dy_end > mach->accel.dy_start) {
                    mach->accel.stepy = 1;
                } else if (mach->accel.dy_end < mach->accel.dy_start) {
                    mach->accel.stepy = -1;
                } else {
                    mach->accel.stepy = 0;
                }

                if (dev->bpp)
                    dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch));
                else
                    dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch));

                mach->accel.src_stepx = 0;

                /*Source Width*/
                dev->accel.cx = mach->accel.src_x;
                if (mach->accel.src_x >= 0x600)
                    dev->accel.cx |= ~0x5ff;
                dev->accel.cy = mach->accel.src_y;
                if (mach->accel.src_y >= 0x600)
                    dev->accel.cy |= ~0x5ff;

                mach->accel.sx_start = mach->accel.src_x_start;
                if (mach->accel.src_x_start >= 0x600)
                    mach->accel.sx_start |= ~0x5ff;

                mach->accel.sx_end = mach->accel.src_x_end;
                if (mach->accel.src_x_end >= 0x600)
                    mach->accel.sx_end |= ~0x5ff;

                if (mach->accel.sx_end > mach->accel.sx_start) {
                    mach->accel.src_width = (mach->accel.sx_end - mach->accel.sx_start);
                    mach->accel.src_stepx = 1;
                } else if (mach->accel.sx_end < mach->accel.sx_start) {
                    mach->accel.src_width = (mach->accel.sx_start - mach->accel.sx_end);
                    mach->accel.src_stepx = -1;
                    if (dev->accel.cx > 0)
                        dev->accel.cx--;
                } else {
                    mach->accel.src_stepx = 1;
                    mach->accel.src_width = 0;
                }

                mach->accel.sx = 0;
                if (dev->bpp)
                    dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch));
                else
                    dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch));

                if ((dev->accel_bpp == 24) && (frgd_sel == 5)) {
                    if (mach->accel.patt_len == 0x17)
                        mach->accel.color_pattern_idx = 0;
                    dev->accel.x1 = dev->accel.dx + mach->accel.width;
                    if (dev->accel.x1 == dev->pitch) {
                        dev->accel.x2 = mach->accel.width & 1;
                    } else if ((dev->accel.x1 == mach->accel.width) && (dev->accel.dy & 1) && !dev->accel.y1 && dev->accel.x2) {
                        if (mach->accel.patt_len == 0x17)
                            mach->accel.color_pattern_idx = 3;
                        dev->accel.x3 = 1;
                    } else
                        dev->accel.x3 = 0;
                } else
                    mach_log("ScanToX=%04x, Pitch=%d, C(%d,%d), SRCWidth=%d, WH(%d,%d), geoffset=%08x.\n", mach->accel.dp_config, dev->ext_pitch, dev->accel.cx, dev->accel.cy, mach->accel.src_width, mach->accel.width, mach->accel.height, (mach->accel.ge_offset << 1));

                dev->accel.y1 = 0;

                if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) {
                    if (mach_pixel_write(mach)) {
                        dev->data_available  = 0;
                        dev->data_available2 = 0;
                        return;
                    } else if (mach_pixel_read(mach)) {
                        dev->data_available  = 1;
                        dev->data_available2 = 1;
                        return;
                    }
                }
            }

            if (mono_src == 1) {
                count               = mach->accel.width;
                mix_dat             = mach->accel.patt_data[0x10];
                dev->accel.temp_cnt = 8;
            }

            if (frgd_sel == 5) {
                if (dev->accel_bpp != 24) {
                    for (int x = 0; x <= mach->accel.patt_len; x++) {
                        mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len];
                    }
                } else {
                    if (mach->accel.patt_len == 0x17) {
                        for (int x = 0; x <= mach->accel.patt_len; x++) {
                            mach->accel.color_pattern_full[x] = mach->accel.patt_data[x];
                            mach_log("ScanToX: Color Pattern 24bpp[%d]=%02x, dataidx=%d, pattlen=%d.\n", x, mach->accel.color_pattern_full[x], mach->accel.patt_data_idx, mach->accel.patt_len);
                        }
                    } else {
                        for (int x = 0; x <= mach->accel.patt_len; x++) {
                            mach->accel.color_pattern[x] = mach->accel.patt_data[x];
                            mach_log("ScanToX: Color Pattern 24bpp[%d]=%02x, dataidx=%d, pattlen=%d.\n", x, mach->accel.color_pattern[x], mach->accel.patt_data_idx, mach->accel.patt_len);
                        }
                    }
                }
            }

            while (count--) {
                switch (mono_src) {
                    case 0:
                        mix = 1;
                        break;
                    case 1:
                        if (!dev->accel.temp_cnt) {
                            dev->accel.temp_cnt = 8;
                            mix_dat >>= 8;
                        }
                        mix = (mix_dat & 0x80);
                        dev->accel.temp_cnt--;
                        mix_dat <<= 1;
                        mix_dat |= 1;
                        break;
                    case 2:
                        if (mach->accel.dp_config & 0x1000) {
                            mix = mix_dat >> 0x1f;
                            mix_dat <<= 1;
                        } else {
                            if (mach->accel.dp_config & 0x200) {
                                mix = mix_dat & 1;
                                mix_dat >>= 1;
                            } else {
                                mix = mix_dat & 0x80;
                                mix_dat <<= 1;
                                mix_dat |= 1;
                            }
                        }
                        break;
                    case 3:
                        READ(dev->accel.src + (dev->accel.cx), mix);
                        mix = (mix & rd_mask) == rd_mask;
                        break;

                    default:
                        break;
                }

                if (((dev->accel.dx) >= clip_l) && ((dev->accel.dx) <= clip_r) && ((dev->accel.dy) >= clip_t) && ((dev->accel.dy) <= clip_b)) {
                    switch (mix ? frgd_sel : bkgd_sel) {
                        case 0:
                            src_dat = dev->accel.bkgd_color;
                            break;
                        case 1:
                            src_dat = dev->accel.frgd_color;
                            break;
                        case 2:
                            src_dat = cpu_dat;
                            break;
                        case 3:
                            if (mach_pixel_read(mach))
                                src_dat = cpu_dat;
                            else {
                                READ(dev->accel.src + dev->accel.cx, src_dat);
                                if (mono_src == 3)
                                    src_dat = (src_dat & rd_mask) == rd_mask;
                            }
                            break;
                        case 5:
                            if (mix) {
                                if (dev->accel_bpp == 24) {
                                    if (mach->accel.patt_len == 0x17)
                                        src_dat = mach->accel.color_pattern_full[mach->accel.color_pattern_idx];
                                    else
                                        src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx];
                                } else
                                    src_dat = mach->accel.color_pattern[(dev->accel.dx + (dev->accel.dy << 3)) & mach->accel.patt_len];
                            } else
                                src_dat = 0;
                            break;

                        default:
                            break;
                    }

                    READ(dev->accel.dest + dev->accel.dx, dest_dat);

                    switch (compare_mode) {
                        case 1:
                            compare = 1;
                            break;
                        case 2:
                            compare = (dest_dat >= dest_cmp_clr) ? 0 : 1;
                            break;
                        case 3:
                            compare = (dest_dat < dest_cmp_clr) ? 0 : 1;
                            break;
                        case 4:
                            compare = (dest_dat != dest_cmp_clr) ? 0 : 1;
                            break;
                        case 5:
                            compare = (dest_dat == dest_cmp_clr) ? 0 : 1;
                            break;
                        case 6:
                            compare = (dest_dat <= dest_cmp_clr) ? 0 : 1;
                            break;
                        case 7:
                            compare = (dest_dat > dest_cmp_clr) ? 0 : 1;
                            break;

                        default:
                            break;
                    }

                    if (!compare) {
                        if (mach_pixel_write(mach)) {
                            old_dest_dat = dest_dat;
                            MIX(mix, dest_dat, src_dat);
                            dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask);
                        }
                    }

                    if (mach->accel.dp_config & 0x10) {
                        WRITE(dev->accel.dest + (dev->accel.dx), dest_dat);
                    }
                }

                if (dev->bpp)
                    cpu_dat >>= 16;
                else
                    cpu_dat >>= 8;

                dev->accel.cx += mach->accel.src_stepx;
                mach->accel.sx++;
                if (mach->accel.sx >= mach->accel.src_width) {
                    mach->accel.sx = 0;
                    if (mach->accel.src_stepx == -1) {
                        dev->accel.cx += mach->accel.src_width;
                    } else
                        dev->accel.cx -= mach->accel.src_width;
                    dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1);
                    if (dev->bpp)
                        dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch));
                    else
                        dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch));
                }

                dev->accel.dx += mach->accel.stepx;
                if ((dev->accel_bpp == 24) && (mach->accel.patt_len == 0x17)) {
                    mach->accel.color_pattern_idx++;
                    if (dev->accel.x3) {
                        if (mach->accel.color_pattern_idx == 9)
                            mach->accel.color_pattern_idx = 3;
                    } else {
                        if (mach->accel.color_pattern_idx == 6)
                            mach->accel.color_pattern_idx = 0;
                    }
                } else if ((dev->accel_bpp == 24) && (mach->accel.patt_len < 3)) {
                    mach->accel.color_pattern_idx++;
                    if (mach->accel.color_pattern_idx == 3)
                        mach->accel.color_pattern_idx = 0;
                } else
                    mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len;

                dev->accel.sx++;
                if (dev->accel.sx >= mach->accel.width) {
                    dev->accel.sx = 0;
                    dev->accel.dy += mach->accel.stepy;
                    if (dev->bpp)
                        dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch));
                    else
                        dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch));
                    if (mach->accel.line_idx == 2) {
                        mach->accel.line_array[0] = dev->accel.dx;
                        mach->accel.line_array[4] = dev->accel.dx;
                    }
                    return;
                }
            }
            break;

        default:
            break;
    }
}

static void
mach_accel_out_pixtrans(mach_t *mach, ibm8514_t *dev, uint16_t val)
{
    int frgd_sel;
    int bkgd_sel;
    int mono_src;

    frgd_sel = (mach->accel.dp_config >> 13) & 7;
    bkgd_sel = (mach->accel.dp_config >> 7) & 3;
    mono_src = (mach->accel.dp_config >> 5) & 3;

    if ((mach->accel.dp_config & 4) && (mach->accel.cmd_type != 5)) {
        val = (val >> 8) | (val << 8);
    }

    switch (mach->accel.dp_config & 0x200) {
        case 0x000: /*8-bit size*/
            if (mono_src == 2) {
                if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                    if (mach->accel.dp_config & 0x1000)
                        val = (val >> 8) | (val << 8);
                    mach_accel_start(mach->accel.cmd_type, 1, 8, val | (val << 16), 0, mach, dev);
                } else
                    mach_accel_start(mach->accel.cmd_type, 1, 1, -1, val | (val << 16), mach, dev);
            } else
                mach_accel_start(mach->accel.cmd_type, 1, 1, -1, val | (val << 16), mach, dev);
            break;
        case 0x200: /*16-bit size*/
            if (mono_src == 2) {
                if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                    if (mach->accel.dp_config & 0x1000)
                        val = (val >> 8) | (val << 8);
                    mach_accel_start(mach->accel.cmd_type, 1, 16, val | (val << 16), 0, mach, dev);
                } else
                    mach_accel_start(mach->accel.cmd_type, 1, 2, -1, val | (val << 16), mach, dev);
            } else
                mach_accel_start(mach->accel.cmd_type, 1, 2, -1, val | (val << 16), mach, dev);
            break;

        default:
            break;
    }
}

static void
mach_out(uint16_t addr, uint8_t val, void *priv)
{
    mach_t          *mach = (mach_t *) priv;
    svga_t          *svga = &mach->svga;
    const ibm8514_t *dev  = (ibm8514_t *) svga->dev8514;
    uint8_t          old;
    uint8_t          rs2;
    uint8_t          rs3;

    if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1))
        addr ^= 0x60;

    switch (addr) {
        case 0x1ce:
            mach->index = val;
            break;
        case 0x1cf:
            old                     = mach->regs[mach->index];
            mach->regs[mach->index] = val;
            mach_log("ATI VGA write reg=0x%02X, val=0x%02X\n", mach->index, val);
            switch (mach->index) {
                case 0xa3:
                    if ((old ^ val) & 0x10)
                        svga_recalctimings(svga);
                    break;
                case 0xa7:
                    if ((old ^ val) & 0x80)
                        svga_recalctimings(svga);
                    break;
                case 0xad:
                    if ((dev->local & 0xff) >= 0x02) {
                        if ((old ^ val) & 0x0c)
                            svga_recalctimings(svga);
                    }
                    break;
                case 0xb0:
                    if ((old ^ val) & 0x60)
                        svga_recalctimings(svga);
                    break;
                case 0xae:
                case 0xb2:
                case 0xbe:
                    mach_log("ATI VGA write reg=0x%02X, val=0x%02X\n", mach->index, val);
                    if (mach->regs[0xbe] & 0x08) { /* Read/write bank mode */
                        mach->bank_r = (((mach->regs[0xb2] & 1) << 3) | ((mach->regs[0xb2] & 0xe0) >> 5));
                        mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1);
                        if ((dev->local & 0xff) >= 0x02) {
                            mach->bank_r |= ((mach->regs[0xae] & 0x0c) << 2);
                            mach->bank_w |= ((mach->regs[0xae] & 3) << 4);
                        }
                        if (dev->on[0] || dev->on[1])
                            mach_log("Separate B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]);
                    } else { /* Single bank mode */
                        mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1);
                        if ((dev->local & 0xff) >= 0x02) {
                            mach->bank_w |= ((mach->regs[0xae] & 3) << 4);
                        }
                        mach->bank_r = mach->bank_w;
                        if (dev->on[0] || dev->on[1])
                            mach_log("Single B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]);
                    }
                    svga->read_bank  = mach->bank_r << 16;
                    svga->write_bank = mach->bank_w << 16;

                    if (mach->index == 0xbe) {
                        if ((old ^ val) & 0x10)
                            svga_recalctimings(svga);
                    }
                    break;
                case 0xbd:
                    if ((old ^ val) & 4) {
                        mach32_updatemapping(mach, svga);
                    }
                    break;
                case 0xb3:
                    ati_eeprom_write(&mach->eeprom, val & 8, val & 2, val & 1);
                    break;
                case 0xb6:
                    if ((old ^ val) & 0x10)
                        svga_recalctimings(svga);
                    break;
                case 0xb8:
                    if ((dev->local & 0xff) >= 0x02) {
                        if ((old ^ val) & 0x40)
                            svga_recalctimings(svga);
                    } else {
                        if ((old ^ val) & 0xc0)
                            svga_recalctimings(svga);
                    }
                    break;
                case 0xb9:
                    if ((old ^ val) & 2)
                        svga_recalctimings(svga);
                    break;

                default:
                    break;
            }
            break;

        case 0x2ea:
        case 0x2eb:
        case 0x2ec:
        case 0x2ed:
            rs2 = !!(mach->accel.ext_ge_config & 0x1000);
            rs3 = !!(mach->accel.ext_ge_config & 0x2000);
            if ((dev->local & 0xff) >= 0x02) {
                if (mach->pci_bus && !mach->ramdac_type)
                    ati68860_ramdac_out((addr & 3) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga);
                else
                    ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga);
            } else
                svga_out(addr, val, svga);
            return;

        case 0x3C6:
        case 0x3C7:
        case 0x3C8:
        case 0x3C9:
            rs2 = !!(mach->regs[0xa0] & 0x20);
            rs3 = !!(mach->regs[0xa0] & 0x40);
            if ((dev->local & 0xff) >= 0x02) {
                if (mach->pci_bus && !mach->ramdac_type)
                    ati68860_ramdac_out((addr & 3) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga);
                else
                    ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga);
            } else
                svga_out(addr, val, svga);
            return;

        case 0x3D4:
            svga->crtcreg = val & 0x3f;
            return;
        case 0x3D5:
            if (svga->crtcreg & 0x20)
                return;
            if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80) && !(mach->regs[0xb4] & 0x80))
                return;
            if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80) && !(mach->regs[0xb4] & 0x80))
                val = (svga->crtc[7] & ~0x10) | (val & 0x10);

            old                       = svga->crtc[svga->crtcreg];
            svga->crtc[svga->crtcreg] = val;
            if (old != val) {
                if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) {
                    if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) {
                        svga->fullchange = 3;
                        svga->ma_latch   = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5);
                    } else {
                        svga->fullchange = changeframecount;
                        svga_recalctimings(svga);
                    }
                }
            }
            break;

        default:
            break;
    }
    svga_out(addr, val, svga);
}

static uint8_t
mach_in(uint16_t addr, void *priv)
{
    mach_t          *mach = (mach_t *) priv;
    svga_t          *svga = &mach->svga;
    const ibm8514_t *dev  = (ibm8514_t *) svga->dev8514;
    uint8_t          temp = 0xff;
    uint8_t          rs2;
    uint8_t          rs3;

    if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1))
        addr ^= 0x60;

    if ((addr >= 0x3c6) && (addr <= 0x3c9) && (dev->on[0] || dev->on[1]))
        addr -= 0xdc;

    switch (addr) {
        case 0x1ce:
            temp = mach->index;
            break;
        case 0x1cf:
            switch (mach->index) {
                case 0xa0:
                    temp = mach->regs[0xa0] | 0x10;
                    break;
                case 0xa8:
                    temp = (svga->vc >> 8) & 3;
                    break;
                case 0xa9:
                    temp = svga->vc & 0xff;
                    break;
                case 0xb0:
                    temp = mach->regs[0xb0] | 0x80;
                    temp &= ~0x18;
                    if ((dev->local & 0xff) >= 0x02) { /*Mach32 VGA 1MB memory*/
                        temp |= 0x08;
                    } else { /*ATI 28800 VGA 512kB memory*/
                        temp |= 0x10;
                    }
                    break;
                case 0xb7:
                    temp = mach->regs[0xb7] & ~0x08;
                    if (ati_eeprom_read(&mach->eeprom))
                        temp |= 0x08;
                    break;

                case 0xbd:
                    temp = mach->regs[0xbd] | 0x10;
                    break;

                default:
                    temp = mach->regs[mach->index];
                    break;
            }
            break;

        case 0x2ea:
        case 0x2eb:
        case 0x2ec:
        case 0x2ed:
            rs2 = !!(mach->accel.ext_ge_config & 0x1000);
            rs3 = !!(mach->accel.ext_ge_config & 0x2000);
            if ((dev->local & 0xff) >= 0x02) {
                if (mach->pci_bus && !mach->ramdac_type)
                    temp = ati68860_ramdac_in((addr & 3) | (rs2 << 2) | (rs3 << 3), svga->ramdac, svga);
                else
                    temp = ati68875_ramdac_in(addr, rs2, rs3, svga->ramdac, svga);
            } else
                temp = svga_in(addr, svga);
            break;

        case 0x3D4:
            temp = svga->crtcreg;
            break;
        case 0x3D5:
            if (svga->crtcreg & 0x20)
                temp = 0xff;
            else
                temp = svga->crtc[svga->crtcreg];
            break;

        default:
            temp = svga_in(addr, svga);
            break;
    }
    return temp;
}


#ifdef ATI_8514_ULTRA
static void
ati8514_out(uint16_t addr, uint8_t val, void *priv)
{
    mach_log("[%04X:%08X]: ADDON OUT addr=%03x, val=%02x.\n", CS, cpu_state.pc, addr, val);
    svga_out(addr, val, priv);
}

static uint8_t
ati8514_in(uint16_t addr, void *priv)
{
    uint8_t temp = 0xff;

    temp = svga_in(addr, priv);

    mach_log("[%04X:%08X]: ADDON IN addr=%03x, temp=%02x.\n", CS, cpu_state.pc, addr, temp);
    return temp;
}

void
ati8514_recalctimings(svga_t *svga)
{
    mach_t       *mach = (mach_t *) svga->ext8514;
    ibm8514_t    *dev  = (ibm8514_t *) svga->dev8514;

    mach_log("ON0=%d, ON1=%d, vgahdisp=%d.\n", dev->on[0], dev->on[1], svga->hdisp);
    if (dev->on[0] || dev->on[1]) {
        mach_log("8514/A ON.\n");
        dev->h_total                    = dev->htotal + 1;
        dev->rowcount                   = !!(dev->disp_cntl & 0x08);
        dev->accel.ge_offset            = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16));
        mach->accel.ge_offset           = dev->accel.ge_offset;

        mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0xfe);
        if (dev->accel.advfunc_cntl & 0x01) {
            if (dev->accel.advfunc_cntl & 0x04) {
                dev->h_disp = dev->hdisp;
                dev->dispend = dev->vdisp;
            } else {
                dev->h_disp = 640;
                dev->dispend = 480;
            }
        } else {
            dev->h_disp = dev->hdisp;
            dev->dispend = dev->vdisp;
        }

        if (dev->accel.advfunc_cntl & 0x04) {
            svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0;
        } else {
            svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 25175000.0;
        }

        if (dev->dispend == 766)
            dev->dispend += 2;

        if (dev->dispend == 598)
            dev->dispend += 2;

        if (dev->dispend == 478)
            dev->dispend += 2;

        dev->pitch = dev->ext_pitch;
        dev->rowoffset = dev->ext_crt_pitch;
        mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace);
        svga->map8 = dev->pallook;
        svga->render8514 = ibm8514_render_8bpp;
    } else {
        if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/
            if (svga->seqregs[1] & 8) {                              /*40 column*/
                svga->render = svga_render_text_40;
            } else {
                svga->render = svga_render_text_80;
            }
        }
    }
}
#endif

static void
mach_recalctimings(svga_t *svga)
{
    mach_t       *mach = (mach_t *) svga->priv;
    ibm8514_t    *dev  = (ibm8514_t *) svga->dev8514;
    int           clock_sel;

    if (mach->regs[0xad] & 0x08)
        svga->hblankstart    = ((mach->regs[0x0d] >> 2) << 8) + svga->crtc[2];

    clock_sel = ((svga->miscout >> 2) & 3) | ((mach->regs[0xbe] & 0x10) >> 1) | ((mach->regs[0xb9] & 2) << 1);

    if ((dev->local & 0xff) >= 0x02) {
        if (mach->regs[0xad] & 0x04)
            svga->ma_latch |= 0x40000;

        if (mach->regs[0xad] & 0x08)
            svga->ma_latch |= 0x80000;
    }

    if (mach->regs[0xa3] & 0x10)
        svga->ma_latch |= 0x10000;

    if (mach->regs[0xb0] & 0x40)
        svga->ma_latch |= 0x20000;

    if ((mach->regs[0xb6] & 0x18) >= 0x10) {
        svga->hdisp <<= 1;
        svga->htotal <<= 1;
        svga->dots_per_clock <<= 1;
        svga->rowoffset <<= 1;
        svga->gdcreg[5] &= ~0x40;
    }

    if (mach->regs[0xb0] & 0x20) {
        svga->gdcreg[5] |= 0x40;
        if ((mach->regs[0xb6] & 0x18) >= 0x10)
            svga->packed_4bpp = 1;
        else
            svga->packed_4bpp = 0;
    } else
        svga->packed_4bpp = 0;

    if ((dev->local & 0xff) < 0x02) {
        if ((mach->regs[0xb6] & 0x18) == 8) {
            svga->hdisp <<= 1;
            svga->htotal <<= 1;
            svga->dots_per_clock <<= 1;
            svga->ati_4color = 1;
        } else
            svga->ati_4color = 0;
    }

    svga->render8514 = ibm8514_render_blank;
    mach_log("ON[0]=%d, ON[1]=%d, exton[0]=%d, exton[1]=%d, vendormode0=%d, vendormode1=%d.\n", dev->on[0], dev->on[1], mach->ext_on[0], mach->ext_on[1], dev->vendor_mode[0], dev->vendor_mode[1]);
    if (dev->on[0] || dev->on[1]) {
        mach_log("8514/A ON.\n");
        dev->h_total                    = dev->htotal + 1;
        dev->rowcount                   = !!(dev->disp_cntl & 0x08);
        dev->accel.ge_offset            = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16));
        mach->accel.ge_offset           = dev->accel.ge_offset;

        mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0xfe);
        if (!dev->bpp) {
            if (dev->accel.advfunc_cntl & 0x01) {
                if (dev->accel.advfunc_cntl & 0x04) {
                    dev->h_disp = dev->hdisp;
                    dev->dispend = dev->vdisp;
                } else {
                    dev->h_disp = 640;
                    dev->dispend = 480;
                }
            } else {
                dev->h_disp = dev->hdisp;
                dev->dispend = dev->vdisp;
            }
        } else {
            dev->h_disp = dev->hdisp;
            dev->dispend = dev->vdisp;
        }

        svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen);

        if (dev->interlace)
            dev->dispend >>= 1;

        if (dev->dispend == 478)
            dev->dispend += 2;

        if (dev->dispend == 598)
            dev->dispend += 2;

        if (dev->dispend == 766)
            dev->dispend += 2;

        if (dev->dispend == 1022)
            dev->dispend += 2;

        if ((dev->local & 0xff) >= 0x02) {
            mach_log("HDISP=%d.\n", dev->h_disp);
            dev->pitch = dev->ext_pitch;
            dev->rowoffset = dev->ext_crt_pitch;
            if ((mach->accel.ext_ge_config & 0x800) || (!(mach->accel.ext_ge_config & 0x8000) && !(mach->accel.ext_ge_config & 0x800))) {
                if ((mach->accel.ext_ge_config & 0x30) == 0x20) {
                    if ((mach->accel.ext_ge_config & 0xc0) == 0x40)
                        dev->accel_bpp = 16;
                    else
                        dev->accel_bpp = 15;
                } else if ((mach->accel.ext_ge_config & 0x30) == 0x30) {
                    if (mach->accel.ext_ge_config & 0x200)
                        dev->accel_bpp = 32;
                    else
                        dev->accel_bpp = 24;
                } else
                    dev->accel_bpp = 8;

                mach_log("hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, bpp=%d, shadow=%x, vgahdisp=%d.\n", dev->h_disp, dev->dispend, dev->pitch, dev->ext_crt_pitch, mach->accel.ext_ge_config & 0xcec0, dev->accel_bpp, mach->shadow_set & 3, svga->hdisp);
                switch (dev->accel_bpp) {
                    case 8:
                        svga->render8514 = ibm8514_render_8bpp;
                        break;
                    case 15:
                        svga->render8514 = ibm8514_render_15bpp;
                        break;
                    case 16:
                        svga->render8514 = ibm8514_render_16bpp;
                        break;
                    case 24:
                        mach_log("GEConfig24bpp: %03x.\n", mach->accel.ext_ge_config & 0x600);
                        if (mach->accel.ext_ge_config & 0x400)
                            svga->render8514 = ibm8514_render_BGR;
                        else
                            svga->render8514 = ibm8514_render_24bpp;
                        break;
                    case 32:
                        mach_log("GEConfig32bpp: %03x.\n", mach->accel.ext_ge_config & 0x600);
                        if (mach->accel.ext_ge_config & 0x400)
                            svga->render8514 = ibm8514_render_ABGR8888;
                        else
                            svga->render8514 = ibm8514_render_32bpp;
                        break;

                    default:
                        break;
                }
            }
        } else {
            dev->pitch = dev->ext_pitch;
            dev->rowoffset = dev->ext_crt_pitch;
            mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace);
            svga->map8 = dev->pallook;
            svga->render8514 = ibm8514_render_8bpp;
        }
    }

    if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) {
        if (((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1))) {
            svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen);
            mach_log("VGA clock=%02x.\n", mach->regs[0xa7] & 0x80);
            if ((dev->local & 0xff) >= 0x02) {
                if (mach->regs[0xb8] & 0x40)
                    svga->clock *= 2;
            } else {
                switch (mach->regs[0xb8] & 0xc0) {
                    case 0x40:
                        svga->clock *= 2;
                        break;
                    case 0x80:
                        svga->clock *= 3;
                        break;
                    case 0xc0:
                        svga->clock *= 4;
                        break;

                    default:
                        break;
                }
            }
            switch (svga->gdcreg[5] & 0x60) {
                case 0x00:
                    if (svga->seqregs[1] & 8) /*Low res (320)*/
                        svga->render = svga_render_4bpp_lowres;
                    else
                        svga->render = svga_render_4bpp_highres;
                    break;
                case 0x20:                    /*4 colours*/
                    if (svga->seqregs[1] & 8) /*Low res (320)*/
                        svga->render = svga_render_2bpp_lowres;
                    else
                        svga->render = svga_render_2bpp_highres;
                    break;
                case 0x40:
                case 0x60: /*256+ colours*/
                    switch (svga->bpp) {
                        default:
                        case 8:
                            svga->map8 = svga->pallook;
                            mach_log("Lowres=%x, seqreg[1]bit3=%x.\n", svga->lowres, svga->seqregs[1] & 8);
                            if (svga->lowres)
                                svga->render = svga_render_8bpp_lowres;
                            else {
                                svga->render = svga_render_8bpp_highres;
                                if (!svga->packed_4bpp) {
                                    svga->ma_latch <<= 1;
                                    svga->rowoffset <<= 1;
                                }
                            }
                            break;
                    }
                    break;

                default:
                    break;
            }
        }
    }
}

static void
mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, uint16_t val, int len)
{
    int frgd_sel;
    int bkgd_sel;
    int mono_src;

    mach_log("[%04X:%08X]: Port FIFO OUT=%04x, val=%04x, len=%d.\n", CS, cpu_state.pc, port, val, len);

    switch (port) {
        case 0x82e8:
        case 0x82e9:
        case 0x86e8:
        case 0x86e9:
        case 0xc2e8:
        case 0xc2e9:
        case 0xc6e8:
        case 0xc6e9:
            ibm8514_accel_out_fifo(svga, port, val, len);
            break;
        case 0xf6ee:
            ibm8514_accel_out_fifo(svga, 0x82e8, val, len);
            break;
        case 0xf6ef:
            ibm8514_accel_out_fifo(svga, 0x82e9, val, len);
            break;

        case 0x8ae8:
        case 0xcae8:
            ibm8514_accel_out_fifo(svga, port, val, len);
            if (len != 1)
                mach->accel.src_y = val;
            break;
        case 0x8ae9:
        case 0x8ee9:
        case 0xcae9:
        case 0xcee9:
            ibm8514_accel_out_fifo(svga, port, val, len);
            break;

        case 0x8ee8:
        case 0xcee8:
            ibm8514_accel_out_fifo(svga, port, val, len);
            if (len != 1)
                mach->accel.src_x = val;
            break;

        case 0x92e8:
        case 0x92e9:
        case 0x96e9:
        case 0xd2e8:
        case 0xd2e9:
        case 0xd6e9:
            ibm8514_accel_out_fifo(svga, port, val, len);
            break;

        case 0x96e8:
        case 0xd6e8:
            ibm8514_accel_out_fifo(svga, port, val, len);
            if (len != 1)
                mach->accel.test = val & 0x1fff;
            break;

        case 0x9ae8:
        case 0xdae8:
            dev->accel.ssv_state = 0;
            if (len == 1)
                dev->accel.cmd = (dev->accel.cmd & 0xff00) | val;
            else {
                dev->data_available  = 0;
                dev->data_available2 = 0;
                dev->accel.cmd       = val;
                mach_log("CMD8514=%04x, len=%d, pixcntl=%02x.\n", val, len, dev->accel.multifunc[0x0a]);
                mach->accel.cmd_type = -1;
                if (port == 0xdae8) {
                    if (dev->accel.cmd & 0x100)
                        dev->accel.cmd_back = 0;
                }
                ibm8514_accel_start(-1, 0, -1, 0, svga, len);
            }
            break;
        case 0x9ae9:
        case 0xdae9:
            if (len == 1) {
                dev->data_available  = 0;
                dev->data_available2 = 0;
                dev->accel.cmd       = (dev->accel.cmd & 0xff) | (val << 8);
                mach->accel.cmd_type = -1;
                if (port == 0xdae9) {
                    if (dev->accel.cmd & 0x100)
                        dev->accel.cmd_back = 0;
                }
                ibm8514_accel_start(-1, 0, -1, 0, svga, len);
            }
            break;

        case 0x9ee8:
        case 0xdee8:
            dev->accel.ssv_state = 1;
            if (len == 1)
                dev->accel.short_stroke = (dev->accel.short_stroke & 0xff00) | val;
            else {
                dev->accel.short_stroke = val;
                dev->accel.cx           = dev->accel.cur_x;
                dev->accel.cy           = dev->accel.cur_y;

                if (dev->accel.cur_x >= 0x600)
                    dev->accel.cx |= ~0x5ff;

                if (dev->accel.cur_y >= 0x600)
                    dev->accel.cy |= ~0x5ff;

                if (dev->accel.cmd & 0x1000) {
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len);
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len);
                } else {
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len);
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len);
                }
            }
            break;
        case 0x9ee9:
        case 0xdee9:
            if (len == 1) {
                dev->accel.short_stroke = (dev->accel.short_stroke & 0xff) | (val << 8);
                dev->accel.cx           = dev->accel.cur_x;
                dev->accel.cy           = dev->accel.cur_y;

                if (dev->accel.cur_x >= 0x600) {
                    dev->accel.cx |= ~0x5ff;
                }
                if (dev->accel.cur_y >= 0x600) {
                    dev->accel.cy |= ~0x5ff;
                }

                if (dev->accel.cmd & 0x1000) {
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len);
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len);
                } else {
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len);
                    ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len);
                }
            }
            break;

        case 0xa2e8:
        case 0xe2e8:
            if (port == 0xe2e8) {
                if (dev->accel.cmd_back) {
                    if (len == 1)
                        dev->accel.bkgd_color = (dev->accel.bkgd_color & 0x00ff) | val;
                    else
                        dev->accel.bkgd_color = val;
                } else {
                    if (len == 1) {
                        if (mach->accel.cmd_type >= 0) {
                            if (mach_pixel_read(mach))
                                break;
                            mach->accel.pix_trans[1] = val;
                        }
                    } else {
                        if (mach->accel.cmd_type >= 0) {
                            if (mach_pixel_read(mach))
                                break;
                            mach_accel_out_pixtrans(mach, dev, val);
                        } else {
                            if (ibm8514_cpu_dest(svga))
                                break;
                            ibm8514_accel_out_pixtrans(svga, port, val, len);
                        }
                    }
                }
            } else {
                if (len == 1)
                    dev->accel.bkgd_color = (dev->accel.bkgd_color & 0x00ff) | val;
                else
                    dev->accel.bkgd_color = val;
            }
            break;
        case 0xa2e9:
        case 0xe2e9:
            if (port == 0xe2e9) {
                if (dev->accel.cmd_back) {
                    if (len == 1)
                        dev->accel.bkgd_color = (dev->accel.bkgd_color & 0xff00) | (val << 8);
                } else {
                    if (len == 1) {
                        if (mach->accel.cmd_type >= 0) {
                            if (mach_pixel_read(mach))
                                break;
                            mach->accel.pix_trans[0] = val;
                            frgd_sel                 = (mach->accel.dp_config >> 13) & 7;
                            bkgd_sel                 = (mach->accel.dp_config >> 7) & 3;
                            mono_src                 = (mach->accel.dp_config >> 5) & 3;

                            switch (mach->accel.dp_config & 0x200) {
                                case 0x000: /*8-bit size*/
                                    if (mono_src == 2) {
                                        if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                                            mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev);
                                        } else
                                            mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    } else
                                        mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    break;
                                case 0x200: /*16-bit size*/
                                    if (mono_src == 2) {
                                        if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                                            if (mach->accel.dp_config & 0x1000)
                                                mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, mach, dev);
                                            else
                                                mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev);
                                        } else
                                            mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    } else
                                        mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    break;

                                default:
                                    break;
                            }
                        }
                    }
                }
            } else {
                if (len == 1)
                    dev->accel.bkgd_color = (dev->accel.bkgd_color & 0xff00) | (val << 8);
            }
            break;

        case 0xa6e8:
        case 0xe6e8:
            if (port == 0xe6e8) {
                if (dev->accel.cmd_back) {
                    if (len == 1)
                        dev->accel.frgd_color = (dev->accel.frgd_color & 0x00ff) | val;
                    else
                        dev->accel.frgd_color = val;
                } else {
                    if (len == 1) {
                        if (mach->accel.cmd_type >= 0) {
                            if (mach_pixel_read(mach))
                                break;
                            mach->accel.pix_trans[1] = val;
                        }
                    } else {
                        if (mach->accel.cmd_type >= 0) {
                            if (mach_pixel_read(mach))
                                break;
                            mach_accel_out_pixtrans(mach, dev, val);
                        } else {
                            if (ibm8514_cpu_dest(svga))
                                break;
                            ibm8514_accel_out_pixtrans(svga, port, val, len);
                        }
                    }
                }
            } else {
                if (len == 1)
                    dev->accel.frgd_color = (dev->accel.frgd_color & 0x00ff) | val;
                else
                    dev->accel.frgd_color = val;
            }
            break;
        case 0xa6e9:
        case 0xe6e9:
            if (port == 0xe6e9) {
                if (dev->accel.cmd_back) {
                    if (len == 1)
                        dev->accel.frgd_color = (dev->accel.frgd_color & 0xff00) | (val << 8);
                } else {
                    if (len == 1) {
                        if (mach->accel.cmd_type >= 0) {
                            if (mach_pixel_read(mach))
                                break;
                            mach->accel.pix_trans[0] = val;
                            frgd_sel                 = (mach->accel.dp_config >> 13) & 7;
                            bkgd_sel                 = (mach->accel.dp_config >> 7) & 3;
                            mono_src                 = (mach->accel.dp_config >> 5) & 3;

                            switch (mach->accel.dp_config & 0x200) {
                                case 0x000: /*8-bit size*/
                                    if (mono_src == 2) {
                                        if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                                            mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev);
                                        } else
                                            mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    } else
                                        mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    break;
                                case 0x200: /*16-bit size*/
                                    if (mono_src == 2) {
                                        if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                                            if (mach->accel.dp_config & 0x1000)
                                                mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, mach, dev);
                                            else
                                                mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev);
                                        } else
                                            mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    } else
                                        mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                    break;

                                default:
                                    break;
                            }
                        }
                    }
                }
            } else {
                if (len == 1)
                    dev->accel.frgd_color = (dev->accel.frgd_color & 0xff00) | (val << 8);
            }
            break;

        case 0xaae8:
        case 0xaae9:
        case 0xaee8:
        case 0xaee9:
        case 0xb2e8:
        case 0xb2e9:
        case 0xb6e8:
        case 0xbae8:
        case 0xeae8:
        case 0xeae9:
        case 0xeee8:
        case 0xeee9:
        case 0xf2e8:
        case 0xf2e9:
        case 0xf6e8:
        case 0xfae8:
            ibm8514_accel_out_fifo(svga, port, val, len);
            break;

        case 0xbee8:
        case 0xfee8:
            if (len == 1)
                dev->accel.multifunc_cntl = (dev->accel.multifunc_cntl & 0xff00) | val;
            else {
                dev->accel.multifunc_cntl                             = val;
                dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff;
                if ((dev->accel.multifunc_cntl >> 12) == 1)
                    dev->accel.clip_top = val & 0x7ff;

                if ((dev->accel.multifunc_cntl >> 12) == 2)
                    dev->accel.clip_left = val & 0x7ff;

                if ((dev->accel.multifunc_cntl >> 12) == 3)
                    dev->accel.multifunc[3] = val & 0x7ff;

                if ((dev->accel.multifunc_cntl >> 12) == 4)
                    dev->accel.multifunc[4] = val & 0x7ff;

                mach_log("CLIPBOTTOM=%d, CLIPRIGHT=%d, bpp=%d, pitch=%d.\n", dev->accel.multifunc[3], dev->accel.multifunc[4], dev->accel_bpp, dev->pitch);
                if ((dev->accel.multifunc_cntl >> 12) == 5) {
                    if ((dev->local & 0xff) < 0x02)
                        dev->ext_crt_pitch = 128;
                }
                if (port == 0xfee8)
                    dev->accel.cmd_back = 1;
                else
                    dev->accel.cmd_back = 0;
            }
            break;
        case 0xbee9:
        case 0xfee9:
            if (len == 1) {
                dev->accel.multifunc_cntl                             = (dev->accel.multifunc_cntl & 0xff) | (val << 8);
                dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff;
                if ((dev->accel.multifunc_cntl >> 12) == 1)
                    dev->accel.clip_top = dev->accel.multifunc_cntl & 0x7ff;

                if ((dev->accel.multifunc_cntl >> 12) == 2)
                    dev->accel.clip_left = dev->accel.multifunc_cntl & 0x7ff;

                if ((dev->accel.multifunc_cntl >> 12) == 5) {
                    if ((dev->local & 0xff) < 0x02)
                        dev->ext_crt_pitch = 128;
                }
                if (port == 0xfee9)
                    dev->accel.cmd_back = 1;
                else
                    dev->accel.cmd_back = 0;
            }
            break;

            /*ATI Mach8/32 specific registers*/
        case 0x82ee:
            mach->accel.patt_data_idx = val & 0x1f;
            mach_log("Pattern Data Index = %d.\n", val & 0x1f);
            break;

        case 0x8eee:
            if (len == 1)
                mach->accel.patt_data[mach->accel.patt_data_idx] = val;
            else {
                mach->accel.patt_data[mach->accel.patt_data_idx]     = val & 0xff;
                mach->accel.patt_data[mach->accel.patt_data_idx + 1] = (val >> 8) & 0xff;
                if (mach->accel.mono_pattern_enable)
                    mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & 0x17;
                else {
                    frgd_sel = (mach->accel.dp_config >> 13) & 7;
                    mono_src = (mach->accel.dp_config >> 5) & 3;
                    if ((dev->accel_bpp == 24) && (mach->accel.patt_len == 0x17) && (frgd_sel == 5)) {
                        mach->accel.patt_data_idx += 2;
                        dev->accel.y1 = 1;
                    } else {
                        if (dev->accel_bpp == 24)
                            mach->accel.patt_data_idx += 2;
                        else
                            mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & mach->accel.patt_len;
                    }
                    mach_log("ExtCONFIG = %04x, Pattern Mono = %04x, selidx = %d, dataidx = %d, bit 0 = %02x len = %d.\n", mach->accel.ext_ge_config, val, mach->accel.patt_idx, mach->accel.patt_data_idx, val & 1, mach->accel.patt_len);
                }
            }
            break;
        case 0x8eef:
            if (len == 1) {
                mach->accel.patt_data[mach->accel.patt_data_idx + 1] = val;
                if (mach->accel.mono_pattern_enable)
                    mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & 7;
                else {
                    frgd_sel = (mach->accel.dp_config >> 13) & 7;
                    if ((dev->accel_bpp == 24) && (mach->accel.patt_len == 0x17) && (frgd_sel == 5)) {
                        mach->accel.patt_data_idx += 2;
                        dev->accel.y1 = 1;
                    } else
                        mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & mach->accel.patt_len;
                }
            }
            break;

        case 0x96ee:
            if (len == 1)
                mach->accel.bres_count = (mach->accel.bres_count & 0x700) | val;
            else {
                mach->accel.bres_count = val & 0x7ff;
                mach_log("BresenhamDraw = %04x.\n", mach->accel.dp_config);
                dev->data_available  = 0;
                dev->data_available2 = 0;
                mach->accel.cmd_type = 1;
                mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev);
            }
            break;
        case 0x96ef:
            if (len == 1) {
                mach->accel.bres_count = (mach->accel.bres_count & 0xff) | ((val & 0x07) << 8);
                mach_log("96EE (2) line draw.\n");
                dev->data_available  = 0;
                dev->data_available2 = 0;
                mach->accel.cmd_type = 1;
                mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev);
            }
            break;

        case 0x9aee:
            mach->accel.line_idx = val & 0x07;
            break;

        case 0xa2ee:
            mach_log("Line OPT = %04x\n", val);
            if (len == 1)
                mach->accel.linedraw_opt = (mach->accel.linedraw_opt & 0xff00) | val;
            else {
                mach->accel.linedraw_opt = val;
                mach->accel.bbottom = dev->accel.multifunc[3] & 0x7ff;
                mach->accel.btop = dev->accel.clip_top & 0x7ff;
                mach->accel.bleft = dev->accel.clip_left & 0x7ff;
                mach->accel.bright = dev->accel.multifunc[4] & 0x7ff;
                if (mach->accel.linedraw_opt & 0x100) {
                    mach->accel.bbottom = 2047;
                    mach->accel.btop = 0;
                    mach->accel.bleft = 0;
                    mach->accel.bright = 2047;
                }
            }
            break;
        case 0xa2ef:
            if (len == 1)
                mach->accel.linedraw_opt = (mach->accel.linedraw_opt & 0x00ff) | (val << 8);
            break;

        case 0xa6ee:
            if (len == 1)
                mach->accel.dest_x_start = (mach->accel.dest_x_start & 0x700) | val;
            else
                mach->accel.dest_x_start = val & 0x7ff;
            break;
        case 0xa6ef:
            if (len == 1)
                mach->accel.dest_x_start = (mach->accel.dest_x_start & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xaaee:
            if (len == 1)
                mach->accel.dest_x_end = (mach->accel.dest_x_end & 0x700) | val;
            else
                mach->accel.dest_x_end = val & 0x7ff;
            break;
        case 0xaaef:
            if (len == 1)
                mach->accel.dest_x_end = (mach->accel.dest_x_end & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xaeee:
            if (len == 1)
                mach->accel.dest_y_end = (mach->accel.dest_y_end & 0x700) | val;
            else {
                mach->accel.dest_y_end = val & 0x7ff;
                if ((val + 1) == 0x10000) {
                    mach_log("Dest_Y_end overflow val = %04x\n", val);
                    mach->accel.dest_y_end = 0;
                }
                dev->data_available  = 0;
                dev->data_available2 = 0;
                mach_log("BitBLT = %04x.\n", mach->accel.dp_config);
                mach->accel.cmd_type = 2; /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/
                mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev);
            }
            break;
        case 0xaeef:
            if (len == 1) {
                mach->accel.dest_y_end = (mach->accel.dest_y_end & 0x0ff) | ((val & 0x07) << 8);
                dev->data_available    = 0;
                dev->data_available2   = 0;
                mach->accel.cmd_type   = 2; /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/
                mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev);
            }
            break;

        case 0xb2ee:
            if (len == 1)
                mach->accel.src_x_start = (mach->accel.src_x_start & 0x700) | val;
            else
                mach->accel.src_x_start = val & 0x7ff;
            break;
        case 0xb2ef:
            if (len == 1)
                mach->accel.src_x_start = (mach->accel.src_x_start & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xb6ee:
            dev->accel.bkgd_mix = val & 0xff;
            break;

        case 0xbaee:
            dev->accel.frgd_mix = val & 0xff;
            break;

        case 0xbeee:
            if (len == 1)
                mach->accel.src_x_end = (mach->accel.src_x_end & 0x700) | val;
            else
                mach->accel.src_x_end = val & 0x7ff;
            break;
        case 0xbeef:
            if (len == 1)
                mach->accel.src_x_end = (mach->accel.src_x_end & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xc2ee:
            mach->accel.src_y_dir = val & 1;
            break;

        case 0xc6ee:
            mach->accel.cmd_type = 0;
            mach_log("TODO: Short Stroke.\n");
            break;

        case 0xcaee:
            if (len == 1)
                mach->accel.scan_to_x = (mach->accel.scan_to_x & 0x700) | val;
            else {
                mach->accel.scan_to_x = (val & 0x7ff);
                if ((val + 1) == 0x10000) {
                    mach_log("Scan_to_X overflow val = %04x\n", val);
                    mach->accel.scan_to_x = 0;
                }
                dev->data_available  = 0;
                dev->data_available2 = 0;
                mach->accel.cmd_type = 5; /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/
                mach_log("ScanToX = %04x.\n", mach->accel.dp_config);
                mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev);
            }
            break;
        case 0xcaef:
            if (len == 1) {
                mach->accel.scan_to_x = (mach->accel.scan_to_x & 0x0ff) | ((val & 0x07) << 8);
                dev->data_available   = 0;
                dev->data_available2  = 0;
                mach->accel.cmd_type  = 5; /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/
                mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev);
            }
            break;

        case 0xceee:
            mach_log("CEEE write val = %04x.\n", val);
            if (len == 1)
                mach->accel.dp_config = (mach->accel.dp_config & 0xff00) | val;
            else {
                dev->data_available  = 0;
                dev->data_available2 = 0;
                mach->accel.dp_config = val;
            }
            break;
        case 0xceef:
            if (len == 1)
                mach->accel.dp_config = (mach->accel.dp_config & 0x00ff) | (val << 8);
            break;

        case 0xd2ee:
            mach->accel.patt_len = val & 0x1f;
            mach_log("Pattern Length = %d, val = %04x.\n", val & 0x1f, val);
            mach->accel.mono_pattern_enable = !!(val & 0x80);
            if (len != 1)
                mach->accel.patt_len_reg = val;
            else
                mach->accel.patt_len_reg = (mach->accel.patt_len_reg & 0xff00) | val;
            break;
        case 0xd2ef:
            if (len == 1)
                mach->accel.patt_len_reg = (mach->accel.patt_len_reg & 0x00ff) | (val << 8);
            break;

        case 0xd6ee:
            mach->accel.patt_idx = val & 0x1f;
            mach_log("Pattern Index = %d, val = %02x.\n", val & 0x1f, val);
            break;

        case 0xdaee:
            mach_log("DAEE (extclipl) write val = %d\n", val);
            if (len == 1)
                dev->accel.clip_left = (dev->accel.clip_left & 0x700) | val;
            else
                dev->accel.clip_left = val & 0x7ff;
            break;
        case 0xdaef:
            if (len == 1)
                dev->accel.clip_left = (dev->accel.clip_left & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xdeee:
            mach_log("DEEE (extclipt) write val = %d\n", val);
            if (len == 1)
                dev->accel.clip_top = (dev->accel.clip_top & 0x700) | val;
            else
                dev->accel.clip_top = val & 0x7ff;
            break;
        case 0xdeef:
            if (len == 1)
                dev->accel.clip_top = (dev->accel.clip_top & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xe2ee:
            mach_log("E2EE (extclipr) write val = %d\n", val);
            if (len == 1)
                dev->accel.multifunc[4] = (dev->accel.multifunc[4] & 0x700) | val;
            else
                dev->accel.multifunc[4] = val & 0x7ff;
            break;
        case 0xe2ef:
            if (len == 1)
                dev->accel.multifunc[4] = (dev->accel.multifunc[4] & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xe6ee:
            mach_log("E6EE (extclipb) write val = %d\n", val);
            if (len == 1)
                dev->accel.multifunc[3] = (dev->accel.multifunc[3] & 0x700) | val;
            else
                dev->accel.multifunc[3] = val & 0x7ff;
            break;
        case 0xe6ef:
            if (len == 1)
                dev->accel.multifunc[3] = (dev->accel.multifunc[3] & 0x0ff) | ((val & 0x07) << 8);
            break;

        case 0xeeee:
            if (len == 1)
                mach->accel.dest_cmp_fn = (mach->accel.dest_cmp_fn & 0xff00) | val;
            else
                mach->accel.dest_cmp_fn = val;
            break;
        case 0xeeef:
            if (len == 1)
                mach->accel.dest_cmp_fn = (mach->accel.dest_cmp_fn & 0x00ff) | (val << 8);
            break;

        case 0xf2ee:
            mach_log("F2EE.\n");
            if (len == 1)
                mach->accel.dst_clr_cmp_mask = (mach->accel.dst_clr_cmp_mask & 0xff00) | val;
            else
                mach->accel.dst_clr_cmp_mask = val;
            break;
        case 0xf2ef:
            if (len == 1)
                mach->accel.dst_clr_cmp_mask = (mach->accel.dst_clr_cmp_mask & 0x00ff) | (val << 8);
            break;

        case 0xfeee:
            mach_log("LineDraw = %04x.\n", mach->accel.dp_config);
            if (len != 1) {
                mach->accel.line_array[mach->accel.line_idx] = val;
                dev->accel.cur_x                             = mach->accel.line_array[(mach->accel.line_idx == 4) ? 4 : 0];
                dev->accel.cur_y                             = mach->accel.line_array[(mach->accel.line_idx == 5) ? 5 : 1];
                mach->accel.cx_end_line                      = mach->accel.line_array[2];
                mach->accel.cy_end_line                      = mach->accel.line_array[3];
                if ((mach->accel.line_idx == 3) || (mach->accel.line_idx == 5)) {
                    mach->accel.cmd_type = (mach->accel.line_idx == 5) ? 4 : 3;
                    mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev);
                    mach->accel.line_idx = (mach->accel.line_idx == 5) ? 4 : 2;
                    break;
                }
                mach->accel.line_idx++;
            }
            break;

        default:
            break;
    }
}

static void
mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8514_t *dev)
{
    if (port != 0x7aee && port != 0x7aef && port != 0x42e8 && port != 0x42e9 && port != 0x46e8 && port != 0x46e9)
        mach_log("[%04X:%08X]: Port CALL OUT=%04x, val=%02x.\n", CS, cpu_state.pc, port, val);

    switch (port) {
        case 0x2e8:
        case 0x6e9:
        case 0xae8:
        case 0xee8:
        case 0x12e8:
        case 0x12e9:
        case 0x1ae8:
        case 0x1ae9:
        case 0x1ee8:
        case 0x1ee9:
        case 0x22e8:
        case 0x42e8:
        case 0x42e9:
            ibm8514_accel_out(port, val, svga, 2);
            break;

        case 0x6e8:
            /*In preparation to switch from VGA to 8514/A mode*/
            if (!dev->on[0] || !dev->on[1] || (mach->accel.clock_sel & 0x01)) {
                dev->hdisped = val;
                dev->hdisp = (dev->hdisped + 1) << 3;
            }
            mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val);
            svga_recalctimings(svga);
            break;

        case 0x16e8:
        case 0x16e9:
            /*In preparation to switch from VGA to 8514/A mode*/
            if (!dev->on[0] || !dev->on[1] || (mach->accel.clock_sel & 0x01)) {
                WRITE8(port, dev->v_disp, val);
                dev->v_disp &= 0x1fff;
                dev->vdisp = (dev->v_disp + 1) >> 1;
            }
            mach_log("ATI 8514/A: V_DISP write 16E8 = %d\n", dev->v_disp);
            mach_log("ATI 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val);
            svga_recalctimings(svga);
            break;

        case 0x4ae8:
        case 0x4ae9:
            WRITE8(port, dev->accel.advfunc_cntl, val);
            dev->on[port & 1] = dev->accel.advfunc_cntl & 0x01;
            if ((dev->local & 0xff) < 0x02)
                dev->ext_crt_pitch = 128;

            vga_on = !dev->on[port & 1];
            mach->ext_on[port & 1] = dev->on[port & 1];
            mach32_updatemapping(mach, svga);
            dev->vendor_mode[port & 1] = 0;
            mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", CS, cpu_state.pc, port, dev->on[port & 1], dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp);
            mach_log("IBM mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480");
            svga_recalctimings(svga);
            break;

        /*ATI Mach8/32 specific registers*/
        case 0x2ee:
            mach_log("2EE write val = %02x.\n", val);
            break;
        case 0x2ef:
            mach_log("2EF write val = %02x.\n", val);
            break;

        case 0x6ee:
            mach_log("6EE write val = %02x.\n", val);
            break;
        case 0x6ef:
            mach_log("6EF write val = %02x.\n", val);
            break;

        case 0xaee:
        case 0xaef:
            WRITE8(port, mach->cursor_offset_lo_reg, val);
            mach->cursor_offset_lo = mach->cursor_offset_lo_reg;
            break;

        case 0xeee:
        case 0xeef:
            WRITE8(port, mach->cursor_offset_hi_reg, val);
            mach->cursor_offset_hi = mach->cursor_offset_hi_reg & 0x0f;
            dev->hwcursor.addr = (mach->cursor_offset_lo | (mach->cursor_offset_hi << 16)) << 2;
            dev->hwcursor.ena = !!(mach->cursor_offset_hi_reg & 0x8000);
            break;

        case 0x12ee:
        case 0x12ef:
            WRITE8(port, mach->cursor_x, val);
            dev->hwcursor.x = mach->cursor_x & 0x7ff;
            break;

        case 0x16ee:
        case 0x16ef:
            WRITE8(port, mach->cursor_y, val);
            dev->hwcursor.y = mach->cursor_y & 0xfff;
            break;

        case 0x1aee:
        case 0x1aef:
            WRITE8(port, mach->cursor_col_b, val);
            mach->cursor_col_0 = mach->cursor_col_b & 0xff;
            mach->cursor_col_1 = (mach->cursor_col_b >> 8) & 0xff;
            break;

        case 0x1eee:
        case 0x1eef:
            WRITE8(port, mach->cursor_vh_offset, val);
            dev->hwcursor.xoff = mach->cursor_vh_offset & 0x3f;
            dev->hwcursor.yoff = (mach->cursor_vh_offset >> 8) & 0x3f;
            break;

        case 0x22ee:
            if (mach->pci_bus) {
                mach->pci_cntl_reg = val;
                mach32_updatemapping(mach, svga);
            }
            break;

        case 0x26ee:
        case 0x26ef:
            WRITE8(port, mach->accel.crt_pitch, val);
            dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff;
            if (dev->accel_bpp > 8) {
                if (dev->accel_bpp == 24)
                    dev->ext_crt_pitch *= 3;
                else if (dev->accel_bpp == 32)
                    dev->ext_crt_pitch <<= 2;
                else
                    dev->ext_crt_pitch <<= 1;
            }
            mach_log("ATI 8514/A: (0x%04x) val=0x%02x.\n", port, val);
            svga_recalctimings(svga);
            break;

        case 0x32ee:
        case 0x32ef:
            WRITE8(port, mach->local_cntl, val);
            mach32_updatemapping(mach, svga);
            break;

        case 0x36ee:
        case 0x36ef:
            mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val);
            WRITE8(port, mach->misc, val);
            mach->misc &= 0xfff0;
            break;

        case 0x3aee:
        case 0x3aef:
            WRITE8(port, mach->cursor_col_0_rg, val);
            mach->ext_cur_col_0_g = mach->cursor_col_0_rg & 0xff;
            mach->ext_cur_col_0_r = (mach->cursor_col_0_rg >> 8) & 0xff;
            break;

        case 0x3eee:
        case 0x3eef:
            WRITE8(port, mach->cursor_col_1_rg, val);
            mach->ext_cur_col_1_g = mach->cursor_col_1_rg & 0xff;
            mach->ext_cur_col_1_r = (mach->cursor_col_1_rg >> 8) & 0xff;
            break;

        case 0x42ee:
        case 0x42ef:
            mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val);
            WRITE8(port, mach->accel.test2, val);
            break;

        case 0x46ee:
        case 0x46ef:
            WRITE8(port, mach->shadow_cntl, val);
            mach_log("ATI 8514/A: (0x%04x) val=%02x.\n", port, val);
            break;

        case 0x4aee:
        case 0x4aef:
            WRITE8(port, mach->accel.clock_sel, val);
            dev->on[port & 1] = mach->accel.clock_sel & 0x01;
            mach_log("ATI 8514/A: (0x%04x): ON=%d, val=%04x, hdisp=%d, vdisp=%d, val=0x%02x.\n", port, dev->on[port & 1], val, dev->hdisp, dev->vdisp, val & 0xfe);
            mach_log("ATI mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480");
            mach->ext_on[port & 1] = dev->on[port & 1];
            vga_on = !dev->on[port & 1];
            dev->vendor_mode[port & 1] = 1;
            svga_recalctimings(svga);
            break;

        case 0x52ee:
        case 0x52ef:
            mach_log("ATI 8514/A: (0x%04x) val=%04x.\n", port, val);
            WRITE8(port, mach->accel.scratch0, val);
            break;

        case 0x56ee:
        case 0x56ef:
            mach_log("ATI 8514/A: (0x%04x) val=%04x.\n", port, val);
            WRITE8(port, mach->accel.scratch1, val);
            break;

        case 0x5aee:
        case 0x5aef:
            WRITE8(port, mach->shadow_set, val);
            mach_log("ATI 8514/A: (0x%04x) val=0x%02x.\n", port, val);
            if ((mach->shadow_set & 0x03) == 0x00)
                mach_log("Primary CRT register set.\n");
            else if ((mach->shadow_set & 0x03) == 0x01)
                mach_log("CRT Shadow Set 1: 640x480.\n");
            else if ((mach->shadow_set & 0x03) == 0x02)
                mach_log("CRT Shadow Set 2: 1024x768.\n");
            break;

        case 0x5eee:
        case 0x5eef:
            WRITE8(port, mach->memory_aperture, val);
            mach_log("Memory Aperture = %04x.\n", mach->memory_aperture);
            if (!mach->pci_bus)
                mach->linear_base = (mach->memory_aperture & 0xff00) << 12;

            mach32_updatemapping(mach, svga);
            break;

        case 0x62ee:
            mach_log("62EE write val = %04x, len = %d.\n", val, len);
            break;

        case 0x66ee:
            mach_log("66EE write val = %04x, len = %d.\n", val, len);
            break;

        case 0x6aee:
        case 0x6aef:
            WRITE8(port, mach->accel.max_waitstates, val);
            break;

        case 0x6eee:
        case 0x6eef:
            WRITE8(port, mach->accel.ge_offset_lo, val);
            svga_recalctimings(svga);
            break;

        case 0x72ee:
        case 0x72ef:
            WRITE8(port, mach->accel.ge_offset_hi, val);
            mach_log("ATI 8514/A: (0x%04x) val=0x%02x, geoffset=%04x.\n", port, val, dev->accel.ge_offset);
            svga_recalctimings(svga);
            break;

        case 0x76ee:
        case 0x76ef:
            WRITE8(port, mach->accel.ge_pitch, val);
            dev->ext_pitch = ((mach->accel.ge_pitch & 0xff) << 3);
            mach_log("ATI 8514/A: (0x%04x) val=0x%02x, extpitch=%d.\n", port, val, dev->ext_pitch);
            svga_recalctimings(svga);
            break;

        case 0x7aee:
        case 0x7aef:
            WRITE8(port, mach->accel.ext_ge_config, val);
            if ((dev->local & 0xff) >= 0x02) {
                if (mach->accel.crt_pitch & 0xff)
                    dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff;
                switch (mach->accel.ext_ge_config & 0x30) {
                    case 0:
                    case 0x10:
                        dev->bpp = 0;
                        break;
                    case 0x20:
                        dev->bpp = 1;
                        dev->ext_crt_pitch <<= 1;
                        break;
                    case 0x30:
                        dev->bpp = 0;
                        if (mach->accel.ext_ge_config & 0x200)
                            dev->ext_crt_pitch <<= 2;
                        else
                            dev->ext_crt_pitch *= 3;
                        break;

                    default:
                        break;
                }
                svga_set_ramdac_type(svga, !!(mach->accel.ext_ge_config & 0x4000));
                dev->vendor_mode[port & 1] = 1;
                mach32_updatemapping(mach, svga);
                mach_log("ATI 8514/A: (0x%04x) val=%02x.\n", port, val);
                svga_recalctimings(svga);
            } else {
                ati_eeprom_write(&mach->eeprom, !!(mach->accel.ext_ge_config & 0x4040), !!(mach->accel.ext_ge_config & 0x2020), !!(mach->accel.ext_ge_config & 0x1010));
            }
            break;

        case 0x7eee:
        case 0x7eef:
            WRITE8(port, mach->accel.eeprom_control, val);
            ati_eeprom_write(&mach->eeprom, !!(mach->accel.eeprom_control & 8), !!(mach->accel.eeprom_control & 2), !!(mach->accel.eeprom_control & 1));
            mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val);
            break;

        default:
            break;
    }
}

static void
mach_accel_out(uint16_t port, uint8_t val, mach_t *mach)
{
    svga_t    *svga = &mach->svga;

    mach_log("[%04X:%08X]: Port NORMAL OUT=%04x, val=%04x.\n", CS, cpu_state.pc, port, val);

    mach_accel_out_call(port, val, mach, svga, (ibm8514_t *) svga->dev8514);
}

static uint16_t
mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, int len)
{
    const uint16_t *vram_w = (uint16_t *) dev->vram;
    uint16_t        temp = 0;
    int             cmd;
    int             frgd_sel;
    int             bkgd_sel;
    int             mono_src;

    switch (port) {
        case 0x82e8:
        case 0x86e8:
        case 0x92e8:
        case 0x96e8:
        case 0xc2e8:
        case 0xc6e8:
            temp = ibm8514_accel_in_fifo(svga, port, len);
            break;

        case 0x9ae8:
        case 0xdae8:
            if (len != 1) {
                if (dev->force_busy)
                    temp |= 0x200; /*Hardware busy*/
                dev->force_busy = 0;
                if (dev->data_available) {
                    temp |= 0x100; /*Read Data available*/
                    if (mach->accel.cmd_type >= 0) {
                        switch (mach->accel.cmd_type) {
                            case 2:
                                if (dev->accel.sy >= mach->accel.height)
                                    dev->data_available = 0;
                                break;
                            case 5:
                                if (dev->accel.sx >= mach->accel.width)
                                    dev->data_available = 0;
                                break;
                            default:
                                if (dev->accel.sy < 0)
                                    dev->data_available = 0;
                                break;
                        }
                    } else {
                        if (dev->accel.sy < 0)
                            dev->data_available = 0;
                    }
                }
            }
            mach_log("[%04X:%08X]: 9AE8: Temp = %04x, len = %d\n\n", CS, cpu_state.pc, temp, len);
            break;
        case 0x9ae9:
        case 0xdae9:
            if (len == 1) {
                if (dev->force_busy2)
                    temp |= 2; /*Hardware busy*/
                dev->force_busy2 = 0;
                if (dev->data_available2) {
                    temp |= 1; /*Read Data available*/
                    if (mach->accel.cmd_type >= 0) {
                        switch (mach->accel.cmd_type) {
                            case 2:
                                if (dev->accel.sy >= mach->accel.height)
                                    dev->data_available2 = 0;
                                break;
                            case 5:
                                if (dev->accel.sx >= mach->accel.width)
                                    dev->data_available2 = 0;
                                break;
                            default:
                                if (dev->accel.sy < 0)
                                    dev->data_available2 = 0;
                                break;
                        }
                    } else {
                        if (dev->accel.sy < 0)
                            dev->data_available2 = 0;
                    }
                }
            }
            mach_log("[%04X:%08X]: 9AE9: Temp = %04x, len = %d\n\n", CS, cpu_state.pc, temp, len);
            break;

        case 0xe2e8:
        case 0xe6e8:
            if (mach->accel.cmd_type >= 0) {
                if (mach_pixel_read(mach)) {
                    cmd = -1;
                    if (len == 1) {
                        READ_PIXTRANS_BYTE_IO(dev->accel.dx, 1)
                        temp = mach->accel.pix_trans[1];
                    } else {
                        if (mach->accel.cmd_type == 3) {
                            READ_PIXTRANS_WORD(dev->accel.cx, 0)
                        } else {
                            READ_PIXTRANS_WORD(dev->accel.dx, 0)
                        }
                        mach_accel_out_pixtrans(mach, dev, temp);
                    }
                }
            } else {
                if (ibm8514_cpu_dest(svga)) {
                    cmd = (dev->accel.cmd >> 13);
                    if (len != 1) {
                        READ_PIXTRANS_WORD(dev->accel.cx, 0)
                        if (dev->accel.input && !dev->accel.odd_in && !dev->accel.sx) {
                            temp &= ~0xff00;
                            temp |= (dev->vram[(dev->accel.newdest_in + dev->accel.cur_x) & dev->vram_mask] << 8);
                        }
                        if (dev->subsys_stat & 1) {
                            dev->force_busy = 1;
                            dev->data_available = 1;
                        }
                    }
                    ibm8514_accel_out_pixtrans(svga, port, temp, len);
                }
            }
            break;
        case 0xe2e9:
        case 0xe6e9:
            if (mach->accel.cmd_type >= 0) {
                mach_log("%04x pixtrans read, len=%d.\n", port, len);
                if (mach_pixel_read(mach)) {
                    if (len == 1) {
                        cmd = -1;
                        READ_PIXTRANS_BYTE_IO(dev->accel.dx, 0)

                        temp = mach->accel.pix_trans[0];
                        frgd_sel = (mach->accel.dp_config >> 13) & 7;
                        bkgd_sel = (mach->accel.dp_config >> 7) & 3;
                        mono_src = (mach->accel.dp_config >> 5) & 3;

                        switch (mach->accel.dp_config & 0x200) {
                            case 0x000: /*8-bit size*/
                                if (mono_src == 2) {
                                    if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                                        mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev);
                                    } else
                                        mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                } else
                                    mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                break;
                            case 0x200: /*16-bit size*/
                                if (mono_src == 2) {
                                    if ((frgd_sel != 2) && (bkgd_sel != 2)) {
                                        if (mach->accel.dp_config & 0x1000)
                                            mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, mach, dev);
                                        else
                                            mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev);
                                    } else
                                        mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                } else
                                    mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev);
                                break;

                            default:
                                break;
                        }
                    }
                }
            }
            break;

        case 0xbee8:
        case 0xfee8:
            if (len != 1) {
                mach_log("Multifunc_cntl = %d.\n", dev->accel.multifunc_cntl >> 12);
                switch ((dev->accel.multifunc_cntl >> 12) & 0x0f) {
                    case 0:
                        temp = dev->accel.multifunc[0];
                        break;
                    case 1:
                        temp = dev->accel.clip_top;
                        break;
                    case 2:
                        temp = dev->accel.clip_left;
                        break;
                    case 3:
                        temp = dev->accel.multifunc[3];
                        break;
                    case 4:
                        temp = dev->accel.multifunc[4];
                        break;
                    case 5:
                        temp = dev->accel.multifunc[5];
                        break;
                    case 8:
                        temp = dev->accel.multifunc[8];
                        break;
                    case 9:
                        temp = dev->accel.multifunc[9];
                        break;
                    case 0x0a:
                        temp = dev->accel.multifunc[0x0a];
                        break;

                    default:
                        break;
                }
            }
            break;

        case 0x82ee:
            temp = mach->accel.patt_data_idx;
            break;

        case 0x86ee:
        case 0x86ef:
            temp = 0x0000;
            break;

        case 0x8eee:
            if (len == 1)
                temp = mach->accel.ext_ge_config & 0xff;
            else
                temp = mach->accel.ext_ge_config;

            mach_log("ExtGE Read = %04x, len=%d.\n", temp, len);
            break;
        case 0x8eef:
            if (len == 1)
                temp = mach->accel.ext_ge_config >> 8;
            break;

        case 0x92ee:
            if (len == 1)
                temp = mach->accel.eeprom_control & 0xff;
            else
                temp = mach->accel.eeprom_control;

            mach_log("EEPROM cntl read=%04x, len=%d.\n", temp, len);
            break;
        case 0x92ef:
            if (len == 1)
                temp = mach->accel.eeprom_control >> 8;

            mach_log("EEPROM cntl read+1=%02x, len=%d.\n", temp, len);
            break;

        case 0x96ee:
            if (len == 1)
                temp = mach->accel.test & 0xff;
            else
                temp = mach->accel.test;
            break;
        case 0x96ef:
            if (len == 1)
                temp = mach->accel.test >> 8;
            break;

        case 0xa2ee:
            if (len == 1)
                temp = mach->accel.linedraw_opt & 0xff;
            else
                temp = mach->accel.linedraw_opt;
            break;
        case 0xa2ef:
            if (len == 1)
                temp = mach->accel.linedraw_opt >> 8;
            break;

        case 0xb2ee:
            if (len == 1)
                temp = dev->hdisped;
            else {
                temp = dev->hdisped & 0xff;
                temp |= (dev->htotal << 8);
            }
            mach_log("B2EE read=%02x.\n", temp & 0xff);
            break;
        case 0xb2ef:
            if (len == 1)
                temp = dev->htotal;
            break;

        case 0xb6ee:
            temp = dev->hsync_start;
            break;

        case 0xbaee:
            temp = dev->hsync_width;
            break;

        case 0xc2ee:
            if (len == 1)
                temp = dev->v_total_reg & 0xff;
            else {
                temp = dev->v_total_reg;
                mach_log("VTOTAL read=%d.\n", temp);
            }
            break;
        case 0xc2ef:
            if (len == 1)
                temp = dev->v_total_reg >> 8;
            break;

        case 0xc6ee:
            if (len == 1)
                temp = dev->v_disp & 0xff;
            else {
                temp = dev->v_disp;
                mach_log("VDISP read=%d.\n", temp);
            }
            break;
        case 0xc6ef:
            if (len == 1)
                temp = dev->v_disp >> 8;
            break;

        case 0xcaee:
            if (len == 1)
                temp = dev->v_sync_start & 0xff;
            else
                temp = dev->v_sync_start;
            break;
        case 0xcaef:
            if (len == 1)
                temp = dev->v_sync_start >> 8;
            break;

        case 0xceee:
            if (len == 1)
                temp = dev->vc & 0xff;
            else
                temp = dev->vc & 0x7ff;
            break;
        case 0xceef:
            if (len == 1)
                temp = (dev->vc >> 8) & 7;
            break;

        case 0xdaee:
            if (len != 1) {
                temp = mach->accel.src_x;
                if ((dev->local & 0xff) >= 0x02)
                    temp &= 0x7ff;
            } else
                temp = mach->accel.src_x & 0xff;
            break;
        case 0xdaef:
            if (len == 1)
                temp = mach->accel.src_x >> 8;
            break;

        case 0xdeee:
            if (len != 1) {
                temp = mach->accel.src_y;
                if ((dev->local & 0xff) >= 0x02)
                    temp &= 0x7ff;
            } else
                temp = mach->accel.src_y & 0xff;
            break;
        case 0xdeef:
            if (len == 1)
                temp = mach->accel.src_y >> 8;
            break;

        case 0xfaee:
            if (len != 1) {
                if ((dev->local & 0xff) >= 0x02) {
                    if (mach->pci_bus)
                        temp = 0x0017;
                    else
                        temp = 0x22f7;
                }
            } else {
                if ((dev->local & 0xff) >= 0x02) {
                    if (mach->pci_bus)
                        temp = 0x17;
                    else
                        temp = 0xf7;
                }
            }
            break;
        case 0xfaef:
            if (len == 1) {
                if ((dev->local & 0xff) >= 0x02) {
                    if (mach->pci_bus)
                        temp = 0x00;
                    else
                        temp = 0x22;
                }
            }
            break;

        default:
            break;
    }

    mach_log("[%04X:%08X]: Port FIFO IN=%04x, temp=%04x, len=%d.\n", CS, cpu_state.pc, port, temp, len);

    return temp;
}

static uint8_t
mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev)
{
    uint8_t         temp        = 0;
    uint16_t        clip_b_ibm  = dev->accel.multifunc[3];
    uint16_t        clip_r_ibm  = dev->accel.multifunc[4];
    int16_t         clip_l      = dev->accel.clip_left & 0x7ff;
    int16_t         clip_t      = dev->accel.clip_top & 0x7ff;
    int16_t         clip_r      = dev->accel.multifunc[4] & 0x7ff;
    int16_t         clip_b      = dev->accel.multifunc[3] & 0x7ff;
    int             cmd         = (dev->accel.cmd >> 13);

    switch (port) {
        case 0x2e8:
        case 0x6e8:
        case 0x22e8:
        case 0x26e8:
        case 0x26e9:
        case 0x2ee8:
        case 0x2ee9:
            temp = ibm8514_accel_in(port, svga);
            break;

        case 0x42e8:
        case 0x42e9:
            if (dev->vc == dev->v_syncstart)
                dev->subsys_stat |= 1;

            if (mach->accel.cmd_type >= 0) {
                if (((dev->accel.dx) >= clip_l) && ((dev->accel.dx) <= clip_r) && ((dev->accel.dy) >= clip_t) && ((dev->accel.dy) <= clip_b))
                    temp |= 2;
            } else {
                if (cmd == 6) {
                    if (((dev->accel.dx) >= dev->accel.clip_left) && ((dev->accel.dx) <= clip_r_ibm) && ((dev->accel.dy) >= dev->accel.clip_top) && ((dev->accel.dy) <= clip_b_ibm))
                        temp |= 2;
                } else {
                    if (((dev->accel.cx) >= dev->accel.clip_left) && ((dev->accel.dx) <= clip_r_ibm) && ((dev->accel.cy) >= dev->accel.clip_top) && ((dev->accel.cy) <= clip_b_ibm))
                        temp |= 2;
                }
            }

            if (!dev->force_busy)
                temp |= 8;

            if (port & 1)
                temp = 0x80;
            else {
                temp |= (dev->subsys_stat | 0x80);
                if (mach->accel.ext_ge_config & 0x08)
                    temp |= ((mach->accel.ext_ge_config & 0x07) << 4);
                else
                    temp |= 0x20;
            }
            mach_log("0x%04x read: Subsystem Status=%02x.\n", port, temp);
            break;

            /*ATI Mach8/32 specific registers*/
        case 0x12ee:
        case 0x12ef:
            READ8(port, mach->config1);
            break;

        case 0x16ee:
        case 0x16ef:
            READ8(port, mach->config2);
            break;

        case 0x1aee:
        case 0x1aef:
            temp = 0x00;
            break;

        case 0x22ee:
            if (mach->pci_bus)
                temp = mach->pci_cntl_reg;
            break;

        case 0x32ee:
        case 0x32ef:
            READ8(port, mach->local_cntl);
            break;

        case 0x36ee:
        case 0x36ef:
            READ8(port, mach->misc);

            if (!(port & 1)) {
                temp &= ~0x0c;
                switch (mach->memory) {
                    case 1024:
                        temp |= 0x04;
                        break;
                    case 2048:
                        temp |= 0x08;
                        break;
                    case 4096:
                        temp |= 0x0c;
                        break;

                    default:
                        if ((dev->local & 0xff) < 0x02)
                            temp |= 0x04;
                        break;
                }
            }
            break;

        case 0x42ee:
        case 0x42ef:
            READ8(port, mach->accel.test2);
            break;

        case 0x46ee:
        case 0x46ef:
            READ8(port, mach->shadow_cntl);
            break;

        case 0x4aee:
        case 0x4aef:
            READ8(port, mach->accel.clock_sel);
            break;

        case 0x52ee:
        case 0x52ef:
            READ8(port, mach->accel.scratch0);
#ifdef ATI_8514_ULTRA
            if (mach->mca_bus) {
                if (!(port & 1)) {
                    if (svga->ext8514 != NULL)
                        temp = dev->pos_regs[4];
                } else {
                    if (svga->ext8514 != NULL)
                        temp = dev->pos_regs[5];
                }
            } else {
                if (svga->ext8514 != NULL) {
                    temp = ((dev->bios_addr >> 7) - 0x1000) >> 4;
                    if (port & 1) {
                        temp &= ~0x80;
                        temp |= 0x01;
                    }
                } else
                    temp = 0x00;
            }
#endif
            break;

        case 0x56ee:
        case 0x56ef:
            READ8(port, mach->accel.scratch1);
            break;

        case 0x5eee:
        case 0x5eef:
            if (mach->pci_bus)
                mach->memory_aperture = (mach->memory_aperture & ~0xfff0) | ((mach->linear_base >> 20) << 4);

            READ8(port, mach->memory_aperture);
            break;

        case 0x62ee:
            temp = mach->accel.clip_overrun;
            mach_log("ClipOverrun = %02x.\n", temp);
            break;
        case 0x62ef:
            if (mach->force_busy)
                temp |= 0x20;

            mach->force_busy = 0;
            if (ati_eeprom_read(&mach->eeprom))
                temp |= 0x40;

            mach_log("Mach busy temp=%02x.\n", temp);
            break;

        case 0x6aee:
        case 0x6aef:
            READ8(port, mach->accel.max_waitstates);
            break;

        case 0x72ee:
        case 0x72ef:
            READ8(port, (mach->accel.bleft));
            break;

        case 0x76ee:
        case 0x76ef:
            READ8(port, (mach->accel.btop));
            break;

        case 0x7aee:
        case 0x7aef:
            READ8(port, (mach->accel.bright));
            break;

        case 0x7eee:
        case 0x7eef:
            READ8(port, (mach->accel.bbottom));
            break;

        default:
            break;
    }
    if (port != 0x62ee && port != 0x62ef && port != 0x42e8 && port != 0x42e9)
        mach_log("[%04X:%08X]: Port NORMAL IN=%04x, temp=%04x.\n", CS, cpu_state.pc, port, temp);

    return temp;
}

#ifdef ATI_8514_ULTRA
static void
ati8514_accel_out(uint16_t port, uint8_t val, svga_t *svga)
{
    mach_log("[%04X:%08X]: Port NORMAL OUT=%04x, val=%04x.\n", CS, cpu_state.pc, port, val);

    mach_accel_out_call(port, val, (mach_t *)svga->ext8514, svga, (ibm8514_t *) svga->dev8514);
}

static void
ati8514_accel_outb(uint16_t port, uint8_t val, void *priv)
{
    svga_t *svga = (svga_t *)priv;
    mach_t *mach = (mach_t *)svga->ext8514;

    if (port & 0x8000)
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 1);
    else
        ati8514_accel_out(port, val, svga);
}

static void
ati8514_accel_outw(uint16_t port, uint16_t val, void *priv)
{
    svga_t *svga = (svga_t *)priv;
    mach_t *mach = (mach_t *)svga->ext8514;

    if (port & 0x8000)
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 2);
    else {
        ati8514_accel_out(port, val, svga);
        ati8514_accel_out(port + 1, (val >> 8), svga);
    }
}

static void
ati8514_accel_outl(uint16_t port, uint32_t val, void *priv)
{
    svga_t *svga = (svga_t *)priv;
    mach_t *mach = (mach_t *)svga->ext8514;

    if (port & 0x8000) {
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val & 0xffff, 2);
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, val >> 16, 2);
    } else {
        ati8514_accel_out(port, val, svga);
        ati8514_accel_out(port + 1, (val >> 8), svga);
        ati8514_accel_out(port + 2, (val >> 16), svga);
        ati8514_accel_out(port + 3, (val >> 24), svga);
    }
}
#endif

static void
mach_accel_outb(uint16_t port, uint8_t val, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;

    if (port & 0x8000)
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 1);
    else
        mach_accel_out(port, val, mach);
}

static void
mach_accel_outw(uint16_t port, uint16_t val, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;

    if (port & 0x8000)
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 2);
    else {
        mach_accel_out(port, val, mach);
        mach_accel_out(port + 1, (val >> 8), mach);
    }
}

static void
mach_accel_outl(uint16_t port, uint32_t val, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;

    if (port & 0x8000) {
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val & 0xffff, 2);
        mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, val >> 16, 2);
    } else {
        mach_accel_out(port, val, mach);
        mach_accel_out(port + 1, (val >> 8), mach);
        mach_accel_out(port + 2, (val >> 16), mach);
        mach_accel_out(port + 3, (val >> 24), mach);
    }
}

#ifdef ATI_8514_ULTRA
static uint8_t
ati8514_accel_in(uint16_t port, svga_t *svga)
{
    return mach_accel_in_call(port, (mach_t *) svga->ext8514, svga, (ibm8514_t *) svga->dev8514);
}

static uint8_t
ati8514_accel_inb(uint16_t port, void *priv)
{
    svga_t *svga = (svga_t *)priv;
    mach_t *mach = (mach_t *)svga->ext8514;
    uint8_t temp;

    if (port & 0x8000)
        temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 1);
    else
        temp = ati8514_accel_in(port, svga);

    return temp;
}

static uint16_t
ati8514_accel_inw(uint16_t port, void *priv)
{
    svga_t *svga = (svga_t *)priv;
    mach_t *mach = (mach_t *)svga->ext8514;
    uint16_t temp;

    if (port & 0x8000)
        temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 2);
    else {
        temp = ati8514_accel_in(port, svga);
        temp |= (ati8514_accel_in(port + 1, svga) << 8);
    }
    return temp;
}

static uint32_t
ati8514_accel_inl(uint16_t port, void *priv)
{
    svga_t *svga = (svga_t *)priv;
    mach_t *mach = (mach_t *)svga->ext8514;
    uint32_t temp;

    if (port & 0x8000) {
        temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 2);
        temp = (mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, 2) << 16);
    } else {
        temp = ati8514_accel_in(port, svga);
        temp |= (ati8514_accel_in(port + 1, svga) << 8);
        temp |= (ati8514_accel_in(port + 2, svga) << 16);
        temp |= (ati8514_accel_in(port + 3, svga) << 24);
    }
    return temp;
}
#endif

static uint8_t
mach_accel_in(uint16_t port, mach_t *mach)
{
    svga_t *svga = &mach->svga;
    return mach_accel_in_call(port, mach, svga, (ibm8514_t *) svga->dev8514);
}

static uint8_t
mach_accel_inb(uint16_t port, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;
    uint8_t temp;

    if (port & 0x8000)
        temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 1);
    else
        temp = mach_accel_in(port, mach);

    return temp;
}

static uint16_t
mach_accel_inw(uint16_t port, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;
    uint16_t temp;

    if (port & 0x8000)
        temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 2);
    else {
        temp = mach_accel_in(port, mach);
        temp |= (mach_accel_in(port + 1, mach) << 8);
    }
    return temp;
}

static uint32_t
mach_accel_inl(uint16_t port, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;
    uint32_t temp;

    if (port & 0x8000) {
        temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 2);
        temp = (mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, 2) << 16);
    } else {
        temp = mach_accel_in(port, mach);
        temp |= (mach_accel_in(port + 1, mach) << 8);
        temp |= (mach_accel_in(port + 2, mach) << 16);
        temp |= (mach_accel_in(port + 3, mach) << 24);
    }
    return temp;
}

static uint32_t
mach32_decode_addr(svga_t *svga, uint32_t addr, int write)
{
    int memory_map_mode = (svga->gdcreg[6] >> 2) & 3;

    addr &= 0x1ffff;

    switch (memory_map_mode) {
        case 0:
            break;
        case 1:
            if (addr >= 0x10000)
                return 0xffffffff;
            break;
        case 2:
            addr -= 0x10000;
            if (addr >= 0x8000)
                return 0xffffffff;
            break;
        default:
        case 3:
            addr -= 0x18000;
            if (addr >= 0x8000)
                return 0xffffffff;
            break;
    }

    if (memory_map_mode <= 1) {
        if (write)
            addr = (addr & svga->banked_mask) + svga->write_bank;
        else
            addr = (addr & svga->banked_mask) + svga->read_bank;
    }

    return addr;
}

static __inline void
mach32_write_common(uint32_t addr, uint8_t val, int linear, mach_t *mach, svga_t *svga)
{
    ibm8514_t *dev = (ibm8514_t *) svga->dev8514;
    int     writemask2 = svga->writemask;
    int     reset_wm   = 0;
    latch8514_t vall;
    uint8_t wm = svga->writemask;
    uint8_t count;
    uint8_t i;

    cycles -= svga->monitor->mon_video_timing_write_b;

    if (linear) {
        addr &= svga->decode_mask;
        if (addr >= dev->vram_size)
            return;
        addr &= dev->vram_mask;
        dev->changedvram[addr >> 12] = svga->monitor->mon_changeframecount;
        dev->vram[addr]              = val;
        return;
    } else {
        addr = mach32_decode_addr(svga, addr, 1);
        if (addr == 0xffffffff)
            return;
    }

    if (!(svga->gdcreg[6] & 1))
        svga->fullchange = 2;

    if (((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only) && (svga->writemode < 4)) {
        writemask2 = 1 << (addr & 3);
        addr &= ~3;
    } else if (svga->chain4 && (svga->writemode < 4)) {
        writemask2 = 1 << (addr & 3);
        addr &= ~3;
        addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff);
    } else if (svga->chain2_write) {
        writemask2 &= ~0xa;
        if (addr & 1)
            writemask2 <<= 1;
        addr &= ~1;
        addr &= dev->vram_mask;
    } else {
        writemask2 = 1 << (addr & 3);
        addr &= ~3;
        addr &= dev->vram_mask;
    }
    addr &= svga->decode_mask;

    if (addr >= dev->vram_size)
        return;

    addr &= dev->vram_mask;

    dev->changedvram[addr >> 12] = svga->monitor->mon_changeframecount;

    count = 4;

    switch (svga->writemode) {
        case 0:
            val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7))));
            if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) {
                for (i = 0; i < count; i++) {
                    if (writemask2 & (1 << i))
                        dev->vram[addr | i] = val;
                }
                return;
            } else {
                for (i = 0; i < count; i++) {
                    if (svga->gdcreg[1] & (1 << i))
                        vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff;
                    else
                        vall.b[i] = val;
                }
            }
            break;
        case 1:
            for (i = 0; i < count; i++) {
                if (writemask2 & (1 << i))
                    dev->vram[addr | i] = dev->latch.b[i];
            }
            return;
        case 2:
            for (i = 0; i < count; i++)
                vall.b[i] = !!(val & (1 << i)) * 0xff;

            if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) {
                for (i = 0; i < count; i++) {
                    if (writemask2 & (1 << i))
                        dev->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (dev->latch.b[i] & ~svga->gdcreg[8]);
                }
                return;
            }
            break;
        case 3:
            val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7))));
            wm  = svga->gdcreg[8];
            svga->gdcreg[8] &= val;

            for (i = 0; i < count; i++)
                vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff;

            reset_wm = 1;
            break;
        default:
            break;
    }

    switch (svga->gdcreg[3] & 0x18) {
        case 0x00: /* Set */
            for (i = 0; i < count; i++) {
                if (writemask2 & (1 << i))
                    dev->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (dev->latch.b[i] & ~svga->gdcreg[8]);
            }
            break;
        case 0x08: /* AND */
            for (i = 0; i < count; i++) {
                if (writemask2 & (1 << i))
                    dev->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & dev->latch.b[i];
            }
            break;
        case 0x10: /* OR */
            for (i = 0; i < count; i++) {
                if (writemask2 & (1 << i))
                    dev->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | dev->latch.b[i];
            }
            break;
        case 0x18: /* XOR */
            for (i = 0; i < count; i++) {
                if (writemask2 & (1 << i))
                    dev->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ dev->latch.b[i];
            }
            break;

        default:
            break;
    }

    if (reset_wm)
        svga->gdcreg[8] = wm;
}

#ifdef ATI_8514_ULTRA
static void
ati8514_write(uint32_t addr, uint8_t val, void *priv)
{
    svga_t *svga = (svga_t *) priv;
    mach_t *mach = (mach_t *) svga->ext8514;
    mach32_write_common(addr, val, 0, mach, svga);
}

static void
ati8514_writew(uint32_t addr, uint16_t val, void *priv)
{
    svga_t *svga = (svga_t *) priv;
    mach_t *mach = (mach_t *) svga->ext8514;
    mach32_write_common(addr, val & 0xff, 0, mach, svga);
    mach32_write_common(addr + 1, val >> 8, 0, mach, svga);
}

static void
ati8514_writel(uint32_t addr, uint32_t val, void *priv)
{
    svga_t *svga = (svga_t *) priv;
    mach_t *mach = (mach_t *) svga->ext8514;
    mach32_write_common(addr, val & 0xff, 0, mach, svga);
    mach32_write_common(addr + 1, val >> 8, 0, mach, svga);
    mach32_write_common(addr + 2, val >> 16, 0, mach, svga);
    mach32_write_common(addr + 3, val >> 24, 0, mach, svga);
}
#endif

static void
mach32_write(uint32_t addr, uint8_t val, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    mach32_write_common(addr, val, 0, mach, &mach->svga);
}

static void
mach32_writew(uint32_t addr, uint16_t val, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    mach32_write_common(addr, val & 0xff, 0, mach, &mach->svga);
    mach32_write_common(addr + 1, val >> 8, 0, mach, &mach->svga);
}

static void
mach32_writel(uint32_t addr, uint32_t val, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    mach32_write_common(addr, val & 0xff, 0, mach, &mach->svga);
    mach32_write_common(addr + 1, val >> 8, 0, mach, &mach->svga);
    mach32_write_common(addr + 2, val >> 16, 0, mach, &mach->svga);
    mach32_write_common(addr + 3, val >> 24, 0, mach, &mach->svga);
}

static __inline void
mach32_writew_linear(uint32_t addr, uint16_t val, mach_t *mach)
{
    svga_t *svga = &mach->svga;
    ibm8514_t *dev = (ibm8514_t *) svga->dev8514;

    cycles -= svga->monitor->mon_video_timing_write_w;

    addr &= svga->decode_mask;
    if (addr >= dev->vram_size)
        return;
    addr &= dev->vram_mask;
    dev->changedvram[addr >> 12] = svga->monitor->mon_changeframecount;
    *(uint16_t *) &dev->vram[addr] = val;
}

static __inline void
mach32_writel_linear(uint32_t addr, uint32_t val, mach_t *mach)
{
    svga_t *svga = &mach->svga;
    ibm8514_t *dev = (ibm8514_t *) svga->dev8514;

    cycles -= svga->monitor->mon_video_timing_write_l;

    addr &= svga->decode_mask;
    if (addr >= dev->vram_size)
        return;
    addr &= dev->vram_mask;
    dev->changedvram[addr >> 12] = svga->monitor->mon_changeframecount;
    *(uint32_t *) &dev->vram[addr] = val;
}

static __inline uint8_t
mach32_read_common(uint32_t addr, int linear, mach_t *mach, svga_t *svga)
{
    ibm8514_t       *dev        = (ibm8514_t *) svga->dev8514;
    uint32_t         latch_addr = 0;
    int              readplane  = svga->readplane;
    uint8_t          count;
    uint8_t          temp;
    uint8_t          ret;

    cycles -= svga->monitor->mon_video_timing_read_b;

    if (linear) {
        addr &= svga->decode_mask;
        if (addr >= dev->vram_size)
            return 0xff;

        return dev->vram[addr & dev->vram_mask];
    } else {
        addr = mach32_decode_addr(svga, addr, 0);
        if (addr == 0xffffffff)
            return 0xff;
    }

    count = 2;

    latch_addr = (addr << count) & svga->decode_mask;
    count      = (1 << count);

    if ((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only) {
        addr &= svga->decode_mask;
        if (addr >= dev->vram_size)
            return 0xff;
        latch_addr = (addr & dev->vram_mask) & ~3;
        for (uint8_t i = 0; i < count; i++)
            dev->latch.b[i] = dev->vram[latch_addr | i];
        return dev->vram[addr & dev->vram_mask];
    } else if (svga->chain4 && !svga->force_old_addr) {
        readplane = addr & 3;
        addr      = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff);
    } else if (svga->chain2_read) {
        readplane = (readplane & 2) | (addr & 1);
        addr &= ~1;
        addr &= dev->vram_mask;
    } else {
        addr &= svga->decode_mask;
        if (addr >= dev->vram_size)
            return 0xff;
        latch_addr = (addr & dev->vram_mask) & ~3;
        for (uint8_t i = 0; i < count; i++)
            dev->latch.b[i] = dev->vram[latch_addr | i];
        return dev->vram[addr & dev->vram_mask];
    }

    addr &= svga->decode_mask;

    /* standard VGA latched access */
    if (latch_addr >= dev->vram_size) {
        for (uint8_t i = 0; i < count; i++)
            dev->latch.b[i] = 0xff;
    } else {
        latch_addr &= dev->vram_mask;

        for (uint8_t i = 0; i < count; i++)
            dev->latch.b[i] = dev->vram[latch_addr | i];
    }

    if (addr >= dev->vram_size)
        return 0xff;

    addr &= dev->vram_mask;

    if (svga->readmode) {
        temp = 0xff;

        for (uint8_t pixel = 0; pixel < 8; pixel++) {
            for (uint8_t plane = 0; plane < count; plane++) {
                if (svga->colournocare & (1 << plane)) {
                    /* If we care about a plane, and the pixel has a mismatch on it, clear its bit. */
                    if (((dev->latch.b[plane] >> pixel) & 1) != ((svga->colourcompare >> plane) & 1))
                        temp &= ~(1 << pixel);
                }
            }
        }

        ret = temp;
    } else
        ret = dev->vram[addr | readplane];

    return ret;
}

#ifdef ATI_8514_ULTRA
static uint8_t
ati8514_read(uint32_t addr, void *priv)
{
    svga_t *svga = (svga_t *) priv;
    mach_t *mach = (mach_t *) svga->ext8514;
    uint8_t          ret;

    ret  = mach32_read_common(addr, 0, mach, svga);
    return ret;
}

static uint16_t
ati8514_readw(uint32_t addr, void *priv)
{
    svga_t *svga = (svga_t *) priv;
    mach_t *mach = (mach_t *) svga->ext8514;
    uint16_t         ret;

    ret  = mach32_read_common(addr, 0, mach, svga);
    ret  |= (mach32_read_common(addr + 1, 0, mach, svga) << 8);
    return ret;
}

static uint32_t
ati8514_readl(uint32_t addr, void *priv)
{
    svga_t *svga = (svga_t *) priv;
    mach_t *mach = (mach_t *) svga->ext8514;
    uint32_t         ret;

    ret  = mach32_read_common(addr, 0, mach, svga);
    ret  |= (mach32_read_common(addr + 1, 0, mach, svga) << 8);
    ret  |= (mach32_read_common(addr + 2, 0, mach, svga) << 16);
    ret  |= (mach32_read_common(addr + 3, 0, mach, svga) << 24);
    return ret;
}
#endif

static uint8_t
mach32_read(uint32_t addr, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    uint8_t          ret;

    ret  = mach32_read_common(addr, 0, mach, &mach->svga);
    return ret;
}

static uint16_t
mach32_readw(uint32_t addr, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    uint16_t         ret;

    ret  = mach32_read_common(addr, 0, mach, &mach->svga);
    ret  |= (mach32_read_common(addr + 1, 0, mach, &mach->svga) << 8);
    return ret;
}

static uint32_t
mach32_readl(uint32_t addr, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    uint32_t         ret;

    ret  = mach32_read_common(addr, 0, mach, &mach->svga);
    ret  |= (mach32_read_common(addr + 1, 0, mach, &mach->svga) << 8);
    ret  |= (mach32_read_common(addr + 2, 0, mach, &mach->svga) << 16);
    ret  |= (mach32_read_common(addr + 3, 0, mach, &mach->svga) << 24);
    return ret;
}

static __inline uint16_t
mach32_readw_linear(uint32_t addr, mach_t *mach)
{
    svga_t          *svga       = &mach->svga;
    ibm8514_t       *dev        = (ibm8514_t *) svga->dev8514;

    cycles -= svga->monitor->mon_video_timing_read_w;

    addr &= svga->decode_mask;
    if (addr >= dev->vram_size)
        return 0xffff;

    return *(uint16_t *) &dev->vram[addr & dev->vram_mask];
}

static __inline uint32_t
mach32_readl_linear(uint32_t addr, mach_t *mach)
{
    svga_t          *svga       = &mach->svga;
    ibm8514_t       *dev        = (ibm8514_t *) svga->dev8514;

    cycles -= svga->monitor->mon_video_timing_read_l;

    addr &= svga->decode_mask;
    if (addr >= dev->vram_size)
        return 0xffffffff;

    return *(uint32_t *) &dev->vram[addr & dev->vram_mask];
}

static void
mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv)
{
    mach_t          *mach  = (mach_t *) priv;
    svga_t          *svga  = &mach->svga;
    const ibm8514_t *dev   = (ibm8514_t *) svga->dev8514;
    uint8_t port_dword     = addr & 0xfc;

    if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) &&
        ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) {
        if (addr & 0x100) {
            mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8));
            mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach);
        } else {
            mach_log("Port WORDB Write=%04x.\n", 0x02e8 + (port_dword << 8));
            mach_accel_outb(0x02e8 + (addr & 1) + (port_dword << 8), val, mach);
        }
    } else {
        mach_log("Linear WORDB Write=%08x, val=%02x.\n", addr, val);
        if (dev->on[0] || dev->on[1])
            mach32_write_common(addr, val, 1, mach, svga);
        else
            svga_write_linear(addr, val, svga);
    }
}

static void
mach32_ap_writew(uint32_t addr, uint16_t val, void *priv)
{
    mach_t          *mach  = (mach_t *) priv;
    svga_t          *svga  = &mach->svga;
    const ibm8514_t *dev   = (ibm8514_t *) svga->dev8514;
    uint8_t port_dword     = addr & 0xfc;

    if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) &&
        ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) {
        if (addr & 0x100) {
            mach_log("Port WORDW Write=%04x.\n", 0x02ee + (port_dword << 8));
            mach_accel_outw(0x02ee + (port_dword << 8), val, mach);
        } else {
            mach_log("Port WORDW Write=%04x.\n", 0x02e8 + (port_dword << 8));
            mach_accel_outw(0x02e8 + (port_dword << 8), val, mach);
        }
    } else {
        mach_log("Linear WORDW Write=%08x, val=%04x.\n", addr, val);
        if (dev->on[0] || dev->on[1]) {
            mach32_writew_linear(addr, val, mach);
        } else
            svga_writew_linear(addr, val, svga);
    }
}

static void
mach32_ap_writel(uint32_t addr, uint32_t val, void *priv)
{
    mach_t          *mach  = (mach_t *) priv;
    svga_t          *svga  = &mach->svga;
    const ibm8514_t *dev   = (ibm8514_t *) svga->dev8514;
    uint8_t port_dword     = addr & 0xfc;

    if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) &&
        ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) {
        if (addr & 0x100) {
            mach_log("Port WORDL Write=%04x.\n", 0x02ee + (port_dword << 8));
            mach_accel_outw(0x02ee + (port_dword << 8), val & 0xffff, mach);
            mach_accel_outw(0x02ee + (port_dword << 8) + 4, val >> 16, mach);
        } else {
            mach_log("Port WORDL Write=%04x.\n", 0x02e8 + (port_dword << 8));
            mach_accel_outw(0x02e8 + (port_dword << 8), val & 0xffff, mach);
            mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach);
        }
    } else {
        mach_log("Linear WORDL Write=%08x, val=%08x.\n", addr, val);
        if (dev->on[0] || dev->on[1]) {
            mach32_writel_linear(addr, val, mach);
        } else
            svga_writel_linear(addr, val, svga);
    }
}

static uint8_t
mach32_ap_readb(uint32_t addr, void *priv)
{
    mach_t          *mach  = (mach_t *) priv;
    svga_t          *svga  = &mach->svga;
    const ibm8514_t *dev   = (ibm8514_t *) svga->dev8514;
    uint8_t temp;
    uint8_t port_dword     = addr & 0xfc;

    if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) &&
        ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) {
        if (addr & 0x100)
            temp = mach_accel_inb(0x02ee + (addr & 1) + (port_dword << 8), mach);
        else
            temp = mach_accel_inb(0x02e8 + (addr & 1) + (port_dword << 8), mach);
    } else {
        if (dev->on[0] || dev->on[1])
            temp = mach32_read_common(addr, 1, mach, svga);
        else
            temp = svga_read_linear(addr, svga);

        mach_log("Linear WORDB Read=%08x, ret=%02x, fast=%d.\n", addr, temp, svga->fast);
    }

    return temp;
}

static uint16_t
mach32_ap_readw(uint32_t addr, void *priv)
{
    mach_t          *mach  = (mach_t *) priv;
    svga_t          *svga  = &mach->svga;
    const ibm8514_t *dev   = (ibm8514_t *) svga->dev8514;
    uint16_t temp;
    uint8_t port_dword     = addr & 0xfc;

    if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) &&
        ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) {
        if (addr & 0x100)
            temp = mach_accel_inw(0x02ee + (port_dword << 8), mach);
        else
            temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach);
    } else {
        if (dev->on[0] || dev->on[1]) {
            temp = mach32_readw_linear(addr, mach);
        } else
            temp = svga_readw_linear(addr, svga);

        mach_log("Linear WORDW Read=%08x, ret=%04x.\n", addr, temp);
    }

    return temp;
}

static uint32_t
mach32_ap_readl(uint32_t addr, void *priv)
{
    mach_t          *mach  = (mach_t *) priv;
    svga_t          *svga  = &mach->svga;
    const ibm8514_t *dev   = (ibm8514_t *) svga->dev8514;
    uint32_t temp;
    uint8_t port_dword     = addr & 0xfc;

    if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) &&
        ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) {
        if (addr & 0x100) {
            temp = mach_accel_inw(0x02ee + (port_dword << 8), mach);
            temp |= (mach_accel_inw(0x02ee + (port_dword << 8) + 4, mach) << 8);
        } else {
            temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach);
            temp |= (mach_accel_inw(0x02e8 + (port_dword << 8) + 4, mach) << 8);
        }
    } else {
        if (dev->on[0] || dev->on[1]) {
            temp = mach32_readl_linear(addr, mach);
        } else
            temp = svga_readl_linear(addr, svga);

        mach_log("Linear WORDL Read=%08x, ret=%08x, ON0=%d, ON1=%d.\n", addr, temp, dev->on[0], dev->on[1]);
    }

    return temp;
}

static void
mach32_updatemapping(mach_t *mach, svga_t *svga)
{
    ibm8514_t *dev = (ibm8514_t *) svga->dev8514;

    if (mach->pci_bus && (!(mach->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM))) {
        mem_mapping_disable(&svga->mapping);
        mem_mapping_disable(&mach->mmio_linear_mapping);
        return;
    }

    if (mach->regs[0xbd] & 4) {
        mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
        svga->banked_mask = 0xffff;
    } else {
        switch (svga->gdcreg[6] & 0x0c) {
            case 0x0: /*128k at A0000*/
                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
                svga->banked_mask = 0xffff;
                break;
            case 0x4: /*64k at A0000*/
                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
                svga->banked_mask = 0xffff;
                break;
            case 0x8: /*32k at B0000*/
                mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
                svga->banked_mask = 0x7fff;
                break;
            case 0xC: /*32k at B8000*/
                mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
                svga->banked_mask = 0x7fff;
                break;

            default:
                break;
        }
    }

    mach_log("Linear base = %08x, aperture = %04x, localcntl = %02x svgagdc = %x.\n", mach->linear_base, mach->memory_aperture, mach->local_cntl, svga->gdcreg[6] & 0x0c);
    if (mach->linear_base) {
        if (((mach->memory_aperture & 3) == 1) && !mach->pci_bus) {
            /*1 MB aperture*/
            mach->ap_size = 1;
            mem_mapping_set_addr(&mach->mmio_linear_mapping, mach->linear_base, mach->ap_size << 20);
        } else {
            /*4 MB aperture*/
            mach->ap_size = 4;
            mem_mapping_set_addr(&mach->mmio_linear_mapping, mach->linear_base, mach->ap_size << 20);
        }
    } else {
        mach->ap_size = 4;
        mem_mapping_disable(&mach->mmio_linear_mapping);
    }
    if ((dev->on[0] || dev->on[1]) && (mach->ext_on[0] || mach->ext_on[1]) && (dev->vendor_mode[0] || dev->vendor_mode[1])) {
        mach_log("ExtON.\n");
#ifdef ATI_8514_ULTRA
        if (svga->ext8514 != NULL) {
            mem_mapping_set_handler(&svga->mapping, ati8514_read, ati8514_readw, ati8514_readl, ati8514_write, ati8514_writew, ati8514_writel);
            mem_mapping_set_p(&svga->mapping, svga);
        } else
#endif
        {
            mem_mapping_set_handler(&svga->mapping, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel);
            mem_mapping_set_p(&svga->mapping, mach);
        }
    } else {
        mach_log("ExtOFF.\n");
        mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
        mem_mapping_set_p(&svga->mapping, svga);
    }
}

static void
mach32_hwcursor_draw(svga_t *svga, int displine)
{
    const mach_t *mach   = (mach_t *) svga->priv;
    ibm8514_t    *dev    = (ibm8514_t *) svga->dev8514;
    uint16_t      dat;
    int           comb;
    int           offset = dev->hwcursor_latch.x - dev->hwcursor_latch.xoff;
    uint32_t      color0;
    uint32_t      color1;
    uint32_t      *p;
    int           x_pos;
    int           y_pos;

    mach_log("BPP=%d.\n", dev->accel_bpp);
    switch (dev->accel_bpp) {
        default:
        case 8:
            color0 = dev->pallook[mach->cursor_col_0];
            color1 = dev->pallook[mach->cursor_col_1];
            break;
        case 15:
            color0 = video_15to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff];
            color1 = video_15to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff];
            break;
        case 16:
            color0 = video_16to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff];
            color1 = video_16to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff];
            break;
        case 24:
        case 32:
            color0 = ((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0);
            color1 = ((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1);
            break;
    }

    if (dev->interlace && dev->hwcursor_oddeven)
        dev->hwcursor_latch.addr += 16;

    for (int x = 0; x < 64; x += 8) {
        dat = dev->vram[dev->hwcursor_latch.addr & dev->vram_mask] | (dev->vram[(dev->hwcursor_latch.addr + 1) & dev->vram_mask] << 8);
        for (int xx = 0; xx < 8; xx++) {
            comb = (dat >> (xx << 1)) & 0x03;

            y_pos = displine;
            x_pos = offset + svga->x_add;
            p     = buffer32->line[y_pos];

            if (offset >= dev->hwcursor_latch.x) {
                mach_log("COMB=%d.\n", comb);
                switch (comb) {
                    case 0:
                        p[x_pos] = color0;
                        break;
                    case 1:
                        p[x_pos] = color1;
                        break;
                    case 3:
                        p[x_pos] ^= 0xffffff;
                        break;

                    default:
                        break;
                }
            }
            offset++;
        }
        dev->hwcursor_latch.addr += 2;
    }
    if (dev->interlace && !dev->hwcursor_oddeven)
        dev->hwcursor_latch.addr += 16;
}

#ifdef ATI_8514_ULTRA
static void
ati8514_io_set(svga_t *svga)
{
    io_sethandler(0x2e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x6e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x12e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x16e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x1ae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x1ee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x22e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x26e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x2ee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x42e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x46e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x4ae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x52e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x56e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x5ae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x5ee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x82e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x86e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x8ae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x8ee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x92e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x96e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x9ae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x9ee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xa2e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xa6e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xaae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xaee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xb2e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xb6e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xbae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xbee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xe2e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);

    io_sethandler(0xc2e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xc6e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xcae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xcee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xd2e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xd6e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xdae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xdee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xe6e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xeae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xeee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xf2e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xf6e8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xfae8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xfee8, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);

    io_sethandler(0x02ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x06ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x0aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x0eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x12ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x16ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x1aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x1eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x22ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x26ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x2aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x2eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x32ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x36ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x3aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x3eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x42ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x46ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x4aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x52ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x56ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x5aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x5eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x62ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x66ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x6aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x6eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x72ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x76ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x7aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x7eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x82ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x86ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x8eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x92ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x96ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0x9aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xa2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xa6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xaaee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xaeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xb2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xb6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xbaee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xbeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xc2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xc6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xcaee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xceee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xd2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xd6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xdaee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xdeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xe2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xe6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xeeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xf2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xf6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
    io_sethandler(0xfeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
}
#endif

static void
mach_io_set(mach_t *mach)
{
    io_sethandler(0x2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x12e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x16e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x1ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x1ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x22e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x26e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x2ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x42e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x46e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x4ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x52e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x56e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x5ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x5ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x82e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x86e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x8ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x8ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x92e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x96e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x9ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x9ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xa2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xa6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xaae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xaee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xb2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xb6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xbae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xbee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xe2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);

    io_sethandler(0xc2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xc6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xcae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xcee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xd2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xd6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xdae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xdee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xe6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xeae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xeee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xf2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xf6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xfae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xfee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);

    io_sethandler(0x02ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x06ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x0aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x0eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x12ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x16ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x1aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x1eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x22ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x26ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x2aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x2eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x32ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x36ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x3aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x3eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x42ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x46ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x4aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x52ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x56ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x5aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x5eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x62ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x66ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x6aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x6eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x72ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x76ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x7aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x7eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x82ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x86ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x8eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x92ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x96ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0x9aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xa2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xa6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xaaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xaeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xb2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xb6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xbaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xbeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xc2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xc6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xcaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xceee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xd2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xd6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xdaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xdeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xe2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xe6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xeeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xf2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xf6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xfaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
    io_sethandler(0xfeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
}

static uint8_t
mach_mca_read(int port, void *priv)
{
    const mach_t *mach = (mach_t *) priv;

    mach_log("[%04X]: MCA read port = %x, val = %02x.\n", CS, port & 7, mach->pos_regs[port & 7]);
    return mach->pos_regs[port & 7];
}

static void
mach_mca_write(int port, uint8_t val, void *priv)
{
    mach_t       *mach = (mach_t *) priv;

    if (port < 0x102)
        return;

    mach->pos_regs[port & 7] = val;
    mach_log("[%04X]: MCA write port = %x, val = %02x, biosaddr = %05x.\n", CS, port & 7, mach->pos_regs[port & 7], (((mach->pos_regs[3] & 0x3e) << 0x0c) >> 1) + 0xc0000);
    mem_mapping_disable(&mach->bios_rom.mapping);
    mem_mapping_disable(&mach->bios_rom2.mapping);
    if (mach->pos_regs[2] & 0x01) {
        mem_mapping_enable(&mach->bios_rom.mapping);
        mem_mapping_enable(&mach->bios_rom2.mapping);
    }
}

static uint8_t
mach_mca_feedb(void *priv)
{
    const mach_t *mach = (mach_t *) priv;

    mach_log("FeedB = %x.\n", mach->pos_regs[2] & 0x01);
    return mach->pos_regs[2] & 0x01;
}

static void
mach_mca_reset(void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t    *svga = &mach->svga;
    ibm8514_t *dev  = (ibm8514_t *) svga->dev8514;

    mem_mapping_disable(&mach->bios_rom.mapping);
    mem_mapping_disable(&mach->bios_rom2.mapping);
    mach_log("MCA reset.\n");
    dev->on[0] = 0;
    dev->on[1] = 0;
    vga_on = 1;
    mach_mca_write(0x102, 0, mach);
}

#ifdef ATI_8514_ULTRA
uint8_t
ati8514_mca_read(int port, void *priv)
{
    const svga_t    *svga = (svga_t *) priv;
    const ibm8514_t *dev  = (ibm8514_t *) svga->dev8514;

    return (dev->pos_regs[port & 7]);
}

void
ati8514_mca_write(int port, uint8_t val, void *priv)
{
    svga_t    *svga = (svga_t *) priv;
    ibm8514_t *dev  = (ibm8514_t *) svga->dev8514;

    if (port < 0x102)
        return;

    dev->pos_regs[port & 7] = val;
    mach_log("[%04X]: MCA write port = %x, val = %02x, biosaddr = %05x.\n", CS, port & 7, dev->pos_regs[port & 7], (((dev->pos_regs[3] & 0x3e) << 0x0c) >> 1) + 0xc0000);
    mem_mapping_disable(&dev->bios_rom.mapping);

    if (dev->pos_regs[2] & 0x01)
        mem_mapping_enable(&dev->bios_rom.mapping);
}

void
ati8514_pos_write(uint16_t port, uint8_t val, void *priv)
{
    ati8514_mca_write(port, val, priv);
}
#endif

static uint8_t
mach32_pci_read(UNUSED(int func), int addr, void *priv)
{
    const mach_t *mach = (mach_t *) priv;
    uint8_t       ret  = 0x00;

    if ((addr >= 0x30) && (addr <= 0x33) && !mach->has_bios)
        return ret;

    switch (addr) {
        case 0x00:
            ret = 0x02; /*ATI*/
            break;
        case 0x01:
            ret = 0x10;
            break;

        case 0x02:
            ret = 0x58;
            break;
        case 0x03:
            ret = 0x41;
            break;

        case PCI_REG_COMMAND:
            ret = mach->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/
            break;

        case 0x07:
            ret = 0x01; /*Medium DEVSEL timing*/
            break;

        case 0x0a:
            ret = 0x00; /*Supports VGA interface*/
            break;
        case 0x0b:
            ret = 0x03;
            break;

        case 0x10:
            ret = 0x00; /*Linear frame buffer address*/
            break;
        case 0x11:
            ret = 0x00;
            break;
        case 0x12:
            ret = mach->linear_base >> 16;
            break;
        case 0x13:
            ret = mach->linear_base >> 24;
            break;

        case 0x30:
            ret = (mach->pci_regs[0x30] & 0x01); /*BIOS ROM address*/
            break;
        case 0x31:
            ret = 0x00;
            break;
        case 0x32:
            ret = mach->pci_regs[0x32];
            break;
        case 0x33:
            ret = mach->pci_regs[0x33];
            break;

        case 0x3c:
            ret = mach->int_line;
            break;
        case 0x3d:
            ret = PCI_INTA;
            break;

        default:
            break;
    }

    return ret;
}

static void
mach32_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
{
    mach_t *mach = (mach_t *) priv;
    if ((addr >= 0x30) && (addr <= 0x33) && !mach->has_bios)
        return;

    switch (addr) {
        case PCI_REG_COMMAND:
            mach->pci_regs[PCI_REG_COMMAND] = val & 0x27;
            if (val & PCI_COMMAND_IO) {
                io_removehandler(0x02ea, 4,  mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
                io_removehandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
                io_sethandler(0x02ea, 4,  mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
                io_sethandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
            } else {
                io_removehandler(0x02ea, 4,  mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
                io_removehandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
            }
            mach32_updatemapping(mach, &mach->svga);
            break;

        case 0x12:
            mach->linear_base = (mach->linear_base & 0xff000000) | ((val & 0xc0) << 16);
            mach32_updatemapping(mach, &mach->svga);
            break;
        case 0x13:
            mach->linear_base = (mach->linear_base & 0xc00000) | (val << 24);
            mach32_updatemapping(mach, &mach->svga);
            break;

        case 0x30:
        case 0x32:
        case 0x33:
            mach->pci_regs[addr] = val;
            if (mach->pci_regs[0x30] & 0x01) {
                uint32_t bios_addr = (mach->pci_regs[0x32] << 16) | (mach->pci_regs[0x33] << 24);
                mach_log("Mach32 bios_rom enabled at %08x\n", bios_addr);
                mem_mapping_set_addr(&mach->bios_rom.mapping, bios_addr, 0x8000);
            } else {
                mach_log("Mach32 bios_rom disabled\n");
                mem_mapping_disable(&mach->bios_rom.mapping);
            }
            return;

        case 0x3c:
            mach->int_line = val;
            break;

        default:
            break;
    }
}

static void *
mach8_init(const device_t *info)
{
    mach_t    *mach;
    svga_t    *svga;
    ibm8514_t *dev;

    mach             = calloc(1, sizeof(mach_t));

    svga             = &mach->svga;
    dev              = (ibm8514_t *) calloc(1, sizeof(ibm8514_t));

    svga->dev8514    = dev;

    mach->pci_bus    = !!(info->flags & DEVICE_PCI);
    mach->vlb_bus    = !!(info->flags & DEVICE_VLB);
    mach->mca_bus    = !!(info->flags & DEVICE_MCA);
    dev->type        = info->flags;
    dev->local       = info->local & 0xff;
    mach->has_bios   = !(info->local & 0xff00);
    mach->memory     = device_get_config_int("memory");
    mach->ramdac_type = mach->pci_bus ? device_get_config_int("ramdac") : 1;

    if ((dev->local & 0xff) >= 0x02) {
        if (mach->pci_bus) {
            if (mach->has_bios) {
                rom_init(&mach->bios_rom,
                         BIOS_MACH32_PCI_ROM_PATH,
                         0xc0000, 0x8000, 0x7fff,
                         0, MEM_MAPPING_EXTERNAL);
            }
        }
        else if (mach->vlb_bus)
            rom_init(&mach->bios_rom,
                     BIOS_MACH32_VLB_ROM_PATH,
                     0xc0000, 0x8000, 0x7fff,
                     0, MEM_MAPPING_EXTERNAL);
        else if (mach->mca_bus) {
            rom_init(&mach->bios_rom,
                     BIOS_MACH32_MCA_ROM_PATH,
                     0xc0000, 0x8000, 0x7fff,
                     0, MEM_MAPPING_EXTERNAL);
            rom_init(&mach->bios_rom2,
                     BIOS_MACH32_MCA_ROM_PATH,
                     0xc8000, 0x1000, 0x0fff,
                     0x8000, MEM_MAPPING_EXTERNAL);
        } else {
            rom_init(&mach->bios_rom,
                     BIOS_MACH32_ISA_ROM_PATH,
                     0xc0000, 0x8000, 0x7fff,
                     0, MEM_MAPPING_EXTERNAL);
        }
    } else
        rom_init(&mach->bios_rom,
                 BIOS_MACH8_VGA_ROM_PATH,
                 0xc0000, 0x8000, 0x7fff,
                 0, MEM_MAPPING_EXTERNAL);

    if ((dev->local & 0xff) >= 0x02) {
        svga_init(info, svga, mach, mach->memory << 10, /*default: 2MB for Mach32*/
                      mach_recalctimings,
                      mach_in, mach_out,
                      mach32_hwcursor_draw,
                      NULL);
        dev->vram_size   = mach->memory << 10;
        dev->vram        = calloc(dev->vram_size, 1);
        dev->changedvram = calloc((dev->vram_size >> 12) + 1, 1);
        dev->vram_mask   = dev->vram_size - 1;
        dev->hwcursor.cur_ysize = 64;
        mach->config1 = 0x20;
        if (mach->pci_bus && !mach->ramdac_type)
            svga->ramdac = device_add(&ati68860_ramdac_device);
        else
            svga->ramdac = device_add(&ati68875_ramdac_device);
        if (mach->vlb_bus) {
            video_inform(VIDEO_FLAG_TYPE_8514, &timing_mach32_vlb);
            if (!is486)
                mach->config1 |= 0x0a;
            else
                mach->config1 |= 0x0c;
            mach->config1 |= 0x0400;
            svga->clock_gen = device_add(&ati18811_0_device);
        } else if (mach->mca_bus) {
            video_inform(VIDEO_FLAG_TYPE_8514, &timing_mach32_mca);
            if (is286 && !is386)
                mach->config1 |= 0x04;
            else
                mach->config1 |= 0x06;
            mach->config1 |= 0x0400;
            svga->clock_gen = device_add(&ati18811_1_device);
        } else if (mach->pci_bus) {
            video_inform(VIDEO_FLAG_TYPE_8514, &timing_mach32_pci);
            mach->config1 |= 0x0e;
            if (mach->ramdac_type)
                mach->config1 |= 0x0400;
            else
                mach->config1 |= 0x0a00;
            mach->config2 |= 0x2000;
            svga->clock_gen = device_add(&ati18811_0_device);
        } else {
            video_inform(VIDEO_FLAG_TYPE_8514, &timing_gfxultra_isa);
            mach->config1 |= 0x0400;
            svga->clock_gen = device_add(&ati18811_0_device);
        }
        mem_mapping_add(&mach->mmio_linear_mapping, 0, 0, mach32_ap_readb, mach32_ap_readw, mach32_ap_readl, mach32_ap_writeb, mach32_ap_writew, mach32_ap_writel, NULL, MEM_MAPPING_EXTERNAL, mach);
        mem_mapping_disable(&mach->mmio_linear_mapping);
    } else {
        svga_init(info, svga, mach, (512 << 10), /*default: 512kB VGA for 28800-6 + 1MB for Mach8*/
                      mach_recalctimings,
                      mach_in, mach_out,
                      NULL,
                      NULL);
        dev->vram_size   = (1024 << 10);
        dev->vram        = calloc(dev->vram_size, 1);
        dev->changedvram = calloc((dev->vram_size >> 12) + 1, 1);
        dev->vram_mask   = dev->vram_size - 1;
        video_inform(VIDEO_FLAG_TYPE_8514, &timing_gfxultra_isa);
        mach->config1 = 0x01 | 0x02 | 0x20 | 0x08 | 0x80;
        mach->config2 = 0x02;
        svga->clock_gen = device_add(&ati18810_device);
    }
    dev->bpp            = 0;
    svga->getclock      = ics2494_getclock;

    dev->on[0] = 0;
    dev->on[1] = 0;
    dev->ext_pitch = 1024;
    dev->ext_crt_pitch = 0x80;
    dev->accel_bpp = 8;
    svga->force_old_addr = 1;
    svga->miscout = 1;
    svga->bpp = 8;
    svga->packed_chain4 = 1;
    dev->rowoffset = 0x80;
    io_sethandler(0x01ce, 2,  mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
    io_sethandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
    io_sethandler(0x02ea, 4,  mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
    mach_io_set(mach);

    if ((dev->local & 0xff) >= 0x02) {
        svga->decode_mask     = (4 << 20) - 1;
        mach->cursor_col_1    = 0xff;
        mach->ext_cur_col_1_r = 0xff;
        mach->ext_cur_col_1_g = 0xff;
        if (mach->vlb_bus)
            ati_eeprom_load(&mach->eeprom, "mach32_vlb.nvr", 1);
        else if (mach->mca_bus) {
            ati_eeprom_load(&mach->eeprom, "mach32_mca.nvr", 1);
            mem_mapping_disable(&mach->bios_rom.mapping);
            mem_mapping_disable(&mach->bios_rom2.mapping);
            mach->pos_regs[0] = 0x89;
            mach->pos_regs[1] = 0x80;
            mca_add(mach_mca_read, mach_mca_write, mach_mca_feedb, mach_mca_reset, mach);
        } else if (mach->pci_bus) {
            ati_eeprom_load(&mach->eeprom, "mach32_pci.nvr", 1);
            if (mach->has_bios) {
                mem_mapping_disable(&mach->bios_rom.mapping);
                pci_add_card(PCI_ADD_NORMAL, mach32_pci_read, mach32_pci_write, mach, &mach->pci_slot);
            } else
                pci_add_card(PCI_ADD_VIDEO, mach32_pci_read, mach32_pci_write, mach, &mach->pci_slot);

            mach->pci_regs[PCI_REG_COMMAND] = 0x83;
            mach->pci_regs[0x30]            = 0x00;
            mach->pci_regs[0x32]            = 0x0c;
            mach->pci_regs[0x33]            = 0x00;
        } else
            ati_eeprom_load(&mach->eeprom, "mach32.nvr", 1);
    } else
        ati_eeprom_load_mach8(&mach->eeprom, "mach8.nvr");

    return mach;
}

#ifdef ATI_8514_ULTRA
void
ati8514_init(svga_t *svga, void *ext8514, void *dev8514)
{
    mach_t *mach = (mach_t *) ext8514;
    ibm8514_t *dev = (ibm8514_t *) dev8514;

    dev->on[0] = 0;
    dev->on[1] = 0;
    dev->ext_pitch = 1024;
    dev->ext_crt_pitch = 0x80;
    dev->accel_bpp = 8;
    dev->rowoffset = 0x80;
    dev->hdisp = 1024;
    dev->vdisp = 768;

    io_sethandler(0x02ea, 4, ati8514_in, NULL, NULL, ati8514_out, NULL, NULL, svga);
    ati8514_io_set(svga);
    mach->mca_bus = !!(dev->type & DEVICE_MCA);

    if (mach->mca_bus)
        mach->config1 = 0x02 | 0x04 | 0x08 | 0x20 | 0x80;
    else
        mach->config1 = 0x02 | 0x08 | 0x20 | 0x80;

    mach->config2 = 0x01 | 0x02;
}
#endif

static int
mach8_vga_available(void)
{
    return rom_present(BIOS_MACH8_VGA_ROM_PATH);
}

static int
mach32_isa_available(void)
{
    return rom_present(BIOS_MACH32_ISA_ROM_PATH);
}

static int
mach32_vlb_available(void)
{
    return rom_present(BIOS_MACH32_VLB_ROM_PATH);
}

static int
mach32_mca_available(void)
{
    return rom_present(BIOS_MACH32_MCA_ROM_PATH);
}

static int
mach32_pci_available(void)
{
    return rom_present(BIOS_MACH32_PCI_ROM_PATH);
}

static void
mach_close(void *priv)
{
    mach_t    *mach = (mach_t *) priv;
    svga_t    *svga = &mach->svga;
    ibm8514_t *dev  = (ibm8514_t *) svga->dev8514;

    if (dev) {
        free(dev->vram);
        free(dev->changedvram);

        free(dev);
    }

    svga_close(svga);
    free(mach);
}

static void
mach_speed_changed(void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;

    svga_recalctimings(svga);
}

static void
mach_force_redraw(void *priv)
{
    mach_t *mach = (mach_t *) priv;
    svga_t *svga = &mach->svga;

    svga->fullchange = svga->monitor->mon_changeframecount;
}

// clang-format off
static const device_config_t mach32_config[] = {
    {
        .name = "memory",
        .description = "Memory size",
        .type = CONFIG_SELECTION,
        .default_int = 2048,
        .selection = {
            {
                .description = "512 KB",
                .value = 512
            },
            {
                .description = "1 MB",
                .value = 1024
            },
            {
                .description = "2 MB",
                .value = 2048
            },
            {
                .description = "4 MB",
                .value = 4096
            },
            {
                .description = ""
            }
        }
    },
    {
        .type = CONFIG_END
    }
};

// clang-format off
static const device_config_t mach32_pci_config[] = {
    {
        .name = "ramdac",
        .description = "RAMDAC type",
        .type = CONFIG_SELECTION,
        .default_int = 0,
        .selection = {
            {
                .description = "ATI 68860",
                .value = 0
            },
            {
                .description = "ATI 68875",
                .value = 1
            },
            {
                .description = ""
            }
        }
    },
    {
        .name = "memory",
        .description = "Memory size",
        .type = CONFIG_SELECTION,
        .default_int = 2048,
        .selection = {
            {
                .description = "512 KB",
                .value = 512
            },
            {
                .description = "1 MB",
                .value = 1024
            },
            {
                .description = "2 MB",
                .value = 2048
            },
            {
                .description = "4 MB",
                .value = 4096
            },
            {
                .description = ""
            }
        }
    },
    {
        .type = CONFIG_END
    }
};

const device_t mach8_vga_isa_device = {
    .name = "ATI Mach8 (ATI Graphics Ultra) (ISA)",
    .internal_name = "mach8_vga_isa",
    .flags = DEVICE_ISA,
    .local = 1,
    .init = mach8_init,
    .close = mach_close,
    .reset = NULL,
    { .available = mach8_vga_available },
    .speed_changed = mach_speed_changed,
    .force_redraw = mach_force_redraw,
    .config = NULL
};

const device_t mach32_isa_device = {
    .name = "ATI Mach32 (ISA)",
    .internal_name = "mach32_isa",
    .flags = DEVICE_ISA,
    .local = 2,
    .init = mach8_init,
    .close = mach_close,
    .reset = NULL,
    { .available = mach32_isa_available },
    .speed_changed = mach_speed_changed,
    .force_redraw = mach_force_redraw,
    .config = mach32_config
};

const device_t mach32_vlb_device = {
    .name = "ATI Mach32 (VLB)",
    .internal_name = "mach32_vlb",
    .flags = DEVICE_VLB,
    .local = 2,
    .init = mach8_init,
    .close = mach_close,
    .reset = NULL,
    { .available = mach32_vlb_available },
    .speed_changed = mach_speed_changed,
    .force_redraw = mach_force_redraw,
    .config = mach32_config
};

const device_t mach32_mca_device = {
    .name = "ATI Mach32 (MCA)",
    .internal_name = "mach32_mca",
    .flags = DEVICE_MCA,
    .local = 2,
    .init = mach8_init,
    .close = mach_close,
    .reset = NULL,
    { .available = mach32_mca_available },
    .speed_changed = mach_speed_changed,
    .force_redraw = mach_force_redraw,
    .config = mach32_config
};

const device_t mach32_pci_device = {
    .name = "ATI Mach32 (PCI)",
    .internal_name = "mach32_pci",
    .flags = DEVICE_PCI,
    .local = 2,
    .init = mach8_init,
    .close = mach_close,
    .reset = NULL,
    { .available = mach32_pci_available },
    .speed_changed = mach_speed_changed,
    .force_redraw = mach_force_redraw,
    .config = mach32_pci_config
};

const device_t mach32_onboard_pci_device = {
    .name = "ATI Mach32 (PCI) On-Board",
    .internal_name = "mach32_pci_onboard",
    .flags = DEVICE_PCI,
    .local = 2 | 0x100,
    .init = mach8_init,
    .close = mach_close,
    .reset = NULL,
    { .available = NULL },
    .speed_changed = mach_speed_changed,
    .force_redraw = mach_force_redraw,
    .config = mach32_pci_config
};

