Files
86Box/src/video/vid_ati_mach8.c
TC1995 f240e8cb0c Video changes:
1. The passthrough from VGA to 8514/A and/or 8514/A to VGA no longer relies on hackish places where to switch from/to, instead, relying on port 0x3c3 of VGA doing so (though the Mach8/32 still needs some places where to manually switch from/to, mainly the MCA one when configuring the EEPROM).
2. Implemented the MCA behalf of the Mach32 and its corresponding reset function.
3. Properly implemented (more or less) true color, including 24-bit BGR rendering
4. Other fixes such as color patterns and mono patterns being more correct than before in various operating systems and in 24-bit true color.
5. Implemented the onboard Mach32 video of the IBM PS/ValuePoint P60 machine.
6. Made the onboard internal video detect when it's 8514/A compatible or not (CGA/EGA/MDA/VGA/etc.). If the former is selected, then the video monitor flag is used instead (for QT).
7. The TGUI9400 and 9440, if on VLB, now detect the right amount of memory if on 2MB.
8. Initial implementation of the ATI 68875 ramdac used by the Mach32 and made the ATI 68860 8514/A aware when selected with the Mach32AX PCI.
9. Separated the 8514/A ramdac ports from the VGA ramdac ports, allowing seamless transition from/to 8514/A/VGA.
10. Fixed a hdisp problem in the ET4000/W32 cards, where it was doubling the horizontal display in 15bpp+ graphics mode.
11. Removed the 0x3da/0x3ba port hack that was on the Mach8/32 code, relying on the (S)VGA core instead.
12. Reworked and simplified the TGUI9440 pitch register based on logging due to no documentation at all.
2023-08-12 00:00:46 +02:00

5667 lines
245 KiB
C

