Re-added the ATi Mach64GX ISA, this time with a working BIOS; Fixed some CGA/EGA/(S)VGA timing mess-ups.
3615 lines
151 KiB
C
3615 lines
151 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.
|
|
*
|
|
* ATi Mach64 graphics card emulation.
|
|
*
|
|
* Version: @(#)vid_ati_mach64.c 1.0.11 2018/01/25
|
|
*
|
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
*
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
* Copyright 2016-2018 Miran Grca.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <wchar.h>
|
|
#include "../86box.h"
|
|
#include "../machine/machine.h"
|
|
#include "../device.h"
|
|
#include "../io.h"
|
|
#include "../mem.h"
|
|
#include "../pci.h"
|
|
#include "../rom.h"
|
|
#include "../plat.h"
|
|
#include "video.h"
|
|
#include "vid_svga.h"
|
|
#include "vid_svga_render.h"
|
|
#include "vid_ati68860_ramdac.h"
|
|
#include "vid_ati_eeprom.h"
|
|
#include "vid_ics2595.h"
|
|
|
|
#ifdef CLAMP
|
|
#undef CLAMP
|
|
#endif
|
|
|
|
#define BIOS_ROM_PATH L"roms/video/mach64/bios.bin"
|
|
#define BIOS_ISA_ROM_PATH L"roms/video/mach64/M64-1994.VBI"
|
|
#define BIOS_VLB_ROM_PATH L"roms/video/mach64/mach64_vlb_vram.bin"
|
|
#define BIOS_ROMVT2_PATH L"roms/video/mach64/atimach64vt2pci.bin"
|
|
|
|
|
|
#define FIFO_SIZE 65536
|
|
#define FIFO_MASK (FIFO_SIZE - 1)
|
|
#define FIFO_ENTRY_SIZE (1 << 31)
|
|
|
|
#define FIFO_ENTRIES (mach64->fifo_write_idx - mach64->fifo_read_idx)
|
|
#define FIFO_FULL ((mach64->fifo_write_idx - mach64->fifo_read_idx) >= FIFO_SIZE)
|
|
#define FIFO_EMPTY (mach64->fifo_read_idx == mach64->fifo_write_idx)
|
|
|
|
#define FIFO_TYPE 0xff000000
|
|
#define FIFO_ADDR 0x00ffffff
|
|
|
|
enum
|
|
{
|
|
FIFO_INVALID = (0x00 << 24),
|
|
FIFO_WRITE_BYTE = (0x01 << 24),
|
|
FIFO_WRITE_WORD = (0x02 << 24),
|
|
FIFO_WRITE_DWORD = (0x03 << 24)
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t addr_type;
|
|
uint32_t val;
|
|
} fifo_entry_t;
|
|
|
|
enum
|
|
{
|
|
MACH64_GX = 0,
|
|
MACH64_VT2
|
|
};
|
|
|
|
typedef struct mach64_t
|
|
{
|
|
mem_mapping_t linear_mapping;
|
|
mem_mapping_t mmio_mapping;
|
|
mem_mapping_t mmio_linear_mapping;
|
|
mem_mapping_t mmio_linear_mapping_2;
|
|
|
|
ati68860_ramdac_t ramdac;
|
|
ati_eeprom_t eeprom;
|
|
ics2595_t ics2595;
|
|
svga_t svga;
|
|
|
|
rom_t bios_rom;
|
|
|
|
uint8_t regs[256];
|
|
int index;
|
|
|
|
int type;
|
|
|
|
uint8_t pci_regs[256];
|
|
uint8_t int_line;
|
|
int card;
|
|
|
|
int bank_r[2];
|
|
int bank_w[2];
|
|
|
|
uint32_t vram_size;
|
|
uint32_t vram_mask;
|
|
|
|
uint32_t config_cntl;
|
|
|
|
uint32_t context_load_cntl;
|
|
uint32_t context_mask;
|
|
|
|
uint32_t crtc_gen_cntl;
|
|
uint8_t crtc_int_cntl;
|
|
uint32_t crtc_h_total_disp;
|
|
uint32_t crtc_v_sync_strt_wid;
|
|
uint32_t crtc_v_total_disp;
|
|
uint32_t crtc_off_pitch;
|
|
|
|
uint32_t clock_cntl;
|
|
|
|
uint32_t clr_cmp_clr;
|
|
uint32_t clr_cmp_cntl;
|
|
uint32_t clr_cmp_mask;
|
|
|
|
uint32_t cur_horz_vert_off;
|
|
uint32_t cur_horz_vert_posn;
|
|
uint32_t cur_offset;
|
|
|
|
uint32_t dac_cntl;
|
|
|
|
uint32_t dp_bkgd_clr;
|
|
uint32_t dp_frgd_clr;
|
|
uint32_t dp_mix;
|
|
uint32_t dp_pix_width;
|
|
uint32_t dp_src;
|
|
|
|
uint32_t dst_bres_lnth;
|
|
uint32_t dst_bres_dec;
|
|
uint32_t dst_bres_err;
|
|
uint32_t dst_bres_inc;
|
|
|
|
uint32_t dst_cntl;
|
|
uint32_t dst_height_width;
|
|
uint32_t dst_off_pitch;
|
|
uint32_t dst_y_x;
|
|
|
|
uint32_t gen_test_cntl;
|
|
|
|
uint32_t gui_traj_cntl;
|
|
|
|
uint32_t host_cntl;
|
|
|
|
uint32_t mem_cntl;
|
|
|
|
uint32_t ovr_clr;
|
|
uint32_t ovr_wid_left_right;
|
|
uint32_t ovr_wid_top_bottom;
|
|
|
|
uint32_t pat_cntl;
|
|
uint32_t pat_reg0, pat_reg1;
|
|
|
|
uint32_t sc_left_right, sc_top_bottom;
|
|
|
|
uint32_t scratch_reg0, scratch_reg1;
|
|
|
|
uint32_t src_cntl;
|
|
uint32_t src_off_pitch;
|
|
uint32_t src_y_x;
|
|
uint32_t src_y_x_start;
|
|
uint32_t src_height1_width1, src_height2_width2;
|
|
|
|
|
|
uint32_t linear_base, old_linear_base;
|
|
uint32_t io_base;
|
|
|
|
struct
|
|
{
|
|
int op;
|
|
|
|
int dst_x, dst_y;
|
|
int dst_x_start, dst_y_start;
|
|
int src_x, src_y;
|
|
int src_x_start, src_y_start;
|
|
int xinc, yinc;
|
|
int x_count, y_count;
|
|
int src_x_count, src_y_count;
|
|
int src_width1, src_height1;
|
|
int src_width2, src_height2;
|
|
uint32_t src_offset, src_pitch;
|
|
uint32_t dst_offset, dst_pitch;
|
|
int mix_bg, mix_fg;
|
|
int source_bg, source_fg, source_mix;
|
|
int source_host;
|
|
int dst_width, dst_height;
|
|
int busy;
|
|
int pattern[8][8];
|
|
int sc_left, sc_right, sc_top, sc_bottom;
|
|
int dst_pix_width, src_pix_width, host_pix_width;
|
|
int dst_size, src_size, host_size;
|
|
|
|
uint32_t dp_bkgd_clr;
|
|
uint32_t dp_frgd_clr;
|
|
|
|
uint32_t clr_cmp_clr;
|
|
uint32_t clr_cmp_mask;
|
|
int clr_cmp_fn;
|
|
int clr_cmp_src;
|
|
|
|
int err;
|
|
int poly_draw;
|
|
} accel;
|
|
|
|
fifo_entry_t fifo[FIFO_SIZE];
|
|
volatile int fifo_read_idx, fifo_write_idx;
|
|
|
|
thread_t *fifo_thread;
|
|
event_t *wake_fifo_thread;
|
|
event_t *fifo_not_full_event;
|
|
|
|
int blitter_busy;
|
|
uint64_t blitter_time;
|
|
uint64_t status_time;
|
|
|
|
uint16_t pci_id;
|
|
uint32_t config_chip_id;
|
|
uint32_t block_decoded_io;
|
|
int use_block_decoded_io;
|
|
|
|
int pll_addr;
|
|
uint8_t pll_regs[16];
|
|
double pll_freq[4];
|
|
|
|
uint32_t config_stat0;
|
|
|
|
uint32_t cur_clr0, cur_clr1;
|
|
|
|
uint32_t overlay_dat[1024];
|
|
uint32_t overlay_graphics_key_clr, overlay_graphics_key_msk;
|
|
uint32_t overlay_video_key_clr, overlay_video_key_msk;
|
|
uint32_t overlay_key_cntl;
|
|
uint32_t overlay_scale_inc;
|
|
uint32_t overlay_scale_cntl;
|
|
uint32_t overlay_y_x_start, overlay_y_x_end;
|
|
|
|
uint32_t scaler_height_width;
|
|
int scaler_format;
|
|
int scaler_update;
|
|
|
|
uint32_t buf_offset[2], buf_pitch[2];
|
|
|
|
int overlay_v_acc;
|
|
} mach64_t;
|
|
|
|
enum
|
|
{
|
|
SRC_BG = 0,
|
|
SRC_FG = 1,
|
|
SRC_HOST = 2,
|
|
SRC_BLITSRC = 3,
|
|
SRC_PAT = 4
|
|
};
|
|
|
|
enum
|
|
{
|
|
MONO_SRC_1 = 0,
|
|
MONO_SRC_PAT = 1,
|
|
MONO_SRC_HOST = 2,
|
|
MONO_SRC_BLITSRC = 3
|
|
};
|
|
|
|
enum
|
|
{
|
|
BPP_1 = 0,
|
|
BPP_4 = 1,
|
|
BPP_8 = 2,
|
|
BPP_15 = 3,
|
|
BPP_16 = 4,
|
|
BPP_32 = 5
|
|
};
|
|
|
|
enum
|
|
{
|
|
OP_RECT,
|
|
OP_LINE
|
|
};
|
|
|
|
enum
|
|
{
|
|
SRC_PATT_EN = 1,
|
|
SRC_PATT_ROT_EN = 2,
|
|
SRC_LINEAR_EN = 4
|
|
};
|
|
|
|
enum
|
|
{
|
|
DP_BYTE_PIX_ORDER = (1 << 24)
|
|
};
|
|
|
|
#define WIDTH_1BIT 3
|
|
|
|
static int mach64_width[8] = {WIDTH_1BIT, 0, 0, 1, 1, 2, 2, 0};
|
|
|
|
enum
|
|
{
|
|
DST_X_DIR = 0x01,
|
|
DST_Y_DIR = 0x02,
|
|
DST_Y_MAJOR = 0x04,
|
|
DST_X_TILE = 0x08,
|
|
DST_Y_TILE = 0x10,
|
|
DST_LAST_PEL = 0x20,
|
|
DST_POLYGON_EN = 0x40,
|
|
DST_24_ROT_EN = 0x80
|
|
};
|
|
|
|
enum
|
|
{
|
|
HOST_BYTE_ALIGN = (1 << 0)
|
|
};
|
|
|
|
void mach64_write(uint32_t addr, uint8_t val, void *priv);
|
|
uint8_t mach64_read(uint32_t addr, void *priv);
|
|
void mach64_updatemapping(mach64_t *mach64);
|
|
void mach64_recalctimings(svga_t *svga);
|
|
void mach64_start_fill(mach64_t *mach64);
|
|
void mach64_start_line(mach64_t *mach64);
|
|
void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64);
|
|
void mach64_load_context(mach64_t *mach64);
|
|
|
|
uint8_t mach64_ext_readb(uint32_t addr, void *priv);
|
|
uint16_t mach64_ext_readw(uint32_t addr, void *priv);
|
|
uint32_t mach64_ext_readl(uint32_t addr, void *priv);
|
|
void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv);
|
|
void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv);
|
|
void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv);
|
|
|
|
void mach64_out(uint16_t addr, uint8_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = p;
|
|
svga_t *svga = &mach64->svga;
|
|
uint8_t old;
|
|
|
|
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1))
|
|
addr ^= 0x60;
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x1ce:
|
|
mach64->index = val;
|
|
break;
|
|
case 0x1cf:
|
|
mach64->regs[mach64->index & 0x3f] = val;
|
|
if ((mach64->index & 0x3f) == 0x36)
|
|
mach64_recalctimings(svga);
|
|
break;
|
|
|
|
case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
|
|
if (mach64->type == MACH64_GX)
|
|
ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->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))
|
|
mach64_updatemapping(mach64);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 0x3D4:
|
|
svga->crtcreg = val & 0x3f;
|
|
return;
|
|
case 0x3D5:
|
|
if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
|
|
return;
|
|
if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
|
|
val = (svga->crtc[7] & ~0x10) | (val & 0x10);
|
|
if (svga->crtcreg > 0x18)
|
|
return;
|
|
old = svga->crtc[svga->crtcreg];
|
|
svga->crtc[svga->crtcreg] = val;
|
|
|
|
if (old!=val)
|
|
{
|
|
if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
|
|
{
|
|
svga->fullchange = changeframecount;
|
|
svga_recalctimings(svga);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
svga_out(addr, val, svga);
|
|
}
|
|
|
|
uint8_t mach64_in(uint16_t addr, void *p)
|
|
{
|
|
mach64_t *mach64 = p;
|
|
svga_t *svga = &mach64->svga;
|
|
|
|
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1))
|
|
addr ^= 0x60;
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x1ce:
|
|
return mach64->index;
|
|
case 0x1cf:
|
|
return mach64->regs[mach64->index & 0x3f];
|
|
|
|
case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
|
|
if (mach64->type == MACH64_GX)
|
|
return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga);
|
|
return svga_in(addr, svga);
|
|
|
|
case 0x3D4:
|
|
return svga->crtcreg;
|
|
case 0x3D5:
|
|
if (svga->crtcreg > 0x18)
|
|
return 0xff;
|
|
return svga->crtc[svga->crtcreg];
|
|
}
|
|
return svga_in(addr, svga);
|
|
}
|
|
|
|
void mach64_recalctimings(svga_t *svga)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)svga->p;
|
|
|
|
if (((mach64->crtc_gen_cntl >> 24) & 3) == 3)
|
|
{
|
|
svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1;
|
|
svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1;
|
|
svga->htotal = (mach64->crtc_h_total_disp & 255) + 1;
|
|
svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1;
|
|
svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1;
|
|
svga->rowoffset = (mach64->crtc_off_pitch >> 22);
|
|
svga->clock = cpuclock / mach64->ics2595.output_clock;
|
|
svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2;
|
|
svga->linedbl = svga->rowcount = 0;
|
|
svga->split = 0xffffff;
|
|
svga->vblankstart = svga->dispend;
|
|
svga->rowcount = mach64->crtc_gen_cntl & 1;
|
|
svga->rowoffset <<= 1;
|
|
if (mach64->type == MACH64_GX)
|
|
svga->render = mach64->ramdac.render;
|
|
switch ((mach64->crtc_gen_cntl >> 8) & 7)
|
|
{
|
|
case 1:
|
|
if (mach64->type != MACH64_GX)
|
|
svga->render = svga_render_4bpp_highres;
|
|
svga->hdisp *= 8;
|
|
break;
|
|
case 2:
|
|
if (mach64->type != MACH64_GX)
|
|
svga->render = svga_render_8bpp_highres;
|
|
svga->hdisp *= 8;
|
|
svga->rowoffset /= 2;
|
|
break;
|
|
case 3:
|
|
if (mach64->type != MACH64_GX)
|
|
svga->render = svga_render_15bpp_highres;
|
|
svga->hdisp *= 8;
|
|
break;
|
|
case 4:
|
|
if (mach64->type != MACH64_GX)
|
|
svga->render = svga_render_16bpp_highres;
|
|
svga->hdisp *= 8;
|
|
break;
|
|
case 5:
|
|
if (mach64->type != MACH64_GX)
|
|
svga->render = svga_render_24bpp_highres;
|
|
svga->hdisp *= 8;
|
|
svga->rowoffset = (svga->rowoffset * 3) / 2;
|
|
break;
|
|
case 6:
|
|
if (mach64->type != MACH64_GX)
|
|
svga->render = svga_render_32bpp_highres;
|
|
svga->hdisp *= 8;
|
|
svga->rowoffset *= 2;
|
|
break;
|
|
}
|
|
|
|
svga->vram_display_mask = mach64->vram_mask;
|
|
}
|
|
else
|
|
{
|
|
svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff;
|
|
}
|
|
}
|
|
|
|
void mach64_updatemapping(mach64_t *mach64)
|
|
{
|
|
svga_t *svga = &mach64->svga;
|
|
|
|
if (!(mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM))
|
|
{
|
|
/* pclog("Update mapping - PCI disabled\n"); */
|
|
mem_mapping_disable(&svga->mapping);
|
|
mem_mapping_disable(&mach64->linear_mapping);
|
|
mem_mapping_disable(&mach64->mmio_mapping);
|
|
mem_mapping_disable(&mach64->mmio_linear_mapping);
|
|
mem_mapping_disable(&mach64->mmio_linear_mapping_2);
|
|
return;
|
|
}
|
|
|
|
mem_mapping_disable(&mach64->mmio_mapping);
|
|
switch (svga->gdcreg[6] & 0xc)
|
|
{
|
|
case 0x0: /*128k at A0000*/
|
|
mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, NULL, NULL, mach64_write, NULL, NULL);
|
|
mem_mapping_set_p(&mach64->svga.mapping, mach64);
|
|
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
|
|
mem_mapping_enable(&mach64->mmio_mapping);
|
|
svga->banked_mask = 0xffff;
|
|
break;
|
|
case 0x4: /*64k at A0000*/
|
|
mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, NULL, NULL, mach64_write, NULL, NULL);
|
|
mem_mapping_set_p(&mach64->svga.mapping, mach64);
|
|
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
|
|
svga->banked_mask = 0xffff;
|
|
break;
|
|
case 0x8: /*32k at B0000*/
|
|
mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
|
|
mem_mapping_set_p(&mach64->svga.mapping, svga);
|
|
mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
|
|
svga->banked_mask = 0x7fff;
|
|
break;
|
|
case 0xC: /*32k at B8000*/
|
|
mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
|
|
mem_mapping_set_p(&mach64->svga.mapping, svga);
|
|
mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
|
|
svga->banked_mask = 0x7fff;
|
|
break;
|
|
}
|
|
if (mach64->linear_base)
|
|
{
|
|
if (mach64->type == MACH64_GX)
|
|
{
|
|
if ((mach64->config_cntl & 3) == 2)
|
|
{
|
|
/*8 MB aperture*/
|
|
mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000);
|
|
mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000);
|
|
}
|
|
else
|
|
{
|
|
/*4 MB aperture*/
|
|
mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (4 << 20) - 0x4000);
|
|
mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((4 << 20) - 0x4000), 0x4000);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*2*8 MB aperture*/
|
|
mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000);
|
|
mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000);
|
|
mem_mapping_set_addr(&mach64->mmio_linear_mapping_2, mach64->linear_base + ((16 << 20) - 0x4000), 0x4000);
|
|
}
|
|
svga->linear_base = mach64->linear_base;
|
|
}
|
|
else
|
|
{
|
|
mem_mapping_disable(&mach64->linear_mapping);
|
|
mem_mapping_disable(&mach64->mmio_linear_mapping);
|
|
mem_mapping_disable(&mach64->mmio_linear_mapping_2);
|
|
}
|
|
}
|
|
|
|
static void mach64_update_irqs(mach64_t *mach64)
|
|
{
|
|
if ((mach64->crtc_int_cntl & 0xaa0024) & ((mach64->crtc_int_cntl << 1) & 0xaa0024))
|
|
pci_set_irq(mach64->card, PCI_INTA);
|
|
else
|
|
pci_clear_irq(mach64->card, PCI_INTA);
|
|
}
|
|
|
|
static __inline void wake_fifo_thread(mach64_t *mach64)
|
|
{
|
|
thread_set_event(mach64->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
|
|
}
|
|
|
|
static void mach64_wait_fifo_idle(mach64_t *mach64)
|
|
{
|
|
while (!FIFO_EMPTY)
|
|
{
|
|
wake_fifo_thread(mach64);
|
|
thread_wait_event(mach64->fifo_not_full_event, 1);
|
|
}
|
|
}
|
|
|
|
#define READ8(addr, var) switch ((addr) & 3) \
|
|
{ \
|
|
case 0: ret = (var) & 0xff; break; \
|
|
case 1: ret = ((var) >> 8) & 0xff; break; \
|
|
case 2: ret = ((var) >> 16) & 0xff; break; \
|
|
case 3: ret = ((var) >> 24) & 0xff; break; \
|
|
}
|
|
|
|
#define WRITE8(addr, var, val) switch ((addr) & 3) \
|
|
{ \
|
|
case 0: var = (var & 0xffffff00) | (val); break; \
|
|
case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \
|
|
case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \
|
|
case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \
|
|
}
|
|
|
|
static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val)
|
|
{
|
|
switch (addr & 0x3ff)
|
|
{
|
|
case 0x100: case 0x101: case 0x102: case 0x103:
|
|
WRITE8(addr, mach64->dst_off_pitch, val);
|
|
break;
|
|
case 0x104: case 0x105: case 0x11c: case 0x11d:
|
|
WRITE8(addr + 2, mach64->dst_y_x, val);
|
|
break;
|
|
case 0x108: case 0x109:
|
|
WRITE8(addr, mach64->dst_y_x, val);
|
|
break;
|
|
case 0x10c: case 0x10d: case 0x10e: case 0x10f:
|
|
WRITE8(addr, mach64->dst_y_x, val);
|
|
break;
|
|
case 0x110: case 0x111:
|
|
WRITE8(addr + 2, mach64->dst_height_width, val);
|
|
break;
|
|
case 0x114: case 0x115:
|
|
case 0x118: case 0x119: case 0x11a: case 0x11b:
|
|
case 0x11e: case 0x11f:
|
|
WRITE8(addr, mach64->dst_height_width, val);
|
|
case 0x113:
|
|
if (((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f ||
|
|
(addr & 0x3ff) == 0x113) && !(val & 0x80))
|
|
{
|
|
mach64_start_fill(mach64);
|
|
#ifdef MACH64_DEBUG
|
|
pclog("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000),
|
|
((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST),
|
|
(((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src);
|
|
#endif
|
|
if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) &&
|
|
((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) &&
|
|
(((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST))
|
|
mach64_blit(0, -1, mach64);
|
|
}
|
|
break;
|
|
|
|
case 0x120: case 0x121: case 0x122: case 0x123:
|
|
WRITE8(addr, mach64->dst_bres_lnth, val);
|
|
if ((addr & 0x3ff) == 0x123 && !(val & 0x80))
|
|
{
|
|
mach64_start_line(mach64);
|
|
|
|
if ((mach64->dst_bres_lnth & 0x7fff) &&
|
|
((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) &&
|
|
(((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST))
|
|
mach64_blit(0, -1, mach64);
|
|
}
|
|
break;
|
|
case 0x124: case 0x125: case 0x126: case 0x127:
|
|
WRITE8(addr, mach64->dst_bres_err, val);
|
|
break;
|
|
case 0x128: case 0x129: case 0x12a: case 0x12b:
|
|
WRITE8(addr, mach64->dst_bres_inc, val);
|
|
break;
|
|
case 0x12c: case 0x12d: case 0x12e: case 0x12f:
|
|
WRITE8(addr, mach64->dst_bres_dec, val);
|
|
break;
|
|
|
|
case 0x130: case 0x131: case 0x132: case 0x133:
|
|
WRITE8(addr, mach64->dst_cntl, val);
|
|
break;
|
|
|
|
case 0x180: case 0x181: case 0x182: case 0x183:
|
|
WRITE8(addr, mach64->src_off_pitch, val);
|
|
break;
|
|
case 0x184: case 0x185:
|
|
WRITE8(addr, mach64->src_y_x, val);
|
|
break;
|
|
case 0x188: case 0x189:
|
|
WRITE8(addr + 2, mach64->src_y_x, val);
|
|
break;
|
|
case 0x18c: case 0x18d: case 0x18e: case 0x18f:
|
|
WRITE8(addr, mach64->src_y_x, val);
|
|
break;
|
|
case 0x190: case 0x191:
|
|
WRITE8(addr + 2, mach64->src_height1_width1, val);
|
|
break;
|
|
case 0x194: case 0x195:
|
|
WRITE8(addr, mach64->src_height1_width1, val);
|
|
break;
|
|
case 0x198: case 0x199: case 0x19a: case 0x19b:
|
|
WRITE8(addr, mach64->src_height1_width1, val);
|
|
break;
|
|
case 0x19c: case 0x19d:
|
|
WRITE8(addr, mach64->src_y_x_start, val);
|
|
break;
|
|
case 0x1a0: case 0x1a1:
|
|
WRITE8(addr + 2, mach64->src_y_x_start, val);
|
|
break;
|
|
case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7:
|
|
WRITE8(addr, mach64->src_y_x_start, val);
|
|
break;
|
|
case 0x1a8: case 0x1a9:
|
|
WRITE8(addr + 2, mach64->src_height2_width2, val);
|
|
break;
|
|
case 0x1ac: case 0x1ad:
|
|
WRITE8(addr, mach64->src_height2_width2, val);
|
|
break;
|
|
case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3:
|
|
WRITE8(addr, mach64->src_height2_width2, val);
|
|
break;
|
|
|
|
case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7:
|
|
WRITE8(addr, mach64->src_cntl, val);
|
|
break;
|
|
|
|
case 0x200: case 0x201: case 0x202: case 0x203:
|
|
case 0x204: case 0x205: case 0x206: case 0x207:
|
|
case 0x208: case 0x209: case 0x20a: case 0x20b:
|
|
case 0x20c: case 0x20d: case 0x20e: case 0x20f:
|
|
case 0x210: case 0x211: case 0x212: case 0x213:
|
|
case 0x214: case 0x215: case 0x216: case 0x217:
|
|
case 0x218: case 0x219: case 0x21a: case 0x21b:
|
|
case 0x21c: case 0x21d: case 0x21e: case 0x21f:
|
|
case 0x220: case 0x221: case 0x222: case 0x223:
|
|
case 0x224: case 0x225: case 0x226: case 0x227:
|
|
case 0x228: case 0x229: case 0x22a: case 0x22b:
|
|
case 0x22c: case 0x22d: case 0x22e: case 0x22f:
|
|
case 0x230: case 0x231: case 0x232: case 0x233:
|
|
case 0x234: case 0x235: case 0x236: case 0x237:
|
|
case 0x238: case 0x239: case 0x23a: case 0x23b:
|
|
case 0x23c: case 0x23d: case 0x23e: case 0x23f:
|
|
mach64_blit(val, 8, mach64);
|
|
break;
|
|
|
|
case 0x240: case 0x241: case 0x242: case 0x243:
|
|
WRITE8(addr, mach64->host_cntl, val);
|
|
break;
|
|
|
|
case 0x280: case 0x281: case 0x282: case 0x283:
|
|
WRITE8(addr, mach64->pat_reg0, val);
|
|
break;
|
|
case 0x284: case 0x285: case 0x286: case 0x287:
|
|
WRITE8(addr, mach64->pat_reg1, val);
|
|
break;
|
|
|
|
case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9:
|
|
WRITE8(addr, mach64->sc_left_right, val);
|
|
break;
|
|
case 0x2a4: case 0x2a5:
|
|
addr += 2;
|
|
case 0x2aa: case 0x2ab:
|
|
WRITE8(addr, mach64->sc_left_right, val);
|
|
break;
|
|
|
|
case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5:
|
|
WRITE8(addr, mach64->sc_top_bottom, val);
|
|
break;
|
|
case 0x2b0: case 0x2b1:
|
|
addr += 2;
|
|
case 0x2b6: case 0x2b7:
|
|
WRITE8(addr, mach64->sc_top_bottom, val);
|
|
break;
|
|
|
|
case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3:
|
|
WRITE8(addr, mach64->dp_bkgd_clr, val);
|
|
break;
|
|
case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7:
|
|
WRITE8(addr, mach64->dp_frgd_clr, val);
|
|
break;
|
|
|
|
case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3:
|
|
WRITE8(addr, mach64->dp_pix_width, val);
|
|
break;
|
|
case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7:
|
|
WRITE8(addr, mach64->dp_mix, val);
|
|
break;
|
|
case 0x2d8: case 0x2d9: case 0x2da: case 0x2db:
|
|
WRITE8(addr, mach64->dp_src, val);
|
|
break;
|
|
|
|
case 0x300: case 0x301: case 0x302: case 0x303:
|
|
WRITE8(addr, mach64->clr_cmp_clr, val);
|
|
break;
|
|
case 0x304: case 0x305: case 0x306: case 0x307:
|
|
WRITE8(addr, mach64->clr_cmp_mask, val);
|
|
break;
|
|
case 0x308: case 0x309: case 0x30a: case 0x30b:
|
|
WRITE8(addr, mach64->clr_cmp_cntl, val);
|
|
break;
|
|
|
|
case 0x320: case 0x321: case 0x322: case 0x323:
|
|
WRITE8(addr, mach64->context_mask, val);
|
|
break;
|
|
|
|
case 0x330: case 0x331:
|
|
WRITE8(addr, mach64->dst_cntl, val);
|
|
break;
|
|
case 0x332:
|
|
WRITE8(addr - 2, mach64->src_cntl, val);
|
|
break;
|
|
case 0x333:
|
|
WRITE8(addr - 3, mach64->pat_cntl, val & 7);
|
|
if (val & 0x10)
|
|
mach64->host_cntl |= HOST_BYTE_ALIGN;
|
|
else
|
|
mach64->host_cntl &= ~HOST_BYTE_ALIGN;
|
|
break;
|
|
}
|
|
}
|
|
static void mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t val)
|
|
{
|
|
switch (addr & 0x3fe)
|
|
{
|
|
case 0x200: case 0x202: case 0x204: case 0x206:
|
|
case 0x208: case 0x20a: case 0x20c: case 0x20e:
|
|
case 0x210: case 0x212: case 0x214: case 0x216:
|
|
case 0x218: case 0x21a: case 0x21c: case 0x21e:
|
|
case 0x220: case 0x222: case 0x224: case 0x226:
|
|
case 0x228: case 0x22a: case 0x22c: case 0x22e:
|
|
case 0x230: case 0x232: case 0x234: case 0x236:
|
|
case 0x238: case 0x23a: case 0x23c: case 0x23e:
|
|
mach64_blit(val, 16, mach64);
|
|
break;
|
|
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_accel_write_fifo(mach64, addr, val);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_accel_write_fifo(mach64, addr + 1, val >> 8);
|
|
break;
|
|
}
|
|
}
|
|
static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val)
|
|
{
|
|
switch (addr & 0x3fc)
|
|
{
|
|
case 0x32c:
|
|
mach64->context_load_cntl = val;
|
|
if (val & 0x30000)
|
|
mach64_load_context(mach64);
|
|
break;
|
|
|
|
case 0x200: case 0x204: case 0x208: case 0x20c:
|
|
case 0x210: case 0x214: case 0x218: case 0x21c:
|
|
case 0x220: case 0x224: case 0x228: case 0x22c:
|
|
case 0x230: case 0x234: case 0x238: case 0x23c:
|
|
if (mach64->accel.source_host || (mach64->dp_pix_width & DP_BYTE_PIX_ORDER))
|
|
mach64_blit(val, 32, mach64);
|
|
else
|
|
mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64);
|
|
break;
|
|
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_accel_write_fifo_w(mach64, addr, val);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_accel_write_fifo_w(mach64, addr + 2, val >> 16);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fifo_thread(void *param)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)param;
|
|
|
|
while (1)
|
|
{
|
|
thread_set_event(mach64->fifo_not_full_event);
|
|
thread_wait_event(mach64->wake_fifo_thread, -1);
|
|
thread_reset_event(mach64->wake_fifo_thread);
|
|
mach64->blitter_busy = 1;
|
|
while (!FIFO_EMPTY)
|
|
{
|
|
uint64_t start_time = plat_timer_read();
|
|
uint64_t end_time;
|
|
fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_read_idx & FIFO_MASK];
|
|
|
|
switch (fifo->addr_type & FIFO_TYPE)
|
|
{
|
|
case FIFO_WRITE_BYTE:
|
|
mach64_accel_write_fifo(mach64, fifo->addr_type & FIFO_ADDR, fifo->val);
|
|
break;
|
|
case FIFO_WRITE_WORD:
|
|
mach64_accel_write_fifo_w(mach64, fifo->addr_type & FIFO_ADDR, fifo->val);
|
|
break;
|
|
case FIFO_WRITE_DWORD:
|
|
mach64_accel_write_fifo_l(mach64, fifo->addr_type & FIFO_ADDR, fifo->val);
|
|
break;
|
|
}
|
|
|
|
mach64->fifo_read_idx++;
|
|
fifo->addr_type = FIFO_INVALID;
|
|
|
|
if (FIFO_ENTRIES > 0xe000)
|
|
thread_set_event(mach64->fifo_not_full_event);
|
|
|
|
end_time = plat_timer_read();
|
|
mach64->blitter_time += end_time - start_time;
|
|
}
|
|
mach64->blitter_busy = 0;
|
|
}
|
|
}
|
|
|
|
static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t type)
|
|
{
|
|
fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_write_idx & FIFO_MASK];
|
|
|
|
if (FIFO_FULL)
|
|
{
|
|
thread_reset_event(mach64->fifo_not_full_event);
|
|
if (FIFO_FULL)
|
|
{
|
|
thread_wait_event(mach64->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/
|
|
}
|
|
}
|
|
|
|
fifo->val = val;
|
|
fifo->addr_type = (addr & FIFO_ADDR) | type;
|
|
|
|
mach64->fifo_write_idx++;
|
|
|
|
if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8)
|
|
wake_fifo_thread(mach64);
|
|
}
|
|
|
|
void mach64_cursor_dump(mach64_t *mach64)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void mach64_start_fill(mach64_t *mach64)
|
|
{
|
|
int x, y;
|
|
|
|
mach64->accel.dst_x = 0;
|
|
mach64->accel.dst_y = 0;
|
|
mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff;
|
|
mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff;
|
|
|
|
mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff;
|
|
mach64->accel.dst_height = mach64->dst_height_width & 0x1fff;
|
|
mach64->accel.x_count = mach64->accel.dst_width;
|
|
|
|
mach64->accel.src_x = 0;
|
|
mach64->accel.src_y = 0;
|
|
mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff;
|
|
mach64->accel.src_y_start = mach64->src_y_x & 0xfff;
|
|
if (mach64->src_cntl & SRC_LINEAR_EN)
|
|
mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/
|
|
else
|
|
mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff;
|
|
if (!(mach64->src_cntl & SRC_PATT_EN))
|
|
mach64->accel.src_y_count = 0x7ffffff; /*Essentially infinite*/
|
|
else
|
|
mach64->accel.src_y_count = mach64->src_height1_width1 & 0x1fff;
|
|
|
|
mach64->accel.src_width1 = (mach64->src_height1_width1 >> 16) & 0x7fff;
|
|
mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff;
|
|
mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff;
|
|
mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff;
|
|
|
|
#ifdef MACH64_DEBUG
|
|
pclog("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count,
|
|
mach64->accel.src_y_count,
|
|
mach64->accel.src_width1,
|
|
mach64->accel.src_height1,
|
|
mach64->src_height1_width1,
|
|
mach64->src_height2_width2);
|
|
#endif
|
|
|
|
mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8;
|
|
mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8;
|
|
|
|
mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8;
|
|
mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8;
|
|
|
|
mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f;
|
|
mach64->accel.mix_bg = mach64->dp_mix & 0x1f;
|
|
|
|
mach64->accel.source_bg = mach64->dp_src & 7;
|
|
mach64->accel.source_fg = (mach64->dp_src >> 8) & 7;
|
|
mach64->accel.source_mix = (mach64->dp_src >> 16) & 7;
|
|
|
|
mach64->accel.dst_pix_width = mach64->dp_pix_width & 7;
|
|
mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7;
|
|
mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7;
|
|
|
|
mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width];
|
|
mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width];
|
|
mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width];
|
|
|
|
if (mach64->accel.src_size == WIDTH_1BIT)
|
|
mach64->accel.src_offset <<= 3;
|
|
else
|
|
mach64->accel.src_offset >>= mach64->accel.src_size;
|
|
|
|
if (mach64->accel.dst_size == WIDTH_1BIT)
|
|
mach64->accel.dst_offset <<= 3;
|
|
else
|
|
mach64->accel.dst_offset >>= mach64->accel.dst_size;
|
|
|
|
mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1;
|
|
mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1;
|
|
|
|
mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST);
|
|
|
|
|
|
for (y = 0; y < 8; y++)
|
|
{
|
|
for (x = 0; x < 8; x++)
|
|
{
|
|
uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0;
|
|
mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1;
|
|
}
|
|
}
|
|
|
|
mach64->accel.sc_left = mach64->sc_left_right & 0x1fff;
|
|
mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff;
|
|
mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff;
|
|
mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff;
|
|
|
|
/* mach64->accel.sc_left *= mach64_inc[mach64->accel.dst_pix_width];
|
|
mach64->accel.sc_right *= mach64_inc[mach64->accel.dst_pix_width];*/
|
|
|
|
mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr;
|
|
mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr;
|
|
|
|
mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask;
|
|
mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask;
|
|
mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7;
|
|
mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24);
|
|
|
|
mach64->accel.poly_draw = 0;
|
|
|
|
mach64->accel.busy = 1;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg);
|
|
#endif
|
|
mach64->accel.op = OP_RECT;
|
|
}
|
|
|
|
void mach64_start_line(mach64_t *mach64)
|
|
{
|
|
int x, y;
|
|
|
|
mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff;
|
|
mach64->accel.dst_y = mach64->dst_y_x & 0xfff;
|
|
|
|
mach64->accel.src_x = (mach64->src_y_x >> 16) & 0xfff;
|
|
mach64->accel.src_y = mach64->src_y_x & 0xfff;
|
|
|
|
mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8;
|
|
mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8;
|
|
|
|
mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8;
|
|
mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8;
|
|
|
|
mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f;
|
|
mach64->accel.mix_bg = mach64->dp_mix & 0x1f;
|
|
|
|
mach64->accel.source_bg = mach64->dp_src & 7;
|
|
mach64->accel.source_fg = (mach64->dp_src >> 8) & 7;
|
|
mach64->accel.source_mix = (mach64->dp_src >> 16) & 7;
|
|
|
|
mach64->accel.dst_pix_width = mach64->dp_pix_width & 7;
|
|
mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7;
|
|
mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7;
|
|
|
|
mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width];
|
|
mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width];
|
|
mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width];
|
|
|
|
if (mach64->accel.src_size == WIDTH_1BIT)
|
|
mach64->accel.src_offset <<= 3;
|
|
else
|
|
mach64->accel.src_offset >>= mach64->accel.src_size;
|
|
|
|
if (mach64->accel.dst_size == WIDTH_1BIT)
|
|
mach64->accel.dst_offset <<= 3;
|
|
else
|
|
mach64->accel.dst_offset >>= mach64->accel.dst_size;
|
|
|
|
/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width];
|
|
mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/
|
|
|
|
mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST);
|
|
|
|
for (y = 0; y < 8; y++)
|
|
{
|
|
for (x = 0; x < 8; x++)
|
|
{
|
|
uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0;
|
|
mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1;
|
|
}
|
|
}
|
|
|
|
mach64->accel.sc_left = mach64->sc_left_right & 0x1fff;
|
|
mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff;
|
|
mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff;
|
|
mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff;
|
|
|
|
mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr;
|
|
mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr;
|
|
|
|
mach64->accel.x_count = mach64->dst_bres_lnth & 0x7fff;
|
|
mach64->accel.err = (mach64->dst_bres_err & 0x3ffff) | ((mach64->dst_bres_err & 0x40000) ? 0xfffc0000 : 0);
|
|
|
|
mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask;
|
|
mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask;
|
|
mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7;
|
|
mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24);
|
|
|
|
mach64->accel.busy = 1;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_start_line\n");
|
|
#endif
|
|
mach64->accel.op = OP_LINE;
|
|
}
|
|
|
|
#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \
|
|
else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \
|
|
else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \
|
|
else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1;
|
|
|
|
#define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \
|
|
{ \
|
|
case 0x0: dest_dat = ~dest_dat; break; \
|
|
case 0x1: dest_dat = 0; break; \
|
|
case 0x2: dest_dat = 0xffffffff; break; \
|
|
case 0x3: dest_dat = dest_dat; break; \
|
|
case 0x4: dest_dat = ~src_dat; break; \
|
|
case 0x5: dest_dat = src_dat ^ dest_dat; break; \
|
|
case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \
|
|
case 0x7: dest_dat = src_dat; break; \
|
|
case 0x8: dest_dat = ~(src_dat & dest_dat); break; \
|
|
case 0x9: dest_dat = ~src_dat | dest_dat; break; \
|
|
case 0xa: dest_dat = src_dat | ~dest_dat; break; \
|
|
case 0xb: dest_dat = src_dat | dest_dat; break; \
|
|
case 0xc: dest_dat = src_dat & dest_dat; break; \
|
|
case 0xd: dest_dat = src_dat & ~dest_dat; break; \
|
|
case 0xe: dest_dat = ~src_dat & dest_dat; break; \
|
|
case 0xf: dest_dat = ~(src_dat | dest_dat); break; \
|
|
}
|
|
|
|
#define WRITE(addr, width) if (width == 0) \
|
|
{ \
|
|
svga->vram[(addr) & mach64->vram_mask] = dest_dat; \
|
|
svga->changedvram[((addr) & mach64->vram_mask) >> 12] = changeframecount; \
|
|
} \
|
|
else if (width == 1) \
|
|
{ \
|
|
*(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \
|
|
svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = changeframecount; \
|
|
} \
|
|
else if (width == 2) \
|
|
{ \
|
|
*(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \
|
|
svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = changeframecount; \
|
|
} \
|
|
else \
|
|
{ \
|
|
if (dest_dat & 1) \
|
|
svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \
|
|
else \
|
|
svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \
|
|
svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \
|
|
}
|
|
|
|
void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64)
|
|
{
|
|
svga_t *svga = &mach64->svga;
|
|
int cmp_clr = 0;
|
|
|
|
if (!mach64->accel.busy)
|
|
{
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_blit : return as not busy\n");
|
|
#endif
|
|
return;
|
|
}
|
|
switch (mach64->accel.op)
|
|
{
|
|
case OP_RECT:
|
|
while (count)
|
|
{
|
|
uint32_t src_dat, dest_dat;
|
|
uint32_t host_dat = 0;
|
|
int mix = 0;
|
|
int dst_x = (mach64->accel.dst_x + mach64->accel.dst_x_start) & 0xfff;
|
|
int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff;
|
|
int src_x;
|
|
int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff;
|
|
|
|
if (mach64->src_cntl & SRC_LINEAR_EN)
|
|
src_x = mach64->accel.src_x;
|
|
else
|
|
src_x = (mach64->accel.src_x + mach64->accel.src_x_start) & 0xfff;
|
|
|
|
if (mach64->accel.source_host)
|
|
{
|
|
host_dat = cpu_dat;
|
|
switch (mach64->accel.host_size)
|
|
{
|
|
case 0:
|
|
cpu_dat >>= 8;
|
|
count -= 8;
|
|
break;
|
|
case 1:
|
|
cpu_dat >>= 16;
|
|
count -= 16;
|
|
break;
|
|
case 2:
|
|
count -= 32;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
count--;
|
|
|
|
switch (mach64->accel.source_mix)
|
|
{
|
|
case MONO_SRC_HOST:
|
|
if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)
|
|
{
|
|
mix = cpu_dat & 1;
|
|
cpu_dat >>= 1;
|
|
}
|
|
else
|
|
{
|
|
mix = cpu_dat >> 31;
|
|
cpu_dat <<= 1;
|
|
}
|
|
break;
|
|
case MONO_SRC_PAT:
|
|
mix = mach64->accel.pattern[dst_y & 7][dst_x & 7];
|
|
break;
|
|
case MONO_SRC_1:
|
|
mix = 1;
|
|
break;
|
|
case MONO_SRC_BLITSRC:
|
|
if (mach64->src_cntl & SRC_LINEAR_EN)
|
|
{
|
|
READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT);
|
|
}
|
|
else
|
|
{
|
|
READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right &&
|
|
dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom)
|
|
{
|
|
switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg)
|
|
{
|
|
case SRC_HOST:
|
|
src_dat = host_dat;
|
|
break;
|
|
case SRC_BLITSRC:
|
|
READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size);
|
|
break;
|
|
case SRC_FG:
|
|
src_dat = mach64->accel.dp_frgd_clr;
|
|
break;
|
|
case SRC_BG:
|
|
src_dat = mach64->accel.dp_bkgd_clr;
|
|
break;
|
|
default:
|
|
src_dat = 0;
|
|
break;
|
|
}
|
|
if (mach64->dst_cntl & DST_POLYGON_EN)
|
|
{
|
|
int poly_src;
|
|
READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, poly_src, mach64->accel.src_size);
|
|
if (poly_src)
|
|
mach64->accel.poly_draw = !mach64->accel.poly_draw;
|
|
}
|
|
if (!(mach64->dst_cntl & DST_POLYGON_EN) || mach64->accel.poly_draw)
|
|
{
|
|
READ(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, dest_dat, mach64->accel.dst_size);
|
|
|
|
switch (mach64->accel.clr_cmp_fn)
|
|
{
|
|
case 1: /*TRUE*/
|
|
cmp_clr = 1;
|
|
break;
|
|
case 4: /*DST_CLR != CLR_CMP_CLR*/
|
|
cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr;
|
|
break;
|
|
case 5: /*DST_CLR == CLR_CMP_CLR*/
|
|
cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr;
|
|
break;
|
|
}
|
|
|
|
if (!cmp_clr)
|
|
MIX
|
|
|
|
WRITE(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, mach64->accel.dst_size);
|
|
}
|
|
}
|
|
|
|
if (mach64->dst_cntl & DST_24_ROT_EN)
|
|
{
|
|
mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16);
|
|
mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16);
|
|
}
|
|
|
|
mach64->accel.src_x += mach64->accel.xinc;
|
|
mach64->accel.dst_x += mach64->accel.xinc;
|
|
if (!(mach64->src_cntl & SRC_LINEAR_EN))
|
|
{
|
|
mach64->accel.src_x_count--;
|
|
if (mach64->accel.src_x_count <= 0)
|
|
{
|
|
mach64->accel.src_x = 0;
|
|
if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN))
|
|
{
|
|
mach64->accel.src_x_start = (mach64->src_y_x_start >> 16) & 0xfff;
|
|
mach64->accel.src_x_count = mach64->accel.src_width2;
|
|
}
|
|
else
|
|
mach64->accel.src_x_count = mach64->accel.src_width1;
|
|
}
|
|
}
|
|
|
|
mach64->accel.x_count--;
|
|
|
|
if (mach64->accel.x_count <= 0)
|
|
{
|
|
mach64->accel.x_count = mach64->accel.dst_width;
|
|
mach64->accel.dst_x = 0;
|
|
mach64->accel.dst_y += mach64->accel.yinc;
|
|
mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff;
|
|
mach64->accel.src_x_count = mach64->accel.src_width1;
|
|
|
|
if (!(mach64->src_cntl & SRC_LINEAR_EN))
|
|
{
|
|
mach64->accel.src_x = 0;
|
|
mach64->accel.src_y += mach64->accel.yinc;
|
|
mach64->accel.src_y_count--;
|
|
if (mach64->accel.src_y_count <= 0)
|
|
{
|
|
mach64->accel.src_y = 0;
|
|
if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN))
|
|
{
|
|
mach64->accel.src_y_start = mach64->src_y_x_start & 0xfff;
|
|
mach64->accel.src_y_count = mach64->accel.src_height2;
|
|
}
|
|
else
|
|
mach64->accel.src_y_count = mach64->accel.src_height1;
|
|
}
|
|
}
|
|
|
|
mach64->accel.poly_draw = 0;
|
|
|
|
mach64->accel.dst_height--;
|
|
|
|
if (mach64->accel.dst_height <= 0)
|
|
{
|
|
/*Blit finished*/
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64 blit finished\n");
|
|
#endif
|
|
mach64->accel.busy = 0;
|
|
if (mach64->dst_cntl & DST_X_TILE)
|
|
mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000);
|
|
if (mach64->dst_cntl & DST_Y_TILE)
|
|
mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff);
|
|
return;
|
|
}
|
|
if (mach64->host_cntl & HOST_BYTE_ALIGN)
|
|
{
|
|
if (mach64->accel.source_mix == MONO_SRC_HOST)
|
|
{
|
|
if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)
|
|
cpu_dat >>= (count & 7);
|
|
else
|
|
cpu_dat <<= (count & 7);
|
|
count &= ~7;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OP_LINE:
|
|
while (count)
|
|
{
|
|
uint32_t src_dat = 0, dest_dat;
|
|
uint32_t host_dat = 0;
|
|
int mix = 0;
|
|
int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN);
|
|
|
|
if (mach64->accel.source_host)
|
|
{
|
|
host_dat = cpu_dat;
|
|
switch (mach64->accel.src_size)
|
|
{
|
|
case 0:
|
|
cpu_dat >>= 8;
|
|
count -= 8;
|
|
break;
|
|
case 1:
|
|
cpu_dat >>= 16;
|
|
count -= 16;
|
|
break;
|
|
case 2:
|
|
count -= 32;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
count--;
|
|
|
|
switch (mach64->accel.source_mix)
|
|
{
|
|
case MONO_SRC_HOST:
|
|
mix = cpu_dat >> 31;
|
|
cpu_dat <<= 1;
|
|
break;
|
|
case MONO_SRC_PAT:
|
|
mix = mach64->accel.pattern[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7];
|
|
break;
|
|
case MONO_SRC_1:
|
|
default:
|
|
mix = 1;
|
|
break;
|
|
}
|
|
|
|
if (mach64->dst_cntl & DST_POLYGON_EN)
|
|
{
|
|
if (mach64->dst_cntl & DST_Y_MAJOR)
|
|
draw_pixel = 1;
|
|
else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/
|
|
draw_pixel = 1;
|
|
else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/
|
|
draw_pixel = 1;
|
|
}
|
|
|
|
if (mach64->accel.x_count == 1 && !(mach64->dst_cntl & DST_LAST_PEL))
|
|
draw_pixel = 0;
|
|
|
|
if (mach64->accel.dst_x >= mach64->accel.sc_left && mach64->accel.dst_x <= mach64->accel.sc_right &&
|
|
mach64->accel.dst_y >= mach64->accel.sc_top && mach64->accel.dst_y <= mach64->accel.sc_bottom && draw_pixel)
|
|
{
|
|
switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg)
|
|
{
|
|
case SRC_HOST:
|
|
src_dat = host_dat;
|
|
break;
|
|
case SRC_BLITSRC:
|
|
READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size);
|
|
break;
|
|
case SRC_FG:
|
|
src_dat = mach64->accel.dp_frgd_clr;
|
|
break;
|
|
case SRC_BG:
|
|
src_dat = mach64->accel.dp_bkgd_clr;
|
|
break;
|
|
default:
|
|
src_dat = 0;
|
|
break;
|
|
}
|
|
|
|
READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size);
|
|
|
|
switch (mach64->accel.clr_cmp_fn)
|
|
{
|
|
case 1: /*TRUE*/
|
|
cmp_clr = 1;
|
|
break;
|
|
case 4: /*DST_CLR != CLR_CMP_CLR*/
|
|
cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr;
|
|
break;
|
|
case 5: /*DST_CLR == CLR_CMP_CLR*/
|
|
cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr;
|
|
break;
|
|
}
|
|
|
|
if (!cmp_clr)
|
|
MIX
|
|
|
|
WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size);
|
|
}
|
|
|
|
mach64->accel.x_count--;
|
|
if (mach64->accel.x_count <= 0)
|
|
{
|
|
/*Blit finished*/
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64 blit finished\n");
|
|
#endif
|
|
mach64->accel.busy = 0;
|
|
return;
|
|
}
|
|
|
|
switch (mach64->dst_cntl & 7)
|
|
{
|
|
case 0: case 2:
|
|
mach64->accel.src_x--;
|
|
mach64->accel.dst_x--;
|
|
break;
|
|
case 1: case 3:
|
|
mach64->accel.src_x++;
|
|
mach64->accel.dst_x++;
|
|
break;
|
|
case 4: case 5:
|
|
mach64->accel.src_y--;
|
|
mach64->accel.dst_y--;
|
|
break;
|
|
case 6: case 7:
|
|
mach64->accel.src_y++;
|
|
mach64->accel.dst_y++;
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
pclog("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec);
|
|
#endif
|
|
if (mach64->accel.err >= 0)
|
|
{
|
|
mach64->accel.err += mach64->dst_bres_dec;
|
|
|
|
switch (mach64->dst_cntl & 7)
|
|
{
|
|
case 0: case 1:
|
|
mach64->accel.src_y--;
|
|
mach64->accel.dst_y--;
|
|
break;
|
|
case 2: case 3:
|
|
mach64->accel.src_y++;
|
|
mach64->accel.dst_y++;
|
|
break;
|
|
case 4: case 6:
|
|
mach64->accel.src_x--;
|
|
mach64->accel.dst_x--;
|
|
break;
|
|
case 5: case 7:
|
|
mach64->accel.src_x++;
|
|
mach64->accel.dst_x++;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
mach64->accel.err += mach64->dst_bres_inc;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void mach64_load_context(mach64_t *mach64)
|
|
{
|
|
svga_t *svga = &mach64->svga;
|
|
uint32_t addr;
|
|
|
|
while (mach64->context_load_cntl & 0x30000)
|
|
{
|
|
addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask;
|
|
mach64->context_mask = *(uint32_t *)&svga->vram[addr];
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_load_context %08X from %08X : mask %08X\n", mach64->context_load_cntl, addr, mach64->context_mask);
|
|
#endif
|
|
|
|
if (mach64->context_mask & (1 << 2))
|
|
mach64_accel_write_fifo_l(mach64, 0x100, *(uint32_t *)&svga->vram[addr + 0x08]);
|
|
if (mach64->context_mask & (1 << 3))
|
|
mach64_accel_write_fifo_l(mach64, 0x10c, *(uint32_t *)&svga->vram[addr + 0x0c]);
|
|
if (mach64->context_mask & (1 << 4))
|
|
mach64_accel_write_fifo_l(mach64, 0x118, *(uint32_t *)&svga->vram[addr + 0x10]);
|
|
if (mach64->context_mask & (1 << 5))
|
|
mach64_accel_write_fifo_l(mach64, 0x124, *(uint32_t *)&svga->vram[addr + 0x14]);
|
|
if (mach64->context_mask & (1 << 6))
|
|
mach64_accel_write_fifo_l(mach64, 0x128, *(uint32_t *)&svga->vram[addr + 0x18]);
|
|
if (mach64->context_mask & (1 << 7))
|
|
mach64_accel_write_fifo_l(mach64, 0x12c, *(uint32_t *)&svga->vram[addr + 0x1c]);
|
|
if (mach64->context_mask & (1 << 8))
|
|
mach64_accel_write_fifo_l(mach64, 0x180, *(uint32_t *)&svga->vram[addr + 0x20]);
|
|
if (mach64->context_mask & (1 << 9))
|
|
mach64_accel_write_fifo_l(mach64, 0x18c, *(uint32_t *)&svga->vram[addr + 0x24]);
|
|
if (mach64->context_mask & (1 << 10))
|
|
mach64_accel_write_fifo_l(mach64, 0x198, *(uint32_t *)&svga->vram[addr + 0x28]);
|
|
if (mach64->context_mask & (1 << 11))
|
|
mach64_accel_write_fifo_l(mach64, 0x1a4, *(uint32_t *)&svga->vram[addr + 0x2c]);
|
|
if (mach64->context_mask & (1 << 12))
|
|
mach64_accel_write_fifo_l(mach64, 0x1b0, *(uint32_t *)&svga->vram[addr + 0x30]);
|
|
if (mach64->context_mask & (1 << 13))
|
|
mach64_accel_write_fifo_l(mach64, 0x280, *(uint32_t *)&svga->vram[addr + 0x34]);
|
|
if (mach64->context_mask & (1 << 14))
|
|
mach64_accel_write_fifo_l(mach64, 0x284, *(uint32_t *)&svga->vram[addr + 0x38]);
|
|
if (mach64->context_mask & (1 << 15))
|
|
mach64_accel_write_fifo_l(mach64, 0x2a8, *(uint32_t *)&svga->vram[addr + 0x3c]);
|
|
if (mach64->context_mask & (1 << 16))
|
|
mach64_accel_write_fifo_l(mach64, 0x2b4, *(uint32_t *)&svga->vram[addr + 0x40]);
|
|
if (mach64->context_mask & (1 << 17))
|
|
mach64_accel_write_fifo_l(mach64, 0x2c0, *(uint32_t *)&svga->vram[addr + 0x44]);
|
|
if (mach64->context_mask & (1 << 18))
|
|
mach64_accel_write_fifo_l(mach64, 0x2c4, *(uint32_t *)&svga->vram[addr + 0x48]);
|
|
if (mach64->context_mask & (1 << 19))
|
|
mach64_accel_write_fifo_l(mach64, 0x2c8, *(uint32_t *)&svga->vram[addr + 0x4c]);
|
|
if (mach64->context_mask & (1 << 20))
|
|
mach64_accel_write_fifo_l(mach64, 0x2cc, *(uint32_t *)&svga->vram[addr + 0x50]);
|
|
if (mach64->context_mask & (1 << 21))
|
|
mach64_accel_write_fifo_l(mach64, 0x2d0, *(uint32_t *)&svga->vram[addr + 0x54]);
|
|
if (mach64->context_mask & (1 << 22))
|
|
mach64_accel_write_fifo_l(mach64, 0x2d4, *(uint32_t *)&svga->vram[addr + 0x58]);
|
|
if (mach64->context_mask & (1 << 23))
|
|
mach64_accel_write_fifo_l(mach64, 0x2d8, *(uint32_t *)&svga->vram[addr + 0x5c]);
|
|
if (mach64->context_mask & (1 << 24))
|
|
mach64_accel_write_fifo_l(mach64, 0x300, *(uint32_t *)&svga->vram[addr + 0x60]);
|
|
if (mach64->context_mask & (1 << 25))
|
|
mach64_accel_write_fifo_l(mach64, 0x304, *(uint32_t *)&svga->vram[addr + 0x64]);
|
|
if (mach64->context_mask & (1 << 26))
|
|
mach64_accel_write_fifo_l(mach64, 0x308, *(uint32_t *)&svga->vram[addr + 0x68]);
|
|
if (mach64->context_mask & (1 << 27))
|
|
mach64_accel_write_fifo_l(mach64, 0x330, *(uint32_t *)&svga->vram[addr + 0x6c]);
|
|
|
|
mach64->context_load_cntl = *(uint32_t *)&svga->vram[addr + 0x70];
|
|
}
|
|
}
|
|
|
|
#define PLL_REF_DIV 0x2
|
|
#define VCLK_POST_DIV 0x6
|
|
#define VCLK0_FB_DIV 0x7
|
|
|
|
static void pll_write(mach64_t *mach64, uint32_t addr, uint8_t val)
|
|
{
|
|
int c;
|
|
|
|
switch (addr & 3)
|
|
{
|
|
case 0: /*Clock sel*/
|
|
break;
|
|
case 1: /*Addr*/
|
|
mach64->pll_addr = (val >> 2) & 0xf;
|
|
break;
|
|
case 2: /*Data*/
|
|
mach64->pll_regs[mach64->pll_addr] = val;
|
|
/* pclog("pll_write %02x,%02x\n", mach64->pll_addr, val); */
|
|
|
|
for (c = 0; c < 4; c++)
|
|
{
|
|
double m = (double)mach64->pll_regs[PLL_REF_DIV];
|
|
double n = (double)mach64->pll_regs[VCLK0_FB_DIV+c];
|
|
double r = 14318184.0;
|
|
double p = (double)(1 << ((mach64->pll_regs[VCLK_POST_DIV] >> (c*2)) & 3));
|
|
|
|
/* pclog("PLLfreq %i = %g %g m=%02x n=%02x p=%02x\n", c, (2.0 * r * n) / (m * p), p, mach64->pll_regs[PLL_REF_DIV], mach64->pll_regs[VCLK0_FB_DIV+c], mach64->pll_regs[VCLK_POST_DIV]); */
|
|
mach64->pll_freq[c] = (2.0 * r * n) / (m * p);
|
|
/* pclog(" %g\n", mach64->pll_freq[c]); */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define OVERLAY_EN (1 << 30)
|
|
static void mach64_vblank_start(svga_t *svga)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)svga->p;
|
|
int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf;
|
|
|
|
mach64->crtc_int_cntl |= 4;
|
|
mach64_update_irqs(mach64);
|
|
|
|
svga->overlay.x = (mach64->overlay_y_x_start >> 16) & 0x7ff;
|
|
svga->overlay.y = mach64->overlay_y_x_start & 0x7ff;
|
|
|
|
svga->overlay.xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x;
|
|
svga->overlay.ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y;
|
|
|
|
svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8;
|
|
svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff;
|
|
|
|
svga->overlay.ena = (mach64->overlay_scale_cntl & OVERLAY_EN) && (overlay_cmp_mix != 1);
|
|
|
|
mach64->overlay_v_acc = 0;
|
|
mach64->scaler_update = 1;
|
|
}
|
|
|
|
uint8_t mach64_ext_readb(uint32_t addr, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
uint8_t ret;
|
|
if (!(addr & 0x400))
|
|
{
|
|
#ifdef MACH64_DEBUG
|
|
pclog("nmach64_ext_readb: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc);
|
|
#endif
|
|
switch (addr & 0x3ff)
|
|
{
|
|
case 0x00: case 0x01: case 0x02: case 0x03:
|
|
READ8(addr, mach64->overlay_y_x_start);
|
|
break;
|
|
case 0x04: case 0x05: case 0x06: case 0x07:
|
|
READ8(addr, mach64->overlay_y_x_end);
|
|
break;
|
|
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
|
READ8(addr, mach64->overlay_video_key_clr);
|
|
break;
|
|
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
|
READ8(addr, mach64->overlay_video_key_msk);
|
|
break;
|
|
case 0x10: case 0x11: case 0x12: case 0x13:
|
|
READ8(addr, mach64->overlay_graphics_key_clr);
|
|
break;
|
|
case 0x14: case 0x15: case 0x16: case 0x17:
|
|
READ8(addr, mach64->overlay_graphics_key_msk);
|
|
break;
|
|
case 0x18: case 0x19: case 0x1a: case 0x1b:
|
|
READ8(addr, mach64->overlay_key_cntl);
|
|
break;
|
|
|
|
case 0x20: case 0x21: case 0x22: case 0x23:
|
|
READ8(addr, mach64->overlay_scale_inc);
|
|
break;
|
|
case 0x24: case 0x25: case 0x26: case 0x27:
|
|
READ8(addr, mach64->overlay_scale_cntl);
|
|
break;
|
|
case 0x28: case 0x29: case 0x2a: case 0x2b:
|
|
READ8(addr, mach64->scaler_height_width);
|
|
break;
|
|
|
|
case 0x4a:
|
|
ret = mach64->scaler_format;
|
|
break;
|
|
|
|
default:
|
|
ret = 0xff;
|
|
break;
|
|
}
|
|
}
|
|
else switch (addr & 0x3ff)
|
|
{
|
|
case 0x00: case 0x01: case 0x02: case 0x03:
|
|
READ8(addr, mach64->crtc_h_total_disp);
|
|
break;
|
|
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
|
READ8(addr, mach64->crtc_v_total_disp);
|
|
break;
|
|
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
|
READ8(addr, mach64->crtc_v_sync_strt_wid);
|
|
break;
|
|
|
|
case 0x12: case 0x13:
|
|
READ8(addr - 2, mach64->svga.vc);
|
|
break;
|
|
|
|
case 0x14: case 0x15: case 0x16: case 0x17:
|
|
READ8(addr, mach64->crtc_off_pitch);
|
|
break;
|
|
|
|
case 0x18:
|
|
ret = mach64->crtc_int_cntl & ~1;
|
|
if (mach64->svga.cgastat & 8)
|
|
ret |= 1;
|
|
break;
|
|
|
|
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
|
READ8(addr, mach64->crtc_gen_cntl);
|
|
break;
|
|
|
|
case 0x40: case 0x41: case 0x42: case 0x43:
|
|
READ8(addr, mach64->ovr_clr);
|
|
break;
|
|
case 0x44: case 0x45: case 0x46: case 0x47:
|
|
READ8(addr, mach64->ovr_wid_left_right);
|
|
break;
|
|
case 0x48: case 0x49: case 0x4a: case 0x4b:
|
|
READ8(addr, mach64->ovr_wid_top_bottom);
|
|
break;
|
|
|
|
case 0x60: case 0x61: case 0x62: case 0x63:
|
|
READ8(addr, mach64->cur_clr0);
|
|
break;
|
|
case 0x64: case 0x65: case 0x66: case 0x67:
|
|
READ8(addr, mach64->cur_clr1);
|
|
break;
|
|
case 0x68: case 0x69: case 0x6a: case 0x6b:
|
|
READ8(addr, mach64->cur_offset);
|
|
break;
|
|
case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
|
READ8(addr, mach64->cur_horz_vert_posn);
|
|
break;
|
|
case 0x70: case 0x71: case 0x72: case 0x73:
|
|
READ8(addr, mach64->cur_horz_vert_off);
|
|
break;
|
|
|
|
case 0x79:
|
|
ret = 0x30;
|
|
break;
|
|
|
|
case 0x80: case 0x81: case 0x82: case 0x83:
|
|
READ8(addr, mach64->scratch_reg0);
|
|
break;
|
|
case 0x84: case 0x85: case 0x86: case 0x87:
|
|
READ8(addr, mach64->scratch_reg1);
|
|
break;
|
|
|
|
case 0x90: case 0x91: case 0x92: case 0x93:
|
|
READ8(addr, mach64->clock_cntl);
|
|
break;
|
|
|
|
case 0xb0: case 0xb1: case 0xb2: case 0xb3:
|
|
READ8(addr, mach64->mem_cntl);
|
|
break;
|
|
|
|
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
|
if (mach64->type == MACH64_GX)
|
|
ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga);
|
|
else
|
|
ret = ati68860_ramdac_in(addr & 3, &mach64->ramdac, &mach64->svga);
|
|
break;
|
|
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
|
if (mach64->type == MACH64_VT2)
|
|
mach64->dac_cntl |= (4 << 24);
|
|
READ8(addr, mach64->dac_cntl);
|
|
break;
|
|
|
|
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
|
READ8(addr, mach64->gen_test_cntl);
|
|
break;
|
|
|
|
case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
|
if (mach64->type == MACH64_GX)
|
|
mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4);
|
|
else
|
|
mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 24) << 4);
|
|
READ8(addr, mach64->config_cntl);
|
|
break;
|
|
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
|
READ8(addr, mach64->config_chip_id);
|
|
break;
|
|
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
|
READ8(addr, mach64->config_stat0);
|
|
break;
|
|
|
|
case 0x100: case 0x101: case 0x102: case 0x103:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_off_pitch);
|
|
break;
|
|
case 0x104: case 0x105:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_y_x);
|
|
break;
|
|
case 0x108: case 0x109: case 0x11c: case 0x11d:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr + 2, mach64->dst_y_x);
|
|
break;
|
|
case 0x10c: case 0x10d: case 0x10e: case 0x10f:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_y_x);
|
|
break;
|
|
case 0x110: case 0x111:
|
|
addr += 2;
|
|
case 0x114: case 0x115:
|
|
case 0x118: case 0x119: case 0x11a: case 0x11b:
|
|
case 0x11e: case 0x11f:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_height_width);
|
|
break;
|
|
|
|
case 0x120: case 0x121: case 0x122: case 0x123:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_bres_lnth);
|
|
break;
|
|
case 0x124: case 0x125: case 0x126: case 0x127:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_bres_err);
|
|
break;
|
|
case 0x128: case 0x129: case 0x12a: case 0x12b:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_bres_inc);
|
|
break;
|
|
case 0x12c: case 0x12d: case 0x12e: case 0x12f:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_bres_dec);
|
|
break;
|
|
|
|
case 0x130: case 0x131: case 0x132: case 0x133:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_cntl);
|
|
break;
|
|
|
|
case 0x180: case 0x181: case 0x182: case 0x183:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_off_pitch);
|
|
break;
|
|
case 0x184: case 0x185:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_y_x);
|
|
break;
|
|
case 0x188: case 0x189:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr + 2, mach64->src_y_x);
|
|
break;
|
|
case 0x18c: case 0x18d: case 0x18e: case 0x18f:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_y_x);
|
|
break;
|
|
case 0x190: case 0x191:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr + 2, mach64->src_height1_width1);
|
|
break;
|
|
case 0x194: case 0x195:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_height1_width1);
|
|
break;
|
|
case 0x198: case 0x199: case 0x19a: case 0x19b:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_height1_width1);
|
|
break;
|
|
case 0x19c: case 0x19d:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_y_x_start);
|
|
break;
|
|
case 0x1a0: case 0x1a1:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr + 2, mach64->src_y_x_start);
|
|
break;
|
|
case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_y_x_start);
|
|
break;
|
|
case 0x1a8: case 0x1a9:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr + 2, mach64->src_height2_width2);
|
|
break;
|
|
case 0x1ac: case 0x1ad:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_height2_width2);
|
|
break;
|
|
case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_height2_width2);
|
|
break;
|
|
|
|
case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->src_cntl);
|
|
break;
|
|
|
|
case 0x240: case 0x241: case 0x242: case 0x243:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->host_cntl);
|
|
break;
|
|
|
|
case 0x280: case 0x281: case 0x282: case 0x283:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->pat_reg0);
|
|
break;
|
|
case 0x284: case 0x285: case 0x286: case 0x287:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->pat_reg1);
|
|
break;
|
|
|
|
case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->sc_left_right);
|
|
break;
|
|
case 0x2a4: case 0x2a5:
|
|
addr += 2;
|
|
case 0x2aa: case 0x2ab:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->sc_left_right);
|
|
break;
|
|
|
|
case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->sc_top_bottom);
|
|
break;
|
|
case 0x2b0: case 0x2b1:
|
|
addr += 2;
|
|
case 0x2b6: case 0x2b7:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->sc_top_bottom);
|
|
break;
|
|
|
|
case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dp_bkgd_clr);
|
|
break;
|
|
case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dp_frgd_clr);
|
|
break;
|
|
|
|
case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dp_pix_width);
|
|
break;
|
|
case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dp_mix);
|
|
break;
|
|
case 0x2d8: case 0x2d9: case 0x2da: case 0x2db:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dp_src);
|
|
break;
|
|
|
|
case 0x300: case 0x301: case 0x302: case 0x303:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->clr_cmp_clr);
|
|
break;
|
|
case 0x304: case 0x305: case 0x306: case 0x307:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->clr_cmp_mask);
|
|
break;
|
|
case 0x308: case 0x309: case 0x30a: case 0x30b:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->clr_cmp_cntl);
|
|
break;
|
|
|
|
case 0x310: case 0x311:
|
|
if (!FIFO_EMPTY)
|
|
wake_fifo_thread(mach64);
|
|
ret = 0;
|
|
if (FIFO_FULL)
|
|
ret = 0xff;
|
|
break;
|
|
|
|
case 0x320: case 0x321: case 0x322: case 0x323:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->context_mask);
|
|
break;
|
|
|
|
case 0x330: case 0x331:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr, mach64->dst_cntl);
|
|
break;
|
|
case 0x332:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr - 2, mach64->src_cntl);
|
|
break;
|
|
case 0x333:
|
|
mach64_wait_fifo_idle(mach64);
|
|
READ8(addr - 3, mach64->pat_cntl);
|
|
break;
|
|
|
|
case 0x338:
|
|
/* if (!FIFO_EMPTY)
|
|
wake_fifo_thread(mach64);*/
|
|
ret = FIFO_EMPTY ? 0 : 1;
|
|
break;
|
|
|
|
default:
|
|
ret = 0;
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readb : addr %08X ret %02X\n", addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
uint16_t mach64_ext_readw(uint32_t addr, void *p)
|
|
{
|
|
uint16_t ret;
|
|
if (!(addr & 0x400))
|
|
{
|
|
#ifdef MACH64_DEBUG
|
|
pclog("nmach64_ext_readw: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc);
|
|
#endif
|
|
ret = 0xffff;
|
|
}
|
|
else switch (addr & 0x3ff)
|
|
{
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret = mach64_ext_readb(addr, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret |= mach64_ext_readb(addr + 1, p) << 8;
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readw : addr %08X ret %04X\n", addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
uint32_t mach64_ext_readl(uint32_t addr, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
uint32_t ret;
|
|
if (!(addr & 0x400))
|
|
{
|
|
#ifdef MACH64_DEBUG
|
|
pclog("nmach64_ext_readl: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc);
|
|
#endif
|
|
ret = 0xffffffff;
|
|
}
|
|
else switch (addr & 0x3ff)
|
|
{
|
|
case 0x18:
|
|
ret = mach64->crtc_int_cntl & ~1;
|
|
if (mach64->svga.cgastat & 8)
|
|
ret |= 1;
|
|
break;
|
|
|
|
case 0xb4:
|
|
ret = (mach64->bank_w[0] >> 15) | ((mach64->bank_w[1] >> 15) << 16);
|
|
break;
|
|
case 0xb8:
|
|
ret = (mach64->bank_r[0] >> 15) | ((mach64->bank_r[1] >> 15) << 16);
|
|
break;
|
|
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret = mach64_ext_readw(addr, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret |= mach64_ext_readw(addr + 2, p) << 16;
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readl : addr %08X ret %08X\n", addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
svga_t *svga = &mach64->svga;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_ext_writeb : addr %08X val %02X %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc);
|
|
#endif
|
|
if (!(addr & 0x400))
|
|
{
|
|
switch (addr & 0x3ff)
|
|
{
|
|
case 0x00: case 0x01: case 0x02: case 0x03:
|
|
WRITE8(addr, mach64->overlay_y_x_start, val);
|
|
break;
|
|
case 0x04: case 0x05: case 0x06: case 0x07:
|
|
WRITE8(addr, mach64->overlay_y_x_end, val);
|
|
break;
|
|
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
|
WRITE8(addr, mach64->overlay_video_key_clr, val);
|
|
break;
|
|
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
|
WRITE8(addr, mach64->overlay_video_key_msk, val);
|
|
break;
|
|
case 0x10: case 0x11: case 0x12: case 0x13:
|
|
WRITE8(addr, mach64->overlay_graphics_key_clr, val);
|
|
break;
|
|
case 0x14: case 0x15: case 0x16: case 0x17:
|
|
WRITE8(addr, mach64->overlay_graphics_key_msk, val);
|
|
break;
|
|
case 0x18: case 0x19: case 0x1a: case 0x1b:
|
|
WRITE8(addr, mach64->overlay_key_cntl, val);
|
|
break;
|
|
|
|
case 0x20: case 0x21: case 0x22: case 0x23:
|
|
WRITE8(addr, mach64->overlay_scale_inc, val);
|
|
break;
|
|
case 0x24: case 0x25: case 0x26: case 0x27:
|
|
WRITE8(addr, mach64->overlay_scale_cntl, val);
|
|
break;
|
|
case 0x28: case 0x29: case 0x2a: case 0x2b:
|
|
WRITE8(addr, mach64->scaler_height_width, val);
|
|
break;
|
|
|
|
case 0x4a:
|
|
mach64->scaler_format = val & 0xf;
|
|
break;
|
|
|
|
case 0x80: case 0x81: case 0x82: case 0x83:
|
|
WRITE8(addr, mach64->buf_offset[0], val);
|
|
break;
|
|
|
|
case 0x8c: case 0x8d: case 0x8e: case 0x8f:
|
|
WRITE8(addr, mach64->buf_pitch[0], val);
|
|
break;
|
|
|
|
case 0x98: case 0x99: case 0x9a: case 0x9b:
|
|
WRITE8(addr, mach64->buf_offset[1], val);
|
|
break;
|
|
|
|
case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
|
WRITE8(addr, mach64->buf_pitch[1], val);
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
pclog("nmach64_ext_writeb: addr=%04x val=%02x\n", addr, val);
|
|
#endif
|
|
}
|
|
else if (addr & 0x300)
|
|
{
|
|
mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE);
|
|
}
|
|
else switch (addr & 0x3ff)
|
|
{
|
|
case 0x00: case 0x01: case 0x02: case 0x03:
|
|
WRITE8(addr, mach64->crtc_h_total_disp, val);
|
|
svga_recalctimings(&mach64->svga);
|
|
break;
|
|
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
|
WRITE8(addr, mach64->crtc_v_total_disp, val);
|
|
svga_recalctimings(&mach64->svga);
|
|
break;
|
|
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
|
WRITE8(addr, mach64->crtc_v_sync_strt_wid, val);
|
|
svga_recalctimings(&mach64->svga);
|
|
break;
|
|
|
|
case 0x14: case 0x15: case 0x16: case 0x17:
|
|
WRITE8(addr, mach64->crtc_off_pitch, val);
|
|
svga_recalctimings(&mach64->svga);
|
|
svga->fullchange = changeframecount;
|
|
break;
|
|
|
|
case 0x18:
|
|
mach64->crtc_int_cntl = (mach64->crtc_int_cntl & 0x75) | (val & ~0x75);
|
|
if (val & 4)
|
|
mach64->crtc_int_cntl &= ~4;
|
|
mach64_update_irqs(mach64);
|
|
break;
|
|
|
|
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
|
WRITE8(addr, mach64->crtc_gen_cntl, val);
|
|
if (((mach64->crtc_gen_cntl >> 24) & 3) == 3)
|
|
svga->fb_only = 1;
|
|
else
|
|
svga->fb_only = 0;
|
|
svga_recalctimings(&mach64->svga);
|
|
break;
|
|
|
|
case 0x40: case 0x41: case 0x42: case 0x43:
|
|
WRITE8(addr, mach64->ovr_clr, val);
|
|
break;
|
|
case 0x44: case 0x45: case 0x46: case 0x47:
|
|
WRITE8(addr, mach64->ovr_wid_left_right, val);
|
|
break;
|
|
case 0x48: case 0x49: case 0x4a: case 0x4b:
|
|
WRITE8(addr, mach64->ovr_wid_top_bottom, val);
|
|
break;
|
|
|
|
case 0x60: case 0x61: case 0x62: case 0x63:
|
|
WRITE8(addr, mach64->cur_clr0, val);
|
|
if (mach64->type == MACH64_VT2)
|
|
mach64->ramdac.pallook[0] = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff);
|
|
break;
|
|
case 0x64: case 0x65: case 0x66: case 0x67:
|
|
WRITE8(addr, mach64->cur_clr1, val);
|
|
if (mach64->type == MACH64_VT2)
|
|
mach64->ramdac.pallook[1] = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff);
|
|
break;
|
|
case 0x68: case 0x69: case 0x6a: case 0x6b:
|
|
WRITE8(addr, mach64->cur_offset, val);
|
|
svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8;
|
|
mach64_cursor_dump(mach64);
|
|
break;
|
|
case 0x6c: case 0x6d: case 0x6e: case 0x6f:
|
|
WRITE8(addr, mach64->cur_horz_vert_posn, val);
|
|
svga->hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff;
|
|
svga->hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff;
|
|
mach64_cursor_dump(mach64);
|
|
break;
|
|
case 0x70: case 0x71: case 0x72: case 0x73:
|
|
WRITE8(addr, mach64->cur_horz_vert_off, val);
|
|
svga->hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f;
|
|
svga->hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f;
|
|
mach64_cursor_dump(mach64);
|
|
break;
|
|
|
|
case 0x80: case 0x81: case 0x82: case 0x83:
|
|
WRITE8(addr, mach64->scratch_reg0, val);
|
|
break;
|
|
case 0x84: case 0x85: case 0x86: case 0x87:
|
|
WRITE8(addr, mach64->scratch_reg1, val);
|
|
break;
|
|
|
|
case 0x90: case 0x91: case 0x92: case 0x93:
|
|
WRITE8(addr, mach64->clock_cntl, val);
|
|
if (mach64->type == MACH64_GX)
|
|
ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf);
|
|
else
|
|
{
|
|
pll_write(mach64, addr, val);
|
|
mach64->ics2595.output_clock = mach64->pll_freq[mach64->clock_cntl & 3];
|
|
}
|
|
svga_recalctimings(&mach64->svga);
|
|
break;
|
|
|
|
case 0xb0: case 0xb1: case 0xb2: case 0xb3:
|
|
WRITE8(addr, mach64->mem_cntl, val);
|
|
break;
|
|
|
|
case 0xb4:
|
|
mach64->bank_w[0] = val * 32768;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64 : write bank A0000-A7FFF set to %08X\n", mach64->bank_w[0]);
|
|
#endif
|
|
break;
|
|
case 0xb5: case 0xb6:
|
|
mach64->bank_w[1] = val * 32768;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64 : write bank A8000-AFFFF set to %08X\n", mach64->bank_w[1]);
|
|
#endif
|
|
break;
|
|
case 0xb8:
|
|
mach64->bank_r[0] = val * 32768;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64 : read bank A0000-A7FFF set to %08X\n", mach64->bank_r[0]);
|
|
#endif
|
|
break;
|
|
case 0xb9: case 0xba:
|
|
mach64->bank_r[1] = val * 32768;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64 : read bank A8000-AFFFF set to %08X\n", mach64->bank_r[1]);
|
|
#endif
|
|
break;
|
|
|
|
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
|
if (mach64->type == MACH64_GX)
|
|
ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga);
|
|
else
|
|
ati68860_ramdac_out(addr & 3, val, &mach64->ramdac, &mach64->svga);
|
|
break;
|
|
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
|
WRITE8(addr, mach64->dac_cntl, val);
|
|
svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT);
|
|
ati68860_set_ramdac_type(&mach64->ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT);
|
|
break;
|
|
|
|
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
|
WRITE8(addr, mach64->gen_test_cntl, val);
|
|
ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1);
|
|
mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0);
|
|
svga->hwcursor.ena = mach64->gen_test_cntl & 0x80;
|
|
mach64_cursor_dump(mach64);
|
|
break;
|
|
|
|
case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
|
WRITE8(addr, mach64->config_cntl, val);
|
|
mach64_updatemapping(mach64);
|
|
break;
|
|
|
|
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
|
if (mach64->type != MACH64_GX)
|
|
WRITE8(addr, mach64->config_stat0, val);
|
|
break;
|
|
}
|
|
}
|
|
void mach64_ext_writew(uint32_t addr, uint16_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_ext_writew : addr %08X val %04X\n", addr, val);
|
|
#endif
|
|
if (!(addr & 0x400))
|
|
{
|
|
#ifdef MACH64_DEBUG
|
|
pclog("nmach64_ext_writew: addr=%04x val=%04x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc);
|
|
#endif
|
|
mach64_ext_writeb(addr, val, p);
|
|
mach64_ext_writeb(addr + 1, val >> 8, p);
|
|
}
|
|
else if (addr & 0x300)
|
|
{
|
|
mach64_queue(mach64, addr & 0x3fe, val, FIFO_WRITE_WORD);
|
|
}
|
|
else switch (addr & 0x3fe)
|
|
{
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_writeb(addr, val, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_writeb(addr + 1, val >> 8, p);
|
|
break;
|
|
}
|
|
}
|
|
void mach64_ext_writel(uint32_t addr, uint32_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
#ifdef MACH64_DEBUG
|
|
if ((addr & 0x3c0) != 0x200)
|
|
pclog("mach64_ext_writel : addr %08X val %08X\n", addr, val);
|
|
#endif
|
|
if (!(addr & 0x400))
|
|
{
|
|
#ifdef MACH64_DEBUG
|
|
pclog("nmach64_ext_writel: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc);
|
|
#endif
|
|
mach64_ext_writew(addr, val, p);
|
|
mach64_ext_writew(addr + 2, val >> 16, p);
|
|
}
|
|
else if (addr & 0x300)
|
|
{
|
|
mach64_queue(mach64, addr & 0x3fc, val, FIFO_WRITE_DWORD);
|
|
}
|
|
else switch (addr & 0x3fc)
|
|
{
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_writew(addr, val, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_writew(addr + 2, val >> 16, p);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint8_t mach64_ext_inb(uint16_t port, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
uint8_t ret;
|
|
switch (port)
|
|
{
|
|
case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef:
|
|
case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef:
|
|
ret = mach64_ext_readb(0x400 | 0x00 | (port & 3), p);
|
|
break;
|
|
case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef:
|
|
ret = mach64_ext_readb(0x400 | 0x08 | (port & 3), p);
|
|
break;
|
|
case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef:
|
|
ret = mach64_ext_readb(0x400 | 0x0c | (port & 3), p);
|
|
break;
|
|
|
|
case 0x12ec: case 0x12ed: case 0x12ee: case 0x12ef:
|
|
ret = mach64_ext_readb(0x400 | 0x10 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef:
|
|
ret = mach64_ext_readb(0x400 | 0x14 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x1aec:
|
|
ret = mach64_ext_readb(0x400 | 0x18, p);
|
|
break;
|
|
|
|
case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef:
|
|
ret = mach64_ext_readb(0x400 | 0x1c | (port & 3), p);
|
|
break;
|
|
|
|
case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef:
|
|
ret = mach64_ext_readb(0x400 | 0x40 | (port & 3), p);
|
|
break;
|
|
case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef:
|
|
ret = mach64_ext_readb(0x400 | 0x44 | (port & 3), p);
|
|
break;
|
|
case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef:
|
|
ret = mach64_ext_readb(0x400 | 0x48 | (port & 3), p);
|
|
break;
|
|
case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef:
|
|
ret = mach64_ext_readb(0x400 | 0x60 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef:
|
|
ret = mach64_ext_readb(0x400 | 0x64 | (port & 3), p);
|
|
break;
|
|
case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef:
|
|
ret = mach64_ext_readb(0x400 | 0x68 | (port & 3), p);
|
|
break;
|
|
case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef:
|
|
ret = mach64_ext_readb(0x400 | 0x6c | (port & 3), p);
|
|
break;
|
|
case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef:
|
|
ret = mach64_ext_readb(0x400 | 0x70 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef:
|
|
ret = mach64_ext_readb(0x400 | 0x80 | (port & 3), p);
|
|
break;
|
|
case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef:
|
|
ret = mach64_ext_readb(0x400 | 0x84 | (port & 3), p);
|
|
break;
|
|
case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef:
|
|
ret = mach64_ext_readb(0x400 | 0x90 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef:
|
|
ret = mach64_ext_readb(0x400 | 0xb0 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x56ec:
|
|
ret = mach64_ext_readb(0x400 | 0xb4, p);
|
|
break;
|
|
case 0x56ed: case 0x56ee:
|
|
ret = mach64_ext_readb(0x400 | 0xb5, p);
|
|
break;
|
|
case 0x5aec:
|
|
ret = mach64_ext_readb(0x400 | 0xb8, p);
|
|
break;
|
|
case 0x5aed: case 0x5aee:
|
|
ret = mach64_ext_readb(0x400 | 0xb9, p);
|
|
break;
|
|
|
|
case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef:
|
|
if (mach64->type == MACH64_GX)
|
|
ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga);
|
|
else
|
|
ret = ati68860_ramdac_in(port & 3, &mach64->ramdac, &mach64->svga);
|
|
break;
|
|
|
|
case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef:
|
|
ret = mach64_ext_readb(0x400 | 0xc4 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef:
|
|
ret = mach64_ext_readb(0x400 | 0xd0 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef:
|
|
mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4);
|
|
READ8(port, mach64->config_cntl);
|
|
break;
|
|
|
|
case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef:
|
|
ret = mach64_ext_readb(0x400 | 0xe0 | (port & 3), p);
|
|
break;
|
|
|
|
case 0x72ec: case 0x72ed: case 0x72ee: case 0x72ef:
|
|
ret = mach64_ext_readb(0x400 | 0xe4 | (port & 3), p);
|
|
break;
|
|
|
|
default:
|
|
ret = 0;
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_ext_inb : port %04X ret %02X %04X:%04X\n", port, ret, CS,cpu_state.pc);
|
|
#endif
|
|
return ret;
|
|
}
|
|
uint16_t mach64_ext_inw(uint16_t port, void *p)
|
|
{
|
|
uint16_t ret;
|
|
switch (port)
|
|
{
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret = mach64_ext_inb(port, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret |= (mach64_ext_inb(port + 1, p) << 8);
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_ext_inw : port %04X ret %04X\n", port, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
uint32_t mach64_ext_inl(uint16_t port, void *p)
|
|
{
|
|
uint32_t ret;
|
|
switch (port)
|
|
{
|
|
case 0x56ec:
|
|
ret = mach64_ext_readl(0x400 | 0xb4, p);
|
|
break;
|
|
case 0x5aec:
|
|
ret = mach64_ext_readl(0x400 | 0xb8, p);
|
|
break;
|
|
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret = mach64_ext_inw(port, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
ret |= (mach64_ext_inw(port + 2, p) << 16);
|
|
break;
|
|
}
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_ext_inl : port %04X ret %08X\n", port, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
void mach64_ext_outb(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_ext_outb : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc);
|
|
#endif
|
|
switch (port)
|
|
{
|
|
case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef:
|
|
case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef:
|
|
mach64_ext_writeb(0x400 | 0x00 | (port & 3), val, p);
|
|
break;
|
|
case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef:
|
|
mach64_ext_writeb(0x400 | 0x08 | (port & 3), val, p);
|
|
break;
|
|
case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef:
|
|
mach64_ext_writeb(0x400 | 0x0c | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef:
|
|
mach64_ext_writeb(0x400 | 0x14 | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x1aec:
|
|
mach64_ext_writeb(0x400 | 0x18, val, p);
|
|
break;
|
|
|
|
case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef:
|
|
mach64_ext_writeb(0x400 | 0x1c | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef:
|
|
mach64_ext_writeb(0x400 | 0x40 | (port & 3), val, p);
|
|
break;
|
|
case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef:
|
|
mach64_ext_writeb(0x400 | 0x44 | (port & 3), val, p);
|
|
break;
|
|
case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef:
|
|
mach64_ext_writeb(0x400 | 0x48 | (port & 3), val, p);
|
|
break;
|
|
case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef:
|
|
mach64_ext_writeb(0x400 | 0x60 | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef:
|
|
mach64_ext_writeb(0x400 | 0x64 | (port & 3), val, p);
|
|
break;
|
|
case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef:
|
|
mach64_ext_writeb(0x400 | 0x68 | (port & 3), val, p);
|
|
break;
|
|
case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef:
|
|
mach64_ext_writeb(0x400 | 0x6c | (port & 3), val, p);
|
|
break;
|
|
case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef:
|
|
mach64_ext_writeb(0x400 | 0x70 | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef:
|
|
mach64_ext_writeb(0x400 | 0x80 | (port & 3), val, p);
|
|
break;
|
|
case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef:
|
|
mach64_ext_writeb(0x400 | 0x84 | (port & 3), val, p);
|
|
break;
|
|
case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef:
|
|
mach64_ext_writeb(0x400 | 0x90 | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef:
|
|
mach64_ext_writeb(0x400 | 0xb0 | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x56ec:
|
|
mach64_ext_writeb(0x400 | 0xb4, val, p);
|
|
break;
|
|
case 0x56ed: case 0x56ee:
|
|
mach64_ext_writeb(0x400 | 0xb5, val, p);
|
|
break;
|
|
case 0x5aec:
|
|
mach64_ext_writeb(0x400 | 0xb8, val, p);
|
|
break;
|
|
case 0x5aed: case 0x5aee:
|
|
mach64_ext_writeb(0x400 | 0xb9, val, p);
|
|
break;
|
|
|
|
case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef:
|
|
if (mach64->type == MACH64_GX)
|
|
ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga);
|
|
else
|
|
ati68860_ramdac_out(port & 3, val, &mach64->ramdac, &mach64->svga);
|
|
break;
|
|
|
|
case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef:
|
|
mach64_ext_writeb(0x400 | 0xc4 | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef:
|
|
mach64_ext_writeb(0x400 | 0xd0 | (port & 3), val, p);
|
|
break;
|
|
|
|
case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef:
|
|
WRITE8(port, mach64->config_cntl, val);
|
|
mach64_updatemapping(mach64);
|
|
break;
|
|
}
|
|
}
|
|
void mach64_ext_outw(uint16_t port, uint16_t val, void *p)
|
|
{
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_ext_outw : port %04X val %04X\n", port, val);
|
|
#endif
|
|
switch (port)
|
|
{
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_outb(port, val, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_outb(port + 1, val >> 8, p);
|
|
break;
|
|
}
|
|
}
|
|
void mach64_ext_outl(uint16_t port, uint32_t val, void *p)
|
|
{
|
|
/* pclog("mach64_ext_outl : port %04X val %08X\n", port, val); */
|
|
switch (port)
|
|
{
|
|
default:
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_outw(port, val, p);
|
|
#ifdef MACH64_DEBUG
|
|
pclog(" ");
|
|
#endif
|
|
mach64_ext_outw(port + 2, val >> 16, p);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint8_t mach64_block_inb(uint16_t port, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
uint8_t ret;
|
|
|
|
ret = mach64_ext_readb(0x400 | (port & 0x3ff), mach64);
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_block_inb : port %04X ret %02X %04x:%04x\n", port, ret, CS,cpu_state.pc);
|
|
#endif
|
|
return ret;
|
|
}
|
|
static uint16_t mach64_block_inw(uint16_t port, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
uint16_t ret;
|
|
|
|
ret = mach64_ext_readw(0x400 | (port & 0x3ff), mach64);
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_block_inw : port %04X ret %04X\n", port, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
static uint32_t mach64_block_inl(uint16_t port, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
uint32_t ret;
|
|
|
|
ret = mach64_ext_readl(0x400 | (port & 0x3ff), mach64);
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_block_inl : port %04X ret %08X\n", port, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static void mach64_block_outb(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_block_outb : port %04X val %02X\n ", port, val);
|
|
#endif
|
|
mach64_ext_writeb(0x400 | (port & 0x3ff), val, mach64);
|
|
}
|
|
static void mach64_block_outw(uint16_t port, uint16_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_block_outw : port %04X val %04X\n ", port, val);
|
|
#endif
|
|
mach64_ext_writew(0x400 | (port & 0x3ff), val, mach64);
|
|
}
|
|
static void mach64_block_outl(uint16_t port, uint32_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
#ifdef MACH64_DEBUG
|
|
pclog("mach64_block_outl : port %04X val %08X\n ", port, val);
|
|
#endif
|
|
mach64_ext_writel(0x400 | (port & 0x3ff), val, mach64);
|
|
}
|
|
|
|
void mach64_write(uint32_t addr, uint8_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
svga_t *svga = &mach64->svga;
|
|
addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1];
|
|
svga_write_linear(addr, val, svga);
|
|
}
|
|
|
|
uint8_t mach64_read(uint32_t addr, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
svga_t *svga = &mach64->svga;
|
|
uint8_t ret;
|
|
addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1];
|
|
ret = svga_read_linear(addr, svga);
|
|
return ret;
|
|
}
|
|
|
|
void mach64_hwcursor_draw(svga_t *svga, int displine)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)svga->p;
|
|
int x, offset;
|
|
uint8_t dat;
|
|
uint32_t col0 = mach64->ramdac.pallook[0];
|
|
uint32_t col1 = mach64->ramdac.pallook[1];
|
|
int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0;
|
|
int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0;
|
|
|
|
offset = svga->hwcursor_latch.xoff;
|
|
for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4)
|
|
{
|
|
dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)];
|
|
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0;
|
|
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF;
|
|
dat >>= 2;
|
|
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0;
|
|
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF;
|
|
dat >>= 2;
|
|
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0;
|
|
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF;
|
|
dat >>= 2;
|
|
if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0;
|
|
else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF;
|
|
dat >>= 2;
|
|
offset += 4;
|
|
}
|
|
svga->hwcursor_latch.addr += 16;
|
|
}
|
|
|
|
#define CLAMP(x) do \
|
|
{ \
|
|
if ((x) & ~0xff) \
|
|
x = ((x) < 0) ? 0 : 0xff; \
|
|
} \
|
|
while (0)
|
|
|
|
#define DECODE_ARGB1555() \
|
|
do \
|
|
{ \
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \
|
|
{ \
|
|
uint16_t dat = ((uint16_t *)src)[x]; \
|
|
\
|
|
int b = dat & 0x1f; \
|
|
int g = (dat >> 5) & 0x1f; \
|
|
int r = (dat >> 10) & 0x1f; \
|
|
\
|
|
b = (b << 3) | (b >> 2); \
|
|
g = (g << 3) | (g >> 2); \
|
|
r = (r << 3) | (r >> 2); \
|
|
\
|
|
mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define DECODE_RGB565() \
|
|
do \
|
|
{ \
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \
|
|
{ \
|
|
uint16_t dat = ((uint16_t *)src)[x]; \
|
|
\
|
|
int b = dat & 0x1f; \
|
|
int g = (dat >> 5) & 0x3f; \
|
|
int r = (dat >> 11) & 0x1f; \
|
|
\
|
|
b = (b << 3) | (b >> 2); \
|
|
g = (g << 2) | (g >> 4); \
|
|
r = (r << 3) | (r >> 2); \
|
|
\
|
|
mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define DECODE_ARGB8888() \
|
|
do \
|
|
{ \
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \
|
|
{ \
|
|
int b = src[0]; \
|
|
int g = src[1]; \
|
|
int r = src[2]; \
|
|
src += 4; \
|
|
\
|
|
mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define DECODE_VYUY422() \
|
|
do \
|
|
{ \
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \
|
|
{ \
|
|
uint8_t y1, y2; \
|
|
int8_t u, v; \
|
|
int dR, dG, dB; \
|
|
int r, g, b; \
|
|
\
|
|
y1 = src[0]; \
|
|
u = src[1] - 0x80; \
|
|
y2 = src[2]; \
|
|
v = src[3] - 0x80; \
|
|
src += 4; \
|
|
\
|
|
dR = (359*v) >> 8; \
|
|
dG = (88*u + 183*v) >> 8; \
|
|
dB = (453*u) >> 8; \
|
|
\
|
|
r = y1 + dR; \
|
|
CLAMP(r); \
|
|
g = y1 - dG; \
|
|
CLAMP(g); \
|
|
b = y1 + dB; \
|
|
CLAMP(b); \
|
|
mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \
|
|
\
|
|
r = y2 + dR; \
|
|
CLAMP(r); \
|
|
g = y2 - dG; \
|
|
CLAMP(g); \
|
|
b = y2 + dB; \
|
|
CLAMP(b); \
|
|
mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define DECODE_YVYU422() \
|
|
do \
|
|
{ \
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \
|
|
{ \
|
|
uint8_t y1, y2; \
|
|
int8_t u, v; \
|
|
int dR, dG, dB; \
|
|
int r, g, b; \
|
|
\
|
|
u = src[0] - 0x80; \
|
|
y1 = src[1]; \
|
|
v = src[2] - 0x80; \
|
|
y2 = src[3]; \
|
|
src += 4; \
|
|
\
|
|
dR = (359*v) >> 8; \
|
|
dG = (88*u + 183*v) >> 8; \
|
|
dB = (453*u) >> 8; \
|
|
\
|
|
r = y1 + dR; \
|
|
CLAMP(r); \
|
|
g = y1 - dG; \
|
|
CLAMP(g); \
|
|
b = y1 + dB; \
|
|
CLAMP(b); \
|
|
mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \
|
|
\
|
|
r = y2 + dR; \
|
|
CLAMP(r); \
|
|
g = y2 - dG; \
|
|
CLAMP(g); \
|
|
b = y2 + dB; \
|
|
CLAMP(b); \
|
|
mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \
|
|
} \
|
|
} while (0)
|
|
|
|
void mach64_overlay_draw(svga_t *svga, int displine)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)svga->p;
|
|
int x;
|
|
int h_acc = 0;
|
|
int h_max = (mach64->scaler_height_width >> 16) & 0x3ff;
|
|
int h_inc = mach64->overlay_scale_inc >> 16;
|
|
int v_max = mach64->scaler_height_width & 0x3ff;
|
|
int v_inc = mach64->overlay_scale_inc & 0xffff;
|
|
uint32_t *p;
|
|
uint8_t *src = &svga->vram[svga->overlay.addr];
|
|
int old_y = mach64->overlay_v_acc;
|
|
int y_diff;
|
|
int video_key_fn = mach64->overlay_key_cntl & 5;
|
|
int graphics_key_fn = (mach64->overlay_key_cntl >> 4) & 5;
|
|
int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf;
|
|
|
|
p = &((uint32_t *)buffer32->line[displine])[32 + mach64->svga.overlay_latch.x];
|
|
|
|
if (mach64->scaler_update)
|
|
{
|
|
switch (mach64->scaler_format)
|
|
{
|
|
case 0x3:
|
|
DECODE_ARGB1555();
|
|
break;
|
|
case 0x4:
|
|
DECODE_RGB565();
|
|
break;
|
|
case 0x6:
|
|
DECODE_ARGB8888();
|
|
break;
|
|
case 0xb:
|
|
DECODE_VYUY422();
|
|
break;
|
|
case 0xc:
|
|
DECODE_YVYU422();
|
|
break;
|
|
|
|
default:
|
|
/* pclog("Unknown Mach64 scaler format %x\n", mach64->scaler_format); */
|
|
/*Fill buffer with something recognisably wrong*/
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x++)
|
|
mach64->overlay_dat[x] = 0xff00ff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (overlay_cmp_mix == 2)
|
|
{
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x++)
|
|
{
|
|
int h = h_acc >> 12;
|
|
|
|
p[x] = mach64->overlay_dat[h];
|
|
|
|
h_acc += h_inc;
|
|
if (h_acc > (h_max << 12))
|
|
h_acc = (h_max << 12);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (x = 0; x < mach64->svga.overlay_latch.xsize; x++)
|
|
{
|
|
int h = h_acc >> 12;
|
|
int gr_cmp = 0, vid_cmp = 0;
|
|
int use_video = 0;
|
|
|
|
switch (video_key_fn)
|
|
{
|
|
case 0: vid_cmp = 0; break;
|
|
case 1: vid_cmp = 1; break;
|
|
case 4: vid_cmp = ((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break;
|
|
case 5: vid_cmp = !((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break;
|
|
}
|
|
switch (graphics_key_fn)
|
|
{
|
|
case 0: gr_cmp = 0; break;
|
|
case 1: gr_cmp = 1; break;
|
|
case 4: gr_cmp = (((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break;
|
|
case 5: gr_cmp = !(((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break;
|
|
}
|
|
vid_cmp = vid_cmp ? -1 : 0;
|
|
gr_cmp = gr_cmp ? -1 : 0;
|
|
|
|
switch (overlay_cmp_mix)
|
|
{
|
|
case 0x0: use_video = gr_cmp; break;
|
|
case 0x1: use_video = 0; break;
|
|
case 0x2: use_video = ~0; break;
|
|
case 0x3: use_video = ~gr_cmp; break;
|
|
case 0x4: use_video = ~vid_cmp; break;
|
|
case 0x5: use_video = gr_cmp ^ vid_cmp; break;
|
|
case 0x6: use_video = ~gr_cmp ^ vid_cmp; break;
|
|
case 0x7: use_video = vid_cmp; break;
|
|
case 0x8: use_video = ~gr_cmp | ~vid_cmp; break;
|
|
case 0x9: use_video = gr_cmp | ~vid_cmp; break;
|
|
case 0xa: use_video = ~gr_cmp | vid_cmp; break;
|
|
case 0xb: use_video = gr_cmp | vid_cmp; break;
|
|
case 0xc: use_video = gr_cmp & vid_cmp; break;
|
|
case 0xd: use_video = ~gr_cmp & vid_cmp; break;
|
|
case 0xe: use_video = gr_cmp & ~vid_cmp; break;
|
|
case 0xf: use_video = ~gr_cmp & ~vid_cmp; break;
|
|
}
|
|
|
|
if (use_video)
|
|
p[x] = mach64->overlay_dat[h];
|
|
|
|
h_acc += h_inc;
|
|
if (h_acc > (h_max << 12))
|
|
h_acc = (h_max << 12);
|
|
}
|
|
}
|
|
|
|
mach64->overlay_v_acc += v_inc;
|
|
if (mach64->overlay_v_acc > (v_max << 12))
|
|
mach64->overlay_v_acc = v_max << 12;
|
|
|
|
y_diff = (mach64->overlay_v_acc >> 12) - (old_y >> 12);
|
|
|
|
if (mach64->scaler_format == 6)
|
|
svga->overlay.addr += svga->overlay.pitch*4*y_diff;
|
|
else
|
|
svga->overlay.addr += svga->overlay.pitch*2*y_diff;
|
|
|
|
mach64->scaler_update = y_diff;
|
|
}
|
|
|
|
static void mach64_io_remove(mach64_t *mach64)
|
|
{
|
|
int c;
|
|
uint16_t io_base = 0x02ec;
|
|
|
|
switch (mach64->io_base)
|
|
{
|
|
case 0:
|
|
default:
|
|
io_base = 0x02ec;
|
|
break;
|
|
case 1:
|
|
io_base = 0x01cc;
|
|
break;
|
|
case 2:
|
|
io_base = 0x01c8;
|
|
break;
|
|
case 3:
|
|
fatal("Attempting to use the reserved value for I/O Base\n");
|
|
return;
|
|
}
|
|
|
|
io_removehandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64);
|
|
|
|
for (c = 0; c < 8; c++)
|
|
{
|
|
io_removehandler((c * 0x1000) + 0x0000 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
io_removehandler((c * 0x1000) + 0x0400 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
io_removehandler((c * 0x1000) + 0x0800 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
io_removehandler((c * 0x1000) + 0x0c00 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
}
|
|
|
|
io_removehandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64);
|
|
|
|
if (mach64->block_decoded_io && mach64->block_decoded_io < 0x10000)
|
|
io_removehandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64);
|
|
}
|
|
|
|
static void mach64_io_set(mach64_t *mach64)
|
|
{
|
|
int c;
|
|
|
|
mach64_io_remove(mach64);
|
|
|
|
io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64);
|
|
|
|
if (!mach64->use_block_decoded_io)
|
|
{
|
|
for (c = 0; c < 8; c++)
|
|
{
|
|
io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64);
|
|
}
|
|
}
|
|
|
|
io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64);
|
|
|
|
if (mach64->use_block_decoded_io && mach64->block_decoded_io && mach64->block_decoded_io < 0x10000)
|
|
io_sethandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64);
|
|
}
|
|
|
|
uint8_t mach64_pci_read(int func, int addr, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x00: return 0x02; /*ATi*/
|
|
case 0x01: return 0x10;
|
|
|
|
case 0x02: return mach64->pci_id & 0xff;
|
|
case 0x03: return mach64->pci_id >> 8;
|
|
|
|
case PCI_REG_COMMAND:
|
|
return mach64->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/
|
|
|
|
case 0x07: return 1 << 1; /*Medium DEVSEL timing*/
|
|
|
|
case 0x08: /*Revision ID*/
|
|
if (mach64->type == MACH64_GX)
|
|
return 0;
|
|
return 0x40;
|
|
|
|
case 0x09: return 0; /*Programming interface*/
|
|
|
|
case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/
|
|
case 0x0b: return 0x03;
|
|
|
|
case 0x10: return 0x00; /*Linear frame buffer address*/
|
|
case 0x11: return 0x00;
|
|
case 0x12: return mach64->linear_base >> 16;
|
|
case 0x13: return mach64->linear_base >> 24;
|
|
|
|
case 0x14:
|
|
if (mach64->type == MACH64_VT2)
|
|
return 0x01; /*Block decoded IO address*/
|
|
return 0x00;
|
|
case 0x15:
|
|
if (mach64->type == MACH64_VT2)
|
|
return mach64->block_decoded_io >> 8;
|
|
return 0x00;
|
|
case 0x16:
|
|
if (mach64->type == MACH64_VT2)
|
|
return mach64->block_decoded_io >> 16;
|
|
return 0x00;
|
|
case 0x17:
|
|
if (mach64->type == MACH64_VT2)
|
|
return mach64->block_decoded_io >> 24;
|
|
return 0x00;
|
|
|
|
case 0x30: return mach64->pci_regs[0x30] & 0x01; /*BIOS ROM address*/
|
|
case 0x31: return 0x00;
|
|
case 0x32: return mach64->pci_regs[0x32];
|
|
case 0x33: return mach64->pci_regs[0x33];
|
|
|
|
case 0x3c: return mach64->int_line;
|
|
case 0x3d: return PCI_INTA;
|
|
|
|
case 0x40: return mach64->use_block_decoded_io | mach64->io_base;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mach64_pci_write(int func, int addr, uint8_t val, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
switch (addr)
|
|
{
|
|
case PCI_REG_COMMAND:
|
|
mach64->pci_regs[PCI_REG_COMMAND] = val & 0x27;
|
|
if (val & PCI_COMMAND_IO)
|
|
mach64_io_set(mach64);
|
|
else
|
|
mach64_io_remove(mach64);
|
|
mach64_updatemapping(mach64);
|
|
break;
|
|
|
|
case 0x12:
|
|
if (mach64->type == MACH64_VT2)
|
|
val = 0;
|
|
mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0x80) << 16);
|
|
mach64_updatemapping(mach64);
|
|
break;
|
|
case 0x13:
|
|
mach64->linear_base = (mach64->linear_base & 0x800000) | (val << 24);
|
|
mach64_updatemapping(mach64);
|
|
break;
|
|
|
|
case 0x15:
|
|
if (mach64->type == MACH64_VT2)
|
|
{
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_remove(mach64);
|
|
mach64->block_decoded_io = (mach64->block_decoded_io & 0xffff0000) | ((val & 0xfc) << 8);
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_set(mach64);
|
|
}
|
|
break;
|
|
case 0x16:
|
|
if (mach64->type == MACH64_VT2)
|
|
{
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_remove(mach64);
|
|
mach64->block_decoded_io = (mach64->block_decoded_io & 0xff00fc00) | (val << 16);
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_set(mach64);
|
|
}
|
|
break;
|
|
case 0x17:
|
|
if (mach64->type == MACH64_VT2)
|
|
{
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_remove(mach64);
|
|
mach64->block_decoded_io = (mach64->block_decoded_io & 0x00fffc00) | (val << 24);
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_set(mach64);
|
|
}
|
|
break;
|
|
|
|
case 0x30: case 0x32: case 0x33:
|
|
mach64->pci_regs[addr] = val;
|
|
if (mach64->pci_regs[0x30] & 0x01)
|
|
{
|
|
uint32_t addr = (mach64->pci_regs[0x32] << 16) | (mach64->pci_regs[0x33] << 24);
|
|
/* pclog("Mach64 bios_rom enabled at %08x\n", addr); */
|
|
mem_mapping_set_addr(&mach64->bios_rom.mapping, addr, 0x8000);
|
|
}
|
|
else
|
|
{
|
|
/* pclog("Mach64 bios_rom disabled\n"); */
|
|
mem_mapping_disable(&mach64->bios_rom.mapping);
|
|
}
|
|
return;
|
|
|
|
case 0x3c:
|
|
mach64->int_line = val;
|
|
break;
|
|
|
|
case 0x40:
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_remove(mach64);
|
|
mach64->io_base = val & 0x03;
|
|
if (mach64->type == MACH64_VT2)
|
|
mach64->use_block_decoded_io = val & 0x04;
|
|
if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO)
|
|
mach64_io_set(mach64);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void *mach64_common_init(device_t *info)
|
|
{
|
|
mach64_t *mach64 = malloc(sizeof(mach64_t));
|
|
memset(mach64, 0, sizeof(mach64_t));
|
|
|
|
mach64->vram_size = device_get_config_int("memory");
|
|
mach64->vram_mask = (mach64->vram_size << 20) - 1;
|
|
|
|
svga_init(&mach64->svga, mach64, mach64->vram_size << 20,
|
|
mach64_recalctimings,
|
|
mach64_in, mach64_out,
|
|
mach64_hwcursor_draw,
|
|
mach64_overlay_draw);
|
|
|
|
if (info->flags & DEVICE_PCI)
|
|
mem_mapping_disable(&mach64->bios_rom.mapping);
|
|
|
|
mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga);
|
|
mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64);
|
|
mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64);
|
|
mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64);
|
|
mem_mapping_disable(&mach64->mmio_mapping);
|
|
|
|
mach64_io_set(mach64);
|
|
|
|
if (info->flags & DEVICE_PCI)
|
|
{
|
|
mach64->card = pci_add_card(PCI_ADD_VIDEO, mach64_pci_read, mach64_pci_write, mach64);
|
|
}
|
|
|
|
mach64->pci_regs[PCI_REG_COMMAND] = 3;
|
|
mach64->pci_regs[0x30] = 0x00;
|
|
mach64->pci_regs[0x32] = 0x0c;
|
|
mach64->pci_regs[0x33] = 0x00;
|
|
|
|
ati68860_ramdac_init(&mach64->ramdac);
|
|
|
|
mach64->dst_cntl = 3;
|
|
|
|
mach64->wake_fifo_thread = thread_create_event();
|
|
mach64->fifo_not_full_event = thread_create_event();
|
|
mach64->fifo_thread = thread_create(fifo_thread, mach64);
|
|
|
|
return mach64;
|
|
}
|
|
|
|
static void *mach64gx_init(device_t *info)
|
|
{
|
|
mach64_t *mach64 = mach64_common_init(info);
|
|
|
|
mach64->type = MACH64_GX;
|
|
mach64->pci_id = (int)'X' | ((int)'G' << 8);
|
|
mach64->config_chip_id = 0x020000d7;
|
|
mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/
|
|
mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI-68860, 256Kx16 DRAM*/
|
|
if (info->flags & DEVICE_PCI)
|
|
mach64->config_stat0 |= 0; /*PCI, 256Kx16 DRAM*/
|
|
else if ((info->flags & DEVICE_VLB) || (info->flags & DEVICE_ISA))
|
|
mach64->config_stat0 |= 1; /*VLB, 256Kx16 DRAM*/
|
|
|
|
ati_eeprom_load(&mach64->eeprom, L"mach64.nvr", 1);
|
|
|
|
if (info->flags & DEVICE_PCI)
|
|
rom_init(&mach64->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
|
else if (info->flags & DEVICE_VLB)
|
|
rom_init(&mach64->bios_rom, BIOS_VLB_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
|
else if (info->flags & DEVICE_ISA)
|
|
rom_init(&mach64->bios_rom, BIOS_ISA_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
|
|
|
return mach64;
|
|
}
|
|
static void *mach64vt2_init(device_t *info)
|
|
{
|
|
mach64_t *mach64 = mach64_common_init(info);
|
|
svga_t *svga = &mach64->svga;
|
|
|
|
mach64->type = MACH64_VT2;
|
|
mach64->pci_id = 0x5654;
|
|
mach64->config_chip_id = 0x40005654;
|
|
mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/
|
|
mach64->config_stat0 = 4;
|
|
mach64->use_block_decoded_io = PCI ? 4 : 0;
|
|
|
|
ati_eeprom_load(&mach64->eeprom, L"mach64vt.nvr", 1);
|
|
|
|
rom_init(&mach64->bios_rom, BIOS_ROMVT2_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
|
|
|
svga->vblank_start = mach64_vblank_start;
|
|
|
|
return mach64;
|
|
}
|
|
|
|
int mach64gx_available(void)
|
|
{
|
|
return rom_present(BIOS_ROM_PATH);
|
|
}
|
|
int mach64gx_isa_available(void)
|
|
{
|
|
return rom_present(BIOS_ISA_ROM_PATH);
|
|
}
|
|
int mach64gx_vlb_available(void)
|
|
{
|
|
return rom_present(BIOS_VLB_ROM_PATH);
|
|
}
|
|
int mach64vt2_available(void)
|
|
{
|
|
return rom_present(BIOS_ROMVT2_PATH);
|
|
}
|
|
|
|
void mach64_close(void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
svga_close(&mach64->svga);
|
|
|
|
thread_kill(mach64->fifo_thread);
|
|
thread_destroy_event(mach64->wake_fifo_thread);
|
|
thread_destroy_event(mach64->fifo_not_full_event);
|
|
|
|
free(mach64);
|
|
}
|
|
|
|
void mach64_speed_changed(void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
svga_recalctimings(&mach64->svga);
|
|
}
|
|
|
|
void mach64_force_redraw(void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
|
|
mach64->svga.fullchange = changeframecount;
|
|
}
|
|
|
|
void mach64_add_status_info(char *s, int max_len, void *p)
|
|
{
|
|
mach64_t *mach64 = (mach64_t *)p;
|
|
char temps[256];
|
|
uint64_t new_time = plat_timer_read();
|
|
uint64_t status_diff = new_time - mach64->status_time;
|
|
mach64->status_time = new_time;
|
|
|
|
if (((mach64->crtc_gen_cntl >> 24) & 3) == 3)
|
|
{
|
|
svga_t *svga = &mach64->svga;
|
|
char temps[128];
|
|
int bpp = 4;
|
|
|
|
strncat(s, "Mach64 in native mode\n", max_len);
|
|
|
|
switch ((mach64->crtc_gen_cntl >> 8) & 7)
|
|
{
|
|
case 1: bpp = 4; break;
|
|
case 2: bpp = 8; break;
|
|
case 3: bpp = 15; break;
|
|
case 4: bpp = 16; break;
|
|
case 5: bpp = 24; break;
|
|
case 6: bpp = 32; break;
|
|
}
|
|
|
|
sprintf(temps, "Mach64 colour depth : %i bpp\n", bpp);
|
|
strncat(s, temps, max_len);
|
|
|
|
sprintf(temps, "Mach64 resolution : %i x %i\n", svga->hdisp, svga->dispend);
|
|
strncat(s, temps, max_len);
|
|
|
|
sprintf(temps, "Mach64 refresh rate : %i Hz\n\n", svga->frames);
|
|
svga->frames = 0;
|
|
strncat(s, temps, max_len);
|
|
}
|
|
else
|
|
{
|
|
strncat(s, "Mach64 in SVGA mode\n", max_len);
|
|
svga_add_status_info(s, max_len, &mach64->svga);
|
|
}
|
|
|
|
sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)mach64->blitter_time * 100.0) / timer_freq, ((double)mach64->blitter_time * 100.0) / status_diff);
|
|
strncat(s, temps, max_len);
|
|
|
|
mach64->blitter_time = 0;
|
|
}
|
|
|
|
static device_config_t mach64gx_config[] =
|
|
{
|
|
{
|
|
"memory", "Memory size", CONFIG_SELECTION, "", 4,
|
|
{
|
|
{
|
|
"1 MB", 1
|
|
},
|
|
{
|
|
"2 MB", 2
|
|
},
|
|
{
|
|
"4 MB", 4
|
|
},
|
|
{
|
|
""
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"", "", -1
|
|
}
|
|
};
|
|
|
|
static device_config_t mach64vt2_config[] =
|
|
{
|
|
{
|
|
"memory", "Memory size", CONFIG_SELECTION, "", 4,
|
|
{
|
|
{
|
|
"2 MB", 2
|
|
},
|
|
{
|
|
"4 MB", 4
|
|
},
|
|
{
|
|
""
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"", "", -1
|
|
}
|
|
};
|
|
|
|
device_t mach64gx_isa_device =
|
|
{
|
|
"ATI Mach64GX ISA",
|
|
DEVICE_ISA,
|
|
0,
|
|
mach64gx_init, mach64_close, NULL,
|
|
mach64gx_isa_available,
|
|
mach64_speed_changed,
|
|
mach64_force_redraw,
|
|
mach64_add_status_info,
|
|
mach64gx_config
|
|
};
|
|
|
|
device_t mach64gx_vlb_device =
|
|
{
|
|
"ATI Mach64GX VLB",
|
|
DEVICE_VLB,
|
|
0,
|
|
mach64gx_init, mach64_close, NULL,
|
|
mach64gx_vlb_available,
|
|
mach64_speed_changed,
|
|
mach64_force_redraw,
|
|
mach64_add_status_info,
|
|
mach64gx_config
|
|
};
|
|
|
|
device_t mach64gx_pci_device =
|
|
{
|
|
"ATI Mach64GX PCI",
|
|
DEVICE_PCI,
|
|
0,
|
|
mach64gx_init, mach64_close, NULL,
|
|
mach64gx_available,
|
|
mach64_speed_changed,
|
|
mach64_force_redraw,
|
|
mach64_add_status_info,
|
|
mach64gx_config
|
|
};
|
|
|
|
device_t mach64vt2_device =
|
|
{
|
|
"ATI Mach64VT2",
|
|
DEVICE_PCI,
|
|
0,
|
|
mach64vt2_init, mach64_close, NULL,
|
|
mach64vt2_available,
|
|
mach64_speed_changed,
|
|
mach64_force_redraw,
|
|
mach64_add_status_info,
|
|
mach64vt2_config
|
|
};
|