/*
* 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-2023 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_svga.h>
#include <86box/vid_svga_render.h>
#include <86box/vid_ati_eeprom.h>
#define BIOS_MACH8_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"
typedef struct mach_t {
ati_eeprom_t eeprom;
svga_t svga;
rom_t bios_rom;
rom_t bios_rom2;
mem_mapping_t mmio_linear_mapping;
int mca_bus;
int pci_bus;
int vlb_bus;
int has_bios;
uint8_t regs[256];
uint8_t pci_regs[256];
uint8_t int_line;
uint8_t pci_slot;
uint8_t irq_state;
int index;
int ramdac_type;
int old_mode;
uint32_t memory;
uint16_t config1;
uint16_t config2;
uint8_t pos_regs[8];
uint8_t pci_cntl_reg;
uint8_t cursor_col_0;
uint8_t cursor_col_1;
uint8_t ext_cur_col_0_r;
uint8_t ext_cur_col_1_r;
uint8_t ext_cur_col_0_g;
uint8_t ext_cur_col_1_g;
uint16_t cursor_col_0_rg;
uint16_t cursor_col_1_rg;
uint16_t cursor_col_b;
uint16_t cursor_offset_lo;
uint16_t cursor_offset_hi;
uint16_t cursor_offset_hi_reg;
uint16_t cursor_vh_offset;
uint16_t cursor_x;
uint16_t cursor_y;
uint16_t misc;
uint16_t memory_aperture;
uint16_t local_cntl;
uint32_t linear_base;
uint8_t ap_size;
uint8_t bank_w;
uint8_t bank_r;
uint16_t shadow_set;
struct {
uint8_t line_idx;
int16_t line_array[6];
uint8_t patt_idx;
uint8_t patt_len;
uint8_t pix_trans[2];
uint8_t eeprom_control;
uint16_t dest_x_end;
uint16_t dest_x_start;
uint16_t dest_y_end;
uint16_t src_x_end;
uint16_t src_x_start;
uint16_t src_x;
uint16_t src_y;
int16_t bres_count;
uint16_t clock_sel;
uint16_t crt_offset_lo;
uint16_t crt_offset_hi;
uint16_t dest_cmp_fn;
uint16_t dp_config;
uint16_t ext_ge_config;
uint16_t ge_offset_lo;
uint16_t ge_offset_hi;
uint16_t linedraw_opt;
uint16_t max_waitstates;
uint8_t patt_data_idx;
uint8_t patt_data[0x18];
uint16_t scan_to_x;
uint16_t scratch0;
uint16_t scratch1;
uint16_t test;
uint16_t pattern;
uint8_t test2[2];
uint8_t test3[2];
int src_y_dir;
int cmd_type;
int block_write_mono_pattern_enable;
int mono_pattern_enable;
int16_t cx_end_line;
int16_t cy_end_line;
int16_t cx;
int16_t cx_end;
int16_t cy_end;
int16_t dx;
int16_t dx_end;
int16_t dy_end;
int16_t dx_start;
int16_t dy_start;
int16_t cy;
int16_t sx_start;
int16_t sx_end;
int16_t sx;
int16_t x_count;
int16_t xx_count;
int16_t xxx_count;
int16_t sy;
int16_t y_count;
int16_t err;
int16_t width;
int16_t src_width;
int16_t height;
int poly_src;
int temp_cnt;
int stepx;
int stepy;
int src_stepx;
uint8_t color_pattern[16];
uint8_t color_pattern_full[32];
uint16_t color_pattern_word[8];
int mono_pattern[8][8];
uint32_t ge_offset;
uint32_t crt_offset;
uint32_t patt_len_reg;
int poly_fill;
uint16_t dst_clr_cmp_mask;
int clip_overrun;
int color_pattern_idx;
} accel;
atomic_int force_busy;
} mach_t;
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);
static void mach32_updatemapping(mach_t *mach);
#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 = dev->vram[((dev->accel.dest) + (cx) + (n)) & dev->vram_mask]; \
temp |= (dev->vram[((dev->accel.dest) + (cx) + (n + 1)) & dev->vram_mask] << 8); \
} else { \
temp = vram_w[((dev->accel.dest) + (cx) + (n)) & (dev->vram_mask >> 1)]; \
} \
} else if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) { \
if (!dev->bpp) { \
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); \
} else { \
temp = vram_w[((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & (dev->vram_mask >> 1)]; \
} \
}
#define READ(addr, dat) \
if (!dev->bpp) \
dat = dev->vram[(addr) & (dev->vram_mask)]; \
else \
dat = vram_w[(addr) & (dev->vram_mask >> 1)];
#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) { \
dev->vram[((addr)) & (dev->vram_mask)] = dat; \
dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \
} else { \
vram_w[((addr)) & (dev->vram_mask >> 1)] = dat; \
dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = 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)
{
svga_t *svga = &mach->svga;
int compare_mode;
int 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;
mach->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16));
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 ((svga->bpp == 8) || (svga->bpp == 15) || (svga->bpp == 16) || (svga->bpp == 24)) {
if (svga->bpp == 24)
mach_log("24BPP: CMDType=%d, cwh(%d,%d,%d,%d), dpconfig=%04x\n", cmd_type, clip_l, clip_r, clip_t, clip_b, mach->accel.dp_config);
else
mach_log("BPP=%d, CMDType = %d, offs=%08x, DPCONFIG = %04x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, dstx = %d, dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monpattern = %x.\n", svga->bpp, cmd_type, mach->accel.ge_offset, mach->accel.dp_config, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, 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)) {
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)) {
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 (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 (dev->accel.sx < mach->accel.width) {
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)) {
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)) {
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 (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 (dev->accel.sx < mach->accel.width) {
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++;
}
}
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;
/*Destination Width*/
if (mach->accel.dest_x_start != dev->accel.dx)
mach->accel.dest_x_start = dev->accel.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 ((svga->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 ((svga->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 ((svga->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
mach_log("BitBLT=%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 << 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 ((svga->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) {
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 ((svga->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) {
READ(dev->accel.src + (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.dp_config & 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 ((svga->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 ((svga->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)) {
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 ((svga->bpp == 8) || ((svga->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 ((svga->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 ((svga->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 ((svga->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) {
mach->accel.poly_fill = 0;
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++;
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) && (svga->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 ((svga->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 == 2) || (frgd_sel == 3) || (bkgd_sel == 2) || (bkgd_sel == 3))
return;
if ((mono_src == 1) && (frgd_sel == 5) && (svga->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).\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);
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;
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.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.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 ((svga->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 ((svga->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 (svga->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 (svga->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 ((svga->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 ((svga->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, UNUSED(uint16_t port), uint16_t val, uint16_t len)
{
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) && (dev->local >= 2))
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;
ibm8514_t *dev = &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 >= 2) {
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 >= 2) {
mach->bank_r |= ((mach->regs[0xae] & 0x0c) << 2);
mach->bank_w |= ((mach->regs[0xae] & 3) << 4);
}
if (ibm8514_on)
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 >= 2) {
mach->bank_w |= ((mach->regs[0xae] & 3) << 4);
}
mach->bank_r = mach->bank_w;
if (ibm8514_on)
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);
}
break;
case 0xb3:
ati_eeprom_write(&mach->eeprom, val & 8, val & 2, val & 1);
break;
case 0xb6:
if ((old ^ val) & 0x11)
svga_recalctimings(svga);
break;
case 0xb8:
if (dev->local >= 2) {
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 >= 2) {
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 >= 2) {
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 0x3CF:
if (svga->gdcaddr == 6) {
uint8_t old_val = svga->gdcreg[6];
svga->gdcreg[6] = val;
if ((svga->gdcreg[6] & 0xc) != (old_val & 0xc))
mach32_updatemapping(mach);
return;
}
break;
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;
case 0x46e8:
io_removehandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
mem_mapping_disable(&svga->mapping);
mem_mapping_disable(&mach->mmio_linear_mapping);
if (val & 8) {
io_sethandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
mem_mapping_enable(&svga->mapping);
mach32_updatemapping(mach);
}
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;
ibm8514_t *dev = &svga->dev8514;
uint8_t temp = 0xff;
uint8_t rs2;
uint8_t rs3;
if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1))
addr ^= 0x60;
switch (addr) {
case 0x1ce:
temp = mach->index;
break;
case 0x1cf:
switch (mach->index) {
case 0xa8:
temp = (svga->vc >> 8) & 3;
break;
case 0xa9:
temp = svga->vc & 0xff;
break;
case 0xb0:
temp = mach->regs[0xb0] | 0x80;
if (dev->local >= 2) { /*Mach32 VGA 1MB memory*/
temp |= 0x08;
temp &= ~0x10;
} else { /*ATI 28800 VGA 512kB memory*/
temp &= ~0x08;
temp |= 0x10;
}
break;
case 0xb7:
temp = mach->regs[0xb7] & ~8;
if (ati_eeprom_read(&mach->eeprom))
temp |= 8;
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 >= 2) {
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 0x3C6:
case 0x3C7:
case 0x3C8:
case 0x3C9:
rs2 = !!(mach->regs[0xa0] & 0x20);
rs3 = !!(mach->regs[0xa0] & 0x40);
if (dev->local >= 2) {
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;
}
static void
mach_recalctimings(svga_t *svga)
{
mach_t *mach = (mach_t *) svga->priv;
ibm8514_t *dev = &svga->dev8514;
int clock_sel;
clock_sel = ((svga->miscout >> 2) & 3) | ((mach->regs[0xbe] & 0x10) >> 1) | ((mach->regs[0xb9] & 2) << 1);
if (dev->local >= 2) {
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[0xa7] & 0x80)
svga->clock *= 3;
if (mach->regs[0xb6] & 0x10) {
svga->hdisp <<= 1;
svga->htotal <<= 1;
svga->rowoffset <<= 1;
svga->gdcreg[5] &= ~0x40;
}
if (mach->regs[0xb0] & 0x20) {
svga->gdcreg[5] |= 0x40;
}
if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) {
if (((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1))) {
mach_log("VGA ON.\n");
svga->clock = (uint64_t)((cpuclock * svga->getclock(clock_sel, svga->clock_gen)) / (double) (1ull << 32));
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) {
case 8:
svga->map8 = svga->pallook;
if (svga->lowres)
svga->render = svga_render_8bpp_lowres;
else {
svga->render = svga_render_8bpp_highres;
svga->ma_latch <<= 1;
svga->rowoffset <<= 1;
}
break;
}
break;
}
}
}
if (dev->local >= 2) {
if (ibm8514_on) {
svga->clock = (uint64_t)((cpuclock * svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen)) / (double) (1ull << 32));
dev->h_disp = (dev->hdisp + 1) << 3;
dev->h_total = (dev->htotal + 1);
dev->v_total = (dev->vtotal + 1);
dev->v_syncstart = (dev->vsyncstart + 1);
dev->dispend = ((dev->vdisp >> 1) + 1);
dev->rowcount = !!(dev->disp_cntl & 0x08);
if (dev->dispend == 766)
dev->dispend += 2;
if (dev->dispend == 598)
dev->dispend += 2;
if (dev->accel.advfunc_cntl & 4) {
if (mach->shadow_set & 2) {
if (dev->h_disp == 8) {
dev->h_disp = 1024;
dev->dispend = 768;
dev->v_total = 1536;
dev->v_syncstart = 1536;
}
}
mach_log("1024x768 clock mode, hdisp = %d, htotal = %d, vtotal = %d, vsyncstart = %d, interlace = %02x\n", dev->h_disp, dev->h_total, dev->v_total, dev->v_syncstart, dev->interlace);
} else {
if (mach->shadow_set & 1) {
if ((dev->h_disp == 1024) && !dev->internal_pitch) {
dev->h_disp = 640;
dev->dispend = 480;
}
}
}
if (dev->interlace) {
dev->dispend >>= 1;
dev->v_syncstart >>= 2;
dev->v_total >>= 2;
} else {
dev->v_syncstart >>= 1;
dev->v_total >>= 1;
}
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)
svga->bpp = 16;
else
svga->bpp = 15;
} else if ((mach->accel.ext_ge_config & 0x30) == 0x30) {
if (mach->accel.ext_ge_config & 0x200)
svga->bpp = 32;
else
svga->bpp = 24;
} else
svga->bpp = 8;
mach_log("hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x.\n", dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0);
switch (svga->bpp) {
case 8:
svga->render = ibm8514_render_8bpp;
break;
case 15:
svga->render = ibm8514_render_15bpp;
break;
case 16:
svga->render = ibm8514_render_16bpp;
break;
case 24:
if (mach->accel.ext_ge_config & 0x400)
svga->render = ibm8514_render_BGR;
else
svga->render = ibm8514_render_24bpp;
break;
case 32:
if (mach->accel.ext_ge_config & 0x400)
svga->render = ibm8514_render_ABGR8888;
else
svga->render = ibm8514_render_RGBA8888;
break;
}
}
switch (mach->regs[0xb8] & 0xc0) {
case 0x40:
svga->clock *= 2;
break;
case 0x80:
svga->clock *= 3;
break;
case 0xc0:
svga->clock *= 4;
break;
}
}
} else {
if (ibm8514_on) {
svga->clock = (uint64_t)((cpuclock * svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen)) / (double) (1ull << 32));
dev->h_disp = (dev->hdisp + 1) << 3;
dev->h_total = (dev->htotal + 1);
dev->v_total = (dev->vtotal + 1);
dev->v_syncstart = (dev->vsyncstart + 1);
dev->rowcount = !!(dev->disp_cntl & 0x08);
dev->dispend = ((dev->vdisp >> 1) + 1);
if (dev->dispend == 766)
dev->dispend += 2;
if (dev->dispend == 598)
dev->dispend += 2;
if (dev->accel.advfunc_cntl & 4) {
if (mach->shadow_set & 2) {
if (dev->h_disp == 8) {
dev->h_disp = 1024;
dev->dispend = 768;
dev->v_total = 1536;
dev->v_syncstart = 1536;
}
}
} else {
if (mach->shadow_set & 1) {
if ((dev->h_disp == 1024) && !dev->internal_pitch) {
dev->h_disp = 640;
dev->dispend = 480;
}
}
}
if (dev->interlace) {
dev->dispend >>= 1;
dev->v_syncstart >>= 2;
dev->v_total >>= 2;
} else {
dev->v_syncstart >>= 1;
dev->v_total >>= 1;
}
dev->pitch = dev->ext_pitch;
dev->rowoffset = dev->ext_crt_pitch;
mach_log("hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x.\n", dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0);
svga->map8 = dev->pallook;
svga->render = ibm8514_render_8bpp;
if (mach->regs[0xb8] & 0x40)
svga->clock *= 2;
}
}
}
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;
switch (port) {
case 0x82e8:
case 0xc2e8:
if (len == 1) {
dev->accel.cur_y = (dev->accel.cur_y & 0x700) | val;
} else {
dev->accel.cur_y = val & 0x7ff;
}
break;
case 0x82e9:
case 0xc2e9:
if (len == 1) {
dev->accel.cur_y = (dev->accel.cur_y & 0xff) | ((val & 0x07) << 8);
}
break;
case 0x86e8:
case 0xc6e8:
if (len == 1) {
dev->accel.cur_x = (dev->accel.cur_x & 0x700) | val;
} else {
dev->accel.cur_x = val & 0x7ff;
}
break;
case 0x86e9:
case 0xc6e9:
if (len == 1) {
dev->accel.cur_x = (dev->accel.cur_x & 0xff) | ((val & 0x07) << 8);
}
break;
case 0x8ae8:
case 0xcae8:
if (len == 1)
dev->accel.desty_axstp = (dev->accel.desty_axstp & 0x3f00) | val;
else {
mach->accel.src_y = val;
dev->accel.desty_axstp = val & 0x3fff;
if (val & 0x2000)
dev->accel.desty_axstp |= ~0x1fff;
}
break;
case 0x8ae9:
case 0xcae9:
if (len == 1) {
dev->accel.desty_axstp = (dev->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8);
if (val & 0x20)
dev->accel.desty_axstp |= ~0x1fff;
}
break;
case 0x8ee8:
case 0xcee8:
if (len == 1)
dev->accel.destx_distp = (dev->accel.destx_distp & 0x3f00) | val;
else {
mach->accel.src_x = val;
dev->accel.destx_distp = val & 0x3fff;
if (val & 0x2000)
dev->accel.destx_distp |= ~0x1fff;
}
break;
case 0x8ee9:
case 0xcee9:
if (len == 1) {
dev->accel.destx_distp = (dev->accel.destx_distp & 0xff) | ((val & 0x3f) << 8);
if (val & 0x20)
dev->accel.destx_distp |= ~0x1fff;
}
break;
case 0x92e8:
if (len != 1)
dev->test = val;
fallthrough;
case 0xd2e8:
mach_log("92E8 = %04x\n", val);
if (len == 1)
dev->accel.err_term = (dev->accel.err_term & 0x3f00) | val;
else {
dev->accel.err_term = val & 0x3fff;
if (val & 0x2000)
dev->accel.err_term |= ~0x1fff;
}
break;
case 0x92e9:
case 0xd2e9:
if (len == 1) {
dev->accel.err_term = (dev->accel.err_term & 0xff) | ((val & 0x3f) << 8);
if (val & 0x20)
dev->accel.err_term |= ~0x1fff;
}
break;
case 0x96e8:
case 0xd6e8:
if (len == 1)
dev->accel.maj_axis_pcnt = (dev->accel.maj_axis_pcnt & 0x0700) | val;
else {
mach->accel.test = val & 0x1fff;
dev->accel.maj_axis_pcnt = val & 0x07ff;
}
break;
case 0x96e9:
case 0xd6e9:
if (len == 1) {
dev->accel.maj_axis_pcnt = (dev->accel.maj_axis_pcnt & 0xff) | ((val & 0x07) << 8);
}
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.\n", val);
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);
svga_recalctimings(svga);
}
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, port, val, len);
} 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, port, val, len);
} 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 0xeae8:
if (len == 1)
dev->accel.wrt_mask = (dev->accel.wrt_mask & 0x00ff) | val;
else
dev->accel.wrt_mask = val;
break;
case 0xaae9:
case 0xeae9:
if (len == 1)
dev->accel.wrt_mask = (dev->accel.wrt_mask & 0xff00) | (val << 8);
break;
case 0xaee8:
case 0xeee8:
if (len == 1)
dev->accel.rd_mask = (dev->accel.rd_mask & 0x00ff) | val;
else
dev->accel.rd_mask = val;
break;
case 0xaee9:
case 0xeee9:
if (len == 1)
dev->accel.rd_mask = (dev->accel.rd_mask & 0xff00) | (val << 8);
break;
case 0xb2e8:
case 0xf2e8:
if (len == 1)
dev->accel.color_cmp = (dev->accel.color_cmp & 0x00ff) | val;
else
dev->accel.color_cmp = val;
break;
case 0xb2e9:
case 0xf2e9:
if (len == 1)
dev->accel.color_cmp = (dev->accel.color_cmp & 0xff00) | (val << 8);
break;
case 0xb6e8:
case 0xf6e8:
dev->accel.bkgd_mix = val & 0xff;
break;
case 0xbae8:
case 0xfae8:
dev->accel.frgd_mix = val & 0xff;
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], svga->bpp, dev->pitch);
if ((dev->accel.multifunc_cntl >> 12) == 5) {
if (!dev->ext_crt_pitch || ((dev->local < 2)))
dev->ext_crt_pitch = 128;
svga_recalctimings(svga);
}
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->ext_crt_pitch || ((dev->local < 2)))
dev->ext_crt_pitch = 128;
svga_recalctimings(svga);
}
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 ((svga->bpp == 24) && (mach->accel.patt_len == 0x17) && (frgd_sel == 5)) {
mach->accel.patt_data_idx += 2;
dev->accel.y1 = 1;
} else {
if (svga->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 ((svga->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("96EE 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 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;
}
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:
mach_log("AEEE write val = %04x.\n", val);
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:
mach_log("CAEE write val = %04x.\n", val);
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 {
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:
if (mach->accel.dp_config == 0x2231 || mach->accel.dp_config == 0x2211)
mach_log("FEEE val = %d, lineidx = %d, DPCONFIG = %04x, CPUCX = %04x.\n", val, mach->accel.line_idx, mach->accel.dp_config, CX);
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(uint16_t port, uint8_t val, mach_t *mach)
{
svga_t *svga = &mach->svga;
ibm8514_t *dev = &svga->dev8514;
mach_log("Port accel out = %04x, val = %04x.\n", port, val);
switch (port) {
case 0x2e8:
case 0x2e9:
WRITE8(port, dev->htotal, val);
svga_recalctimings(svga);
break;
case 0x6e8:
dev->hdisp = val;
mach_log("ATI 8514/A: H_DISP write 06E8 = %d\n", dev->hdisp + 1);
svga_recalctimings(svga);
break;
case 0xae8:
mach_log("ATI 8514/A: H_SYNC_STRT write 0AE8 = %d\n", val + 1);
svga_recalctimings(svga);
break;
case 0xee8:
mach_log("ATI 8514/A: H_SYNC_WID write 0EE8 = %d\n", val + 1);
svga_recalctimings(svga);
break;
case 0x12e8:
case 0x12e9:
WRITE8(port, dev->vtotal, val);
dev->vtotal &= 0x1fff;
svga_recalctimings(svga);
break;
case 0x16e8:
case 0x16e9:
WRITE8(port, dev->vdisp, val);
dev->vdisp &= 0x1fff;
svga_recalctimings(svga);
break;
case 0x1ae8:
case 0x1ae9:
WRITE8(port, dev->vsyncstart, val);
dev->vsyncstart &= 0x1fff;
svga_recalctimings(svga);
break;
case 0x1ee8:
dev->vsyncwidth = val;
mach_log("ATI 8514/A: V_SYNC_WID write 1EE8 = %02x\n", val);
svga_recalctimings(svga);
break;
case 0x22e8:
dev->disp_cntl = val & 0x7e;
dev->interlace = !!(val & 0x10);
mach_log("ATI 8514/A: DISP_CNTL write 22E8 = %02x, SCANMODULOS = %d\n", dev->disp_cntl, dev->scanmodulos);
svga_recalctimings(svga);
break;
case 0x42e8:
dev->subsys_stat &= ~val;
break;
case 0x42e9:
dev->subsys_cntl = val;
break;
case 0x4ae8:
if (!val)
break;
if (!dev->ext_crt_pitch || ((dev->local < 2)))
dev->ext_crt_pitch = 128;
dev->accel.advfunc_cntl = val & 0x0f;
ibm8514_on = val & 0x01;
if (!ibm8514_on && mach->old_mode) {
ibm8514_on = 1;
mach->old_mode = 0;
}
vga_on = !ibm8514_on;
mach_log("ATI 8514/A: VGA ON (0x4ae8) = %i, val = %02x, 8514 = %i, gdcreg6 = %02x\n", vga_on, val, ibm8514_on, svga->gdcreg[6] & 0x0c);
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, val);
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);
}
break;
case 0x26ee:
mach_log("CRT Pitch = %d, original val = %d.\n", val << 3, val);
dev->ext_crt_pitch = val;
dev->internal_pitch = val;
if (svga->bpp > 8) {
if (svga->bpp == 24)
dev->ext_crt_pitch *= 3;
else if (svga->bpp == 32)
dev->ext_crt_pitch <<= 2;
else
dev->ext_crt_pitch <<= 1;
}
if (dev->local >= 2) {
if (!ibm8514_on) {
ibm8514_on = 1;
svga->adv_flags |= FLAG_ATI;
}
}
svga_recalctimings(svga);
break;
case 0x32ee:
case 0x32ef:
WRITE8(port, mach->local_cntl, val);
mach32_updatemapping(mach);
break;
case 0x36ee:
case 0x36ef:
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:
mach->accel.test2[0] = val;
break;
case 0x42ef:
mach->accel.test2[1] = val;
break;
case 0x46ee:
mach->accel.test3[0] = val;
break;
case 0x46ef:
mach->accel.test3[1] = val;
break;
case 0x4aee:
case 0x4aef:
if (!(port & 1))
mach->old_mode = mach->accel.clock_sel & 0x01;
WRITE8(port, mach->accel.clock_sel, val);
ibm8514_on = mach->accel.clock_sel & 0x01;
vga_on = !ibm8514_on;
if (dev->local >= 2) {
if (ibm8514_on)
svga->adv_flags |= FLAG_ATI;
else
svga->adv_flags &= ~FLAG_ATI;
}
mach_log("ATI 8514/A: VGA ON (0x4aee) = %i, Ext = %i, val = %04x\n", vga_on, ibm8514_on, mach->accel.clock_sel);
svga_recalctimings(svga);
break;
case 0x52ee:
case 0x52ef:
WRITE8(port, mach->accel.scratch0, val);
break;
case 0x56ee:
case 0x56ef:
WRITE8(port, mach->accel.scratch1, val);
break;
case 0x5aee:
case 0x5aef:
WRITE8(port, mach->shadow_set, val);
svga_recalctimings(svga);
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);
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);
dev->accel.ge_offset = mach->accel.ge_offset_lo;
break;
case 0x72ee:
case 0x72ef:
WRITE8(port, mach->accel.ge_offset_hi, val);
dev->accel.ge_offset = mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16);
break;
case 0x76ee:
mach_log("76EE write val=%d shifted, normal=%d.\n", val << 3, val);
dev->ext_pitch = val << 3;
mach->old_mode = 1;
svga_recalctimings(svga);
break;
case 0x7aee:
case 0x7aef:
WRITE8(port, mach->accel.ext_ge_config, val);
if (dev->local >= 2) {
dev->ext_crt_pitch = dev->internal_pitch;
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;
}
svga_set_ramdac_type(svga, !!(mach->accel.ext_ge_config & 0x4000));
mach_log("Passthrough override = %04x.\n", val & 0x1000);
svga_recalctimings(svga);
}
mach_log("7AEE write val = %04x.\n", mach->accel.ext_ge_config);
break;
case 0x7eee:
case 0x7eef:
WRITE8(port, mach->accel.eeprom_control, val);
ati_eeprom_write(&mach->eeprom, mach->accel.eeprom_control & 4, mach->accel.eeprom_control & 2, mach->accel.eeprom_control & 1);
mach_log("[%04X]: 7EEE+%d VGA ON = %d, Ext = %i, val = %04x, pagesel = %04x.\n", CS, port & 1, vga_on, ibm8514_on, mach->accel.eeprom_control & 0x10ff, (mach->accel.eeprom_control & 0xf0) << 7);
svga_recalctimings(svga);
break;
default:
break;
}
}
static uint16_t
mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, int len)
{
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 0xc2e8:
if (len != 1) {
temp = dev->accel.cur_y;
}
break;
case 0x86e8:
case 0xc6e8:
if (len != 1) {
temp = dev->accel.cur_x;
}
break;
case 0x92e8:
if (len != 1) {
temp = dev->test;
}
break;
case 0x96e8:
if (len != 1) {
temp = dev->accel.maj_axis_pcnt;
}
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, port, temp, len);
}
}
} 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;
}
}
}
}
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;
}
}
break;
case 0x82ee:
temp = mach->accel.patt_data_idx;
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 = dev->accel.maj_axis_pcnt & 0xff;
} else {
temp = dev->accel.maj_axis_pcnt;
if ((mach->accel.test == 0x1555) || (mach->accel.test == 0x0aaa))
temp = mach->accel.test;
}
break;
case 0x96ef:
if (len == 1)
temp = dev->accel.maj_axis_pcnt >> 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->hdisp;
else {
temp = dev->hdisp & 0xff;
temp |= (dev->htotal << 8);
mach_log("HDISP read=%d, HTOTAL read=%d.\n", temp & 0xff, temp >> 8);
}
break;
case 0xb2ef:
if (len == 1) {
temp = dev->htotal;
}
break;
case 0xc2ee:
if (len == 1)
temp = dev->vtotal & 0xff;
else {
temp = dev->vtotal;
mach_log("VTOTAL read=%d.\n", temp);
}
break;
case 0xc2ef:
if (len == 1)
temp = dev->vtotal >> 8;
break;
case 0xc6ee:
if (len == 1)
temp = dev->vdisp & 0xff;
else {
temp = dev->vdisp;
mach_log("VDISP read=%d.\n", temp);
}
break;
case 0xc6ef:
if (len == 1)
temp = dev->vdisp >> 8;
break;
case 0xcaee:
if (len == 1)
temp = dev->vsyncstart & 0xff;
else
temp = dev->vsyncstart;
break;
case 0xcaef:
if (len == 1)
temp = dev->vsyncstart >> 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 >= 2)
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 >= 2)
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 (mach->pci_bus)
temp = 0x0017;
else
temp = 0x22f7;
} else {
if (mach->pci_bus)
temp = 0x17;
else
temp = 0xf7;
}
break;
case 0xfaef:
if (len == 1) {
if (mach->pci_bus)
temp = 0x00;
else
temp = 0x22;
}
break;
}
mach_log("Port FIFO IN=%04x, temp=%04x, len=%d.\n", port, temp, len);
return temp;
}
static uint8_t
mach_accel_in(uint16_t port, mach_t *mach)
{
svga_t *svga = &mach->svga;
ibm8514_t *dev = &svga->dev8514;
uint8_t temp = 0;
int vpos = 0;
int vblankend = svga->vblankstart + svga->crtc[0x16];
switch (port) {
case 0x2e8:
vpos = dev->vc & 0x7ff;
if (vblankend > dev->v_total) {
vblankend -= dev->v_total;
if (vpos >= svga->vblankstart || vpos <= vblankend)
temp |= 2;
} else {
if (vpos >= svga->vblankstart && vpos <= vblankend)
temp |= 2;
}
break;
case 0x6e8:
temp = dev->hdisp;
break;
case 0x22e8:
temp = dev->disp_cntl;
break;
case 0x26e8:
case 0x26e9:
READ8(port, dev->htotal);
break;
case 0x2ee8:
temp = dev->subsys_cntl;
break;
case 0x2ee9:
temp = 0xff;
break;
case 0x42e8:
case 0x42e9:
vpos = dev->vc & 0x7ff;
if (vblankend > dev->v_total) {
vblankend -= dev->v_total;
if (vpos >= svga->vblankstart || vpos <= vblankend)
dev->subsys_stat |= 1;
} else {
if (vpos >= svga->vblankstart && vpos <= vblankend)
dev->subsys_stat |= 1;
}
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;
}
break;
case 0x4ae8:
temp = dev->accel.advfunc_cntl;
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 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)) {
switch (mach->memory) {
case 512:
temp &= ~0x0c;
break;
case 1024:
temp |= 0x04;
break;
case 2048:
temp |= 0x08;
break;
case 4096:
temp |= 0x0c;
break;
}
}
break;
case 0x42ee:
temp = mach->accel.test2[0];
break;
case 0x42ef:
temp = mach->accel.test2[1];
break;
case 0x46ee:
temp = mach->accel.test3[0];
break;
case 0x46ef:
temp = mach->accel.test3[1];
break;
case 0x4aee:
case 0x4aef:
READ8(port, mach->accel.clock_sel);
break;
case 0x52ee:
case 0x52ef:
READ8(port, mach->accel.scratch0);
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);
if ((port & 1) && ibm8514_on) {
ibm8514_on = 0;
vga_on = 1;
}
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, dev->accel.clip_left);
break;
case 0x76ee:
case 0x76ef:
READ8(port, dev->accel.clip_top);
break;
case 0x7aee:
case 0x7aef:
READ8(port, dev->accel.multifunc[4]);
break;
case 0x7eee:
case 0x7eef:
READ8(port, dev->accel.multifunc[3]);
break;
default:
break;
}
mach_log("Port accel in = %04x, temp = %04x.\n", port, temp);
return temp;
}
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, &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, &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, &svga->dev8514, port, val & 0xffff, 2);
mach_accel_out_fifo(mach, svga, &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);
}
}
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, &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, &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, &svga->dev8514, port, 2);
temp = (mach_accel_in_fifo(mach, svga, &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 void
mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv)
{
mach_t *mach = (mach_t *) priv;
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.\n", addr);
svga_write_linear(addr, val, &mach->svga);
}
}
static void
mach32_ap_writew(uint32_t addr, uint16_t val, void *priv)
{
mach_t *mach = (mach_t *) priv;
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.\n", addr);
svga_writew_linear(addr, val, &mach->svga);
}
}
static void
mach32_ap_writel(uint32_t addr, uint32_t val, void *priv)
{
mach_t *mach = (mach_t *) priv;
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, mode=%d, rop=%02x.\n", addr, val, mach->svga.writemode, mach->svga.gdcreg[3] & 0x18);
svga_writel_linear(addr, val, &mach->svga);
}
}
static uint8_t
mach32_ap_readb(uint32_t addr, void *priv)
{
mach_t *mach = (mach_t *) priv;
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
temp = svga_read_linear(addr, &mach->svga);
return temp;
}
static uint16_t
mach32_ap_readw(uint32_t addr, void *priv)
{
mach_t *mach = (mach_t *) priv;
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
temp = svga_readw_linear(addr, &mach->svga);
return temp;
}
static uint32_t
mach32_ap_readl(uint32_t addr, void *priv)
{
mach_t *mach = (mach_t *) priv;
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
temp = svga_readl_linear(addr, &mach->svga);
return temp;
}
static void
mach32_updatemapping(mach_t *mach)
{
svga_t *svga = &mach->svga;
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);
}
}
static void
mach32_hwcursor_draw(svga_t *svga, int displine)
{
mach_t *mach = (mach_t *) svga->priv;
ibm8514_t *dev = &svga->dev8514;
uint16_t dat;
int comb;
int offset = dev->hwcursor_latch.x - dev->hwcursor_latch.xoff;
uint32_t color0;
uint32_t color1;
if (svga->bpp == 8) {
color0 = dev->pallook[mach->cursor_col_0];
color1 = dev->pallook[mach->cursor_col_1];
} else if (svga->bpp == 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];
} else if (svga->bpp == 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];
} else {
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);
}
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;
if (offset >= dev->hwcursor_latch.x) {
switch (comb) {
case 0:
(svga->monitor->target_buffer->line[displine])[offset + svga->x_add] = color0;
break;
case 1:
(svga->monitor->target_buffer->line[displine])[offset + svga->x_add] = color1;
break;
case 3:
(svga->monitor->target_buffer->line[displine])[offset + svga->x_add] ^= 0xffffff;
break;
default:
break;
}
}
offset++;
}
dev->hwcursor_latch.addr += 2;
}
if (dev->interlace && !dev->hwcursor_oddeven)
dev->hwcursor_latch.addr += 16;
}
static void
mach_io_remove(mach_t *mach)
{
io_removehandler(0x2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x12e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x16e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x1ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x1ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x22e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x26e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x2ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x42e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x4ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x52e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x56e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x5ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x5ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x82e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x86e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x8ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x8ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x92e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x96e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x9ae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x9ee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xa2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xa6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xaae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xaee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xb2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xb6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xbae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xbee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xe2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xc2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xc6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xcae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xcee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xd2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xd6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xdae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xdee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xe6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xeae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xeee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xf2e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xf6e8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xfae8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xfee8, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x02ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x06ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x0aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x0eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x12ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x16ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x1aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x1eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x22ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x26ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x2aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x2eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x32ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x36ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x3aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x3eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x42ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x46ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x4aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x52ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x56ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x5aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x5eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x62ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x66ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x6aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x6eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x72ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x76ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x7aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x7eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x82ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x8eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x92ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x96ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0x9aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xa2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xa6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xaaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xaeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xb2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xb6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xbaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xbeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xc2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xc6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xcaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xceee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xd2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xd6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xdaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xdeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xe2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xe6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xeeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xf2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xfaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
io_removehandler(0xfeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach);
}
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(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(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(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 *p)
{
mach_t *mach = (mach_t *) p;
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;
svga_t *svga = &mach->svga;
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 *p)
{
mach_t *mach = (mach_t *) p;
mach_log("FeedB = %x.\n", mach->pos_regs[2] & 0x01);
return mach->pos_regs[2] & 0x01;
}
static void
mach_mca_reset(void *p)
{
mach_t *mach = (mach_t *) p;
mem_mapping_disable(&mach->bios_rom.mapping);
mem_mapping_disable(&mach->bios_rom2.mapping);
mach_log("MCA reset.\n");
ibm8514_on = 0;
vga_on = 1;
mach_mca_write(0x102, 0, mach);
}
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(0x03c0, 32, 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(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
mach32_updatemapping(mach);
break;
case 0x12:
mach->linear_base = (mach->linear_base & 0xff000000) | ((val & 0xc0) << 16);
mach32_updatemapping(mach);
break;
case 0x13:
mach->linear_base = (mach->linear_base & 0xc00000) | (val << 24);
mach32_updatemapping(mach);
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 = malloc(sizeof(mach_t));
memset(mach, 0x00, sizeof(mach_t));
svga = &mach->svga;
dev = &svga->dev8514;
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 >= 2) {
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_ROM_PATH,
0xc0000, 0x8000, 0x7fff,
0, MEM_MAPPING_EXTERNAL);
}
if (dev->local >= 2) {
svga_init(info, svga, mach, mach->memory << 10, /*default: 2MB for Mach32*/
mach_recalctimings,
mach_in, mach_out,
mach32_hwcursor_draw,
NULL);
dev->hwcursor.cur_ysize = 64;
dev->vram_size = svga->vram_max;
dev->vram = svga->vram;
dev->changedvram = svga->changedvram;
dev->vram_mask = svga->vram_mask;
mach->config1 = 0x20;
mach->config2 = 0x08;
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;
mach->config1 |= 0x1000;
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);
dev->vram_mask = dev->vram_size - 1;
video_inform(VIDEO_FLAG_TYPE_8514, &timing_gfxultra_isa);
mach->config1 = 0x02 | 0x20 | 0x80;
mach->config2 = 0x02;
svga->clock_gen = device_add(&ati18810_device);
}
dev->bpp = 0;
svga->getclock = ics2494_getclock;
dev->ext_pitch = 1024;
dev->ext_crt_pitch = 0x80;
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);
io_sethandler(0x46e8, 1, mach_in, NULL, NULL, mach_out, NULL, NULL, mach);
mach_io_set(mach);
if (dev->local >= 2) {
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;
}
static int
mach8_available(void)
{
return rom_present(BIOS_MACH8_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 = &svga->dev8514;
if (dev && (dev->local < 2)) {
free(dev->vram);
free(dev->changedvram);
}
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_isa_device = {
.name = "ATI Mach8 (ISA)",
.internal_name = "mach8_isa",
.flags = DEVICE_ISA,
.local = 1,
.init = mach8_init,
.close = mach_close,
.reset = NULL,
{ .available = mach8_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
};