Convert ATI register offsets to DWORD format.

This commit is contained in:
Maxim Poliakovski 2023-04-11 01:23:40 +02:00
parent b07b700b36
commit 2f562e7761
3 changed files with 208 additions and 203 deletions

View File

@ -1,6 +1,6 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-22 divingkatae and maximum
Copyright (C) 2018-23 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -31,150 +31,154 @@ enum {
/** Mach64 register offsets. */
enum {
ATI_CRTC_H_TOTAL_DISP = 0x0000,
ATI_CRTC_H_SYNC_STRT_WID = 0x0004,
ATI_CRTC_V_TOTAL_DISP = 0x0008,
ATI_CRTC_V_SYNC_STRT_WID = 0x000C,
ATI_CRTC_VLINE_CRNT_VLINE = 0x0010,
ATI_CRTC_OFF_PITCH = 0x0014,
ATI_CRTC_INT_CNTL = 0x0018,
ATI_CRTC_GEN_CNTL = 0x001C,
ATI_DSP_CONFIG = 0x0020,
ATI_DSP_ON_OFF = 0x0024,
ATI_TIMER_CFG = 0x0028,
ATI_MEM_BUF_CNTL = 0x002C,
ATI_MEM_ADDR_CFG = 0x0034,
ATI_CRT_TRAP = 0x0038,
ATI_I2C_CNTL_0 = 0x003C,
ATI_OVR_CLR = 0x0040,
ATI_OVR_WID_LEFT_RIGHT = 0x0044,
ATI_OVR_WID_TOP_BOTTOM = 0x0048,
ATI_VGA_DSP_CFG = 0x004C,
ATI_VGA_DSP_TGL = 0x0050,
ATI_DSP2_CONFIG = 0x0054,
ATI_DSP2_TOGGLE = 0x0058,
ATI_CRTC2_OFF_PITCH = 0x005C,
ATI_CUR_CLR0 = 0x0060,
ATI_CUR_CLR1 = 0x0064,
ATI_CUR_OFFSET = 0x0068,
ATI_CUR_HORZ_VERT_POSN = 0x006C,
ATI_CUR_HORZ_VERT_OFF = 0x0070,
ATI_GP_IO = 0x0078,
ATI_HW_DEBUG = 0x007C,
ATI_SCRATCH_REG0 = 0x0080,
ATI_SCRATCH_REG1 = 0x0084,
ATI_SCRATCH_REG2 = 0x0088,
ATI_SCRATCH_REG3 = 0x008C,
ATI_CLOCK_CNTL = 0x0090,
ATI_CONFIG_STAT1 = 0x0094,
ATI_CONFIG_STAT2 = 0x0098,
ATI_BUS_CNTL = 0x00A0,
ATI_EXT_MEM_CNTL = 0x00AC,
ATI_MEM_CNTL = 0x00B0,
ATI_MEM_VGA_WP_SEL = 0x00B4,
ATI_MEM_VGA_RP_SEL = 0x00B8,
ATI_I2C_CNTL_1 = 0x00BC,
ATI_DAC_REGS = 0x00C0,
ATI_CRTC_H_TOTAL_DISP = 0x000, // 0x0000
ATI_CRTC_H_SYNC_STRT_WID = 0x001, // 0x0004
ATI_CRTC_V_TOTAL_DISP = 0x002, // 0x0008
ATI_CRTC_V_SYNC_STRT_WID = 0x003, // 0x000C
ATI_CRTC_VLINE_CRNT_VLINE = 0x004, // 0x0010
ATI_CRTC_OFF_PITCH = 0x005, // 0x0014
ATI_CRTC_INT_CNTL = 0x006, // 0x0018
ATI_CRTC_GEN_CNTL = 0x007, // 0x001C
ATI_DSP_CONFIG = 0x008, // 0x0020
ATI_DSP_ON_OFF = 0x009, // 0x0024
ATI_TIMER_CFG = 0x00A, // 0x0028
ATI_MEM_BUF_CNTL = 0x00B, // 0x002C
ATI_MEM_ADDR_CFG = 0x00D, // 0x0034
ATI_CRT_TRAP = 0x00E, // 0x0038
ATI_I2C_CNTL_0 = 0x00F, // 0x003C
ATI_OVR_CLR = 0x010, // 0x0040
ATI_OVR_WID_LEFT_RIGHT = 0x011, // 0x0044
ATI_OVR_WID_TOP_BOTTOM = 0x012, // 0x0048
ATI_VGA_DSP_CFG = 0x013, // 0x004C
ATI_VGA_DSP_ON_OFF = 0x014, // 0x0050
ATI_DSP2_CONFIG = 0x015, // 0x0054 <-- LT specific
ATI_DSP2_ON_OFF = 0x016, // 0x0058 <-- LT specific
ATI_CRTC2_OFF_PITCH = 0x017, // 0x005C <-- LT specific
ATI_CUR_CLR0 = 0x018, // 0x0060
ATI_CUR_CLR1 = 0x019, // 0x0064
ATI_CUR_OFFSET = 0x01A, // 0x0068
ATI_CUR_HORZ_VERT_POSN = 0x01B, // 0x006C
ATI_CUR_HORZ_VERT_OFF = 0x01C, // 0x0070
ATI_GP_IO = 0x01E, // 0x0078
ATI_HW_DEBUG = 0x01F, // 0x007C
ATI_SCRATCH_REG0 = 0x020, // 0x0080
ATI_SCRATCH_REG1 = 0x021, // 0x0084
ATI_SCRATCH_REG2 = 0x022, // 0x0088
ATI_SCRATCH_REG3 = 0x023, // 0x008C
ATI_CLOCK_CNTL = 0x024, // 0x0090
ATI_CONFIG_STAT1 = 0x025, // 0x0094
ATI_CONFIG_STAT2 = 0x026, // 0x0098
ATI_BUS_CNTL = 0x028, // 0x00A0
ATI_EXT_MEM_CNTL = 0x02B, // 0x00AC
ATI_MEM_CNTL = 0x02C, // 0x00B0
ATI_MEM_VGA_WP_SEL = 0x02D, // 0x00B4
ATI_MEM_VGA_RP_SEL = 0x02E, // 0x00B8
ATI_I2C_CNTL_1 = 0x02F, // 0x00BC
ATI_DAC_REGS = 0x030, // 0x00C0
// byte offsets for the built-in DAC registers
ATI_DAC_W_INDEX = 0x00C0,
ATI_DAC_DATA = 0x00C1,
ATI_DAC_MASK = 0x00C2,
ATI_DAC_R_INDEX = 0x00C3,
ATI_DAC_CNTL = 0x00C4,
ATI_GEN_TEST_CNTL = 0x00D0,
ATI_CUSTOM_MACRO_CNTL = 0x00D4,
ATI_CONFIG_CNTL = 0x00DC,
ATI_CONFIG_CHIP_ID = 0x00E0,
ATI_CONFIG_STAT0 = 0x00E4,
ATI_GX_CONFIG_STAT1 = 0x00E8, // GX only
ATI_CRC_SIG = 0x00E8,
ATI_DST_Y_X_ALIAS1 = 0x00F4,
ATI_DST_OFF_PITCH = 0x0100,
ATI_DST_X = 0x0104,
ATI_DST_Y = 0x0108,
ATI_DST_Y_X = 0x010C,
ATI_DST_WIDTH = 0x0110,
ATI_DST_HEIGHT = 0x0114,
ATI_DST_HEIGHT_WIDTH = 0x0118,
ATI_DST_X_WIDTH = 0x011C,
ATI_DST_BRES_LNTH = 0x0120,
ATI_DST_BRES_ERR = 0x0124,
ATI_DST_BRES_INC = 0x0128,
ATI_DST_BRES_DEC = 0x012C,
ATI_DST_CNTL = 0x0130,
ATI_DST_Y_X_ALIAS2 = 0x0134,
ATI_TRAIL_BRES_ERR = 0x0138,
ATI_TRAIL_BRES_INC = 0x013C,
ATI_TRAIL_BRES_DEC = 0x0140,
ATI_DST_BRES_LNTH_ALIAS1 = 0x0144,
ATI_Z_OFF_PITCH = 0x0148,
ATI_Z_CNTL = 0x014C,
ATI_ALPHA_TST_CNTL = 0x0150,
ATI_SRC_OFF_PITCH = 0x0180,
ATI_SRC_X = 0x0184,
ATI_SRC_Y = 0x0188,
ATI_SRC_Y_X = 0x018C,
ATI_SRC_WIDTH1 = 0x0190,
ATI_SRC_HEIGHT1 = 0x0194,
ATI_SRC_HEIGHT1_WIDTH1 = 0x0198,
ATI_SRC_X_START = 0x019C,
ATI_SRC_Y_START = 0x01A0,
ATI_SRC_Y_X_START = 0x01A4,
ATI_SRC_WIDTH2 = 0x01A8,
ATI_SRC_HEIGHT2 = 0x01AC,
ATI_SRC_HEIGHT2_WIDTH2 = 0x01B0,
ATI_SRC_CNTL = 0x01B4,
ATI_SCALE_OFF = 0x01C0,
ATI_SCALE_WIDTH = 0x01DC,
ATI_SCALE_HEIGHT = 0x01E0,
ATI_SCALE_PITCH = 0x01EC,
ATI_SCALE_X_INC = 0x01F0,
ATI_SCALE_Y_INC = 0x01F4,
ATI_SCALE_VACC = 0x01F8,
ATI_SCALE_3D_CNTL = 0x01FC,
ATI_HOST_CNTL = 0x0240,
ATI_PAT_REG0 = 0x0280,
ATI_PAT_REG1 = 0x0284,
ATI_PAT_CNTL = 0x0288,
ATI_SC_LEFT = 0x02A0,
ATI_SC_RIGHT = 0x02A4,
ATI_SC_LEFT_RIGHT = 0x02A8,
ATI_SC_TOP = 0x02AC,
ATI_SC_BOTTOM = 0x02B0,
ATI_SC_TOP_BOTTOM = 0x02B4,
ATI_DP_BKGD_CLR = 0x02C0,
ATI_DP_FOG_CLR = 0x02C0,
ATI_DP_WRITE_MSK = 0x02C8,
ATI_DP_PIX_WIDTH = 0x02D0,
ATI_DP_MIX = 0x02D4,
ATI_DP_SRC = 0x02D8,
ATI_FRGD_CLR_MIX = 0x02DC,
ATI_FRGD_BKGD_CLR = 0x02E0,
ATI_DST_X_Y = 0x02E8,
ATI_DST_WIDTH_HEIGHT = 0x02EC,
ATI_USR_DST_PITCH = 0x02F0,
ATI_DP_SET_GUI_ENGINE2 = 0x02F4,
ATI_DP_SET_GUI_ENGINE = 0x02F8,
ATI_CLR_CMP_CLR = 0x0300,
ATI_CLR_CMP_MSK = 0x0304,
ATI_CLR_CMP_CNTL = 0x0308,
ATI_FIFO_STAT = 0x0310,
ATI_CONTEXT_MASK = 0x0320,
ATI_GUI_TRAJ_CNTL = 0x0330,
ATI_GUI_STAT = 0x0338,
ATI_MPP_CONFIG = 0x04C0,
ATI_MPP_STROBE_SEQ = 0x04C4,
ATI_MPP_ADDR = 0x04C8,
ATI_MPP_DATA = 0x04CC,
ATI_TVO_CNTL = 0x0500,
ATI_SETUP_CNTL = 0x0704,
ATI_DAC_CNTL = 0x031, // 0x00C4
ATI_GEN_TEST_CNTL = 0x034, // 0x00D0
ATI_CUSTOM_MACRO_CNTL = 0x035, // 0x00D4
ATI_CONFIG_CNTL = 0x037, // 0x00DC
ATI_CONFIG_CHIP_ID = 0x038, // 0x00E0
ATI_CONFIG_STAT0 = 0x039, // 0x00E4
ATI_GX_CONFIG_STAT1 = 0x03A, // 0x00E8 <-- GX/CT specific
ATI_CRC_SIG = 0x03A, // 0x00E8
ATI_DST_OFF_PITCH = 0x040, // 0x0100
ATI_DST_X = 0x041, // 0x0104
ATI_DST_Y = 0x042, // 0x0108
ATI_DST_Y_X = 0x043, // 0x010C
ATI_DST_WIDTH = 0x044, // 0x0110
ATI_DST_HEIGHT = 0x045, // 0x0114
ATI_DST_HEIGHT_WIDTH = 0x046, // 0x0118
ATI_DST_X_WIDTH = 0x047, // 0x011C
ATI_DST_BRES_LNTH = 0x048, // 0x0120
ATI_DST_BRES_ERR = 0x049, // 0x0124
ATI_DST_BRES_INC = 0x04A, // 0x0128
ATI_DST_BRES_DEC = 0x04B, // 0x012C
ATI_DST_CNTL = 0x04C, // 0x0130
ATI_DST_Y_X_ALIAS1 = 0x04D, // 0x0134
ATI_TRAIL_BRES_ERR = 0x04E, // 0x0138
ATI_TRAIL_BRES_INC = 0x04F, // 0x013C
ATI_TRAIL_BRES_DEC = 0x050, // 0x0140
ATI_DST_BRES_LNTH_ALIAS1 = 0x051, // 0x0144
ATI_Z_OFF_PITCH = 0x052, // 0x0148
ATI_Z_CNTL = 0x053, // 0x014C
ATI_ALPHA_TST_CNTL = 0x054, // 0x0150
ATI_SRC_OFF_PITCH = 0x060, // 0x0180
ATI_SRC_X = 0x061, // 0x0184
ATI_SRC_Y = 0x062, // 0x0188
ATI_SRC_Y_X = 0x063, // 0x018C
ATI_SRC_WIDTH1 = 0x064, // 0x0190
ATI_SRC_HEIGHT1 = 0x065, // 0x0194
ATI_SRC_HEIGHT1_WIDTH1 = 0x066, // 0x0198
ATI_SRC_X_START = 0x067, // 0x019C
ATI_SRC_Y_START = 0x068, // 0x01A0
ATI_SRC_Y_X_START = 0x069, // 0x01A4
ATI_SRC_WIDTH2 = 0x06A, // 0x01A8
ATI_SRC_HEIGHT2 = 0x06B, // 0x01AC
ATI_SRC_HEIGHT2_WIDTH2 = 0x06C, // 0x01B0
ATI_SRC_CNTL = 0x06D, // 0x01B4
ATI_SCALE_OFF = 0x070, // 0x01C0
ATI_SCALE_WIDTH = 0x077, // 0x01DC
ATI_SCALE_HEIGHT = 0x078, // 0x01E0
ATI_SCALE_PITCH = 0x07B, // 0x01EC
ATI_SCALE_X_INC = 0x07C, // 0x01F0
ATI_SCALE_Y_INC = 0x07D, // 0x01F4
ATI_SCALE_VACC = 0x07E, // 0x01F8
ATI_SCALE_3D_CNTL = 0x07F, // 0x01FC
ATI_HOST_CNTL = 0x090, // 0x0240
ATI_PAT_REG0 = 0x0A0, // 0x0280
ATI_PAT_REG1 = 0x0A1, // 0x0284
ATI_PAT_CNTL = 0x0A2, // 0x0288
ATI_SC_LEFT = 0x0A8, // 0x02A0
ATI_SC_RIGHT = 0x0A9, // 0x02A4
ATI_SC_LEFT_RIGHT = 0x0AA, // 0x02A8
ATI_SC_TOP = 0x0AB, // 0x02AC
ATI_SC_BOTTOM = 0x0AC, // 0x02B0
ATI_SC_TOP_BOTTOM = 0x0AD, // 0x02B4
ATI_DP_BKGD_CLR = 0x0B0, // 0x02C0
ATI_DP_FRGD_CLR = 0x0B1, // 0x02C4
ATI_DP_FOG_CLR = 0x0B1, // 0x02C4
ATI_DP_WRITE_MSK = 0x0B2, // 0x02C8
ATI_DP_PIX_WIDTH = 0x0B4, // 0x02D0
ATI_DP_MIX = 0x0B5, // 0x02D4
ATI_DP_SRC = 0x0B6, // 0x02D8
ATI_DP_FRGD_CLR_MIX = 0x0B7, // 0x02DC
ATI_DP_FRGD_BKGD_CLR = 0x0B8, // 0x02E0
ATI_DST_X_Y = 0x0BA, // 0x02E8
ATI_DST_WIDTH_HEIGHT = 0x0BB, // 0x02EC
ATI_USR_DST_PITCH = 0x0BC, // 0x02F0
ATI_DP_SET_GUI_ENGINE2 = 0x0BE, // 0x02F8
ATI_DP_SET_GUI_ENGINE = 0x0BF, // 0x02FC
ATI_CLR_CMP_CLR = 0x0C0, // 0x0300
ATI_CLR_CMP_MSK = 0x0C1, // 0x0304
ATI_CLR_CMP_CNTL = 0x0C2, // 0x0308
ATI_FIFO_STAT = 0x0C4, // 0x0310
ATI_CONTEXT_MASK = 0x0C8, // 0x0320 <-- 264VT specific
ATI_GUI_TRAJ_CNTL = 0x0CC, // 0x0330
ATI_GUI_STAT = 0x0CE, // 0x0338
ATI_MPP_CONFIG = 0x130, // 0x04C0
ATI_MPP_STROBE_SEQ = 0x131, // 0x04C4
ATI_MPP_ADDR = 0x132, // 0x04C8
ATI_MPP_DATA = 0x133, // 0x04CC
ATI_TVO_CNTL = 0x140, // 0x0500
ATI_SETUP_CNTL = 0x1C1, // 0x0704
ATI_INVALID = 0xFFFF
};
constexpr auto APERTURE_SIZE = 0x01000000UL; /* Mach64 aperture size */
constexpr auto MM_REGS_0_OFF = 0x007FFC00UL; /* offset to memory mapped registers, block 0 */
constexpr auto MM_REGS_1_OFF = 0x007FF800UL; /* offset to memory mapped registers, block 1 */
constexpr auto MM_REGS_2_OFF = 0x003FFC00UL; /* offset to memory mapped registers, 4MB aperture */
constexpr auto BE_FB_OFFSET = 0x00800000UL; /* Offset to the big-endian frame buffer */
constexpr auto APERTURE_SIZE = 0x01000000UL; // Mach64 aperture size
constexpr auto MM_REGS_0_OFF = 0x007FFC00UL; // offset to memory mapped registers, block 0
constexpr auto MM_REGS_1_OFF = 0x007FF800UL; // offset to memory mapped registers, block 1
constexpr auto MM_REGS_2_OFF = 0x003FFC00UL; // offset to memory mapped registers, 4MB aperture
constexpr auto BE_FB_OFFSET = 0x00800000UL; // Offset to the big-endian frame buffer
constexpr auto ATI_XTAL = 14318180.0f; // external crystal oscillator frequency

View File

@ -66,7 +66,7 @@ AtiMach64Gx::AtiMach64Gx()
this->vram_ptr = std::unique_ptr<uint8_t[]> (new uint8_t[this->vram_size]);
// set up RAMDAC identification
this->regs[ATI_CONFIG_STAT0 >> 2] = 1 << 9;
this->regs[ATI_CONFIG_STAT0] = 1 << 9;
}
void AtiMach64Gx::notify_bar_change(int bar_num)
@ -121,10 +121,10 @@ bool AtiMach64Gx::pci_io_read(uint32_t offset, uint32_t size, uint32_t* res)
}
// convert ISA-style I/O address to MMIO register offset
offset = io_idx_to_reg_offset[(offset >> 10) & 0x1F] + (offset & 3);
offset = io_idx_to_reg_offset[(offset >> 10) & 0x1F] * 4 + (offset & 3);
// CONFIG_CNTL is accessible from I/O space only
if ((offset & ~3) == ATI_CONFIG_CNTL) {
if ((offset >> 2) == ATI_CONFIG_CNTL) {
*res = read_mem(((uint8_t *)&this->config_cntl) + (offset & 3), size);
} else {
*res = BYTESWAP_SIZED(this->read_reg(offset, size), size);
@ -141,10 +141,10 @@ bool AtiMach64Gx::pci_io_write(uint32_t offset, uint32_t value, uint32_t size)
}
// convert ISA-style I/O address to MMIO register offset
offset = io_idx_to_reg_offset[(offset >> 10) & 0x1F] + (offset & 3);
offset = io_idx_to_reg_offset[(offset >> 10) & 0x1F] * 4 + (offset & 3);
// CONFIG_CNTL is accessible from I/O space only
if ((offset & ~3) == ATI_CONFIG_CNTL) {
if ((offset >> 2) == ATI_CONFIG_CNTL) {
write_mem(((uint8_t *)&this->config_cntl) + (offset & 3), value, size);
switch (this->config_cntl & 3) {
case 0:
@ -190,24 +190,24 @@ void AtiMach64Gx::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size)
int crtc_en;
uint32_t offset = reg_offset & 3;
reg_offset >>= 2;
if (offset || size != 4) { // slow path
if ((offset + size) > 4) {
ABORT_F("%s: unaligned DWORD writes not implemented", this->name.c_str());
}
uint64_t old_val = this->regs[reg_offset >> 2];
uint64_t old_val = this->regs[reg_offset];
insert_bits<uint64_t>(old_val, value, offset * 8, size * 8);
value = old_val;
}
switch (reg_offset & ~3) {
switch (reg_offset) {
case ATI_CRTC_OFF_PITCH:
this->regs[reg_offset >> 2] = value;
this->fb_pitch = extract_bits<uint32_t>(value, 22, 10) * 8;
this->fb_ptr = &this->vram_ptr[extract_bits<uint32_t>(value, 0, 20) * 8];
break;
case ATI_CRTC_GEN_CNTL:
if (bit_changed(this->regs[reg_offset >> 2], value, 6)) {
if (bit_changed(this->regs[reg_offset], value, 6)) {
if (value & 0x40) {
this->blank_on = true;
this->blank_display();
@ -216,7 +216,7 @@ void AtiMach64Gx::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size)
}
}
if (bit_changed(this->regs[reg_offset >> 2], value, 25)) {
if (bit_changed(this->regs[reg_offset], value, 25)) {
if (!bit_set(value, 25)) {
this->disable_crtc_internal();
} else {
@ -226,7 +226,7 @@ void AtiMach64Gx::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size)
break;
case ATI_DAC_REGS:
if (size == 1) { // only byte accesses are allowed for DAC registers
int dac_reg_addr = ((this->regs[ATI_DAC_CNTL >> 2] & 1) << 2) | offset;
int dac_reg_addr = ((this->regs[ATI_DAC_CNTL] & 1) << 2) | offset;
rgb514_write_reg(dac_reg_addr, extract_bits<uint32_t>(value, offset * 8, 8));
}
break;
@ -243,7 +243,7 @@ void AtiMach64Gx::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size)
return; // prevent writes to this read-only register
}
this->regs[reg_offset >> 2] = value;
this->regs[reg_offset] = value;
}
uint32_t AtiMach64Gx::read(uint32_t rgn_start, uint32_t offset, int size)
@ -280,19 +280,19 @@ void AtiMach64Gx::enable_crtc_internal()
uint32_t new_width, new_height;
// check for unsupported modes and fail early
if (!bit_set(this->regs[ATI_CRTC_GEN_CNTL >> 2], 24))
if (!bit_set(this->regs[ATI_CRTC_GEN_CNTL], 24))
ABORT_F("%s: VGA not supported", this->name.c_str());
new_width = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP >> 2], 16, 8) + 1) * 8;
new_height = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP >> 2], 16, 11) + 1;
new_width = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP], 16, 8) + 1) * 8;
new_height = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP], 16, 11) + 1;
if (new_width != this->active_width || new_height != this->active_height) {
this->create_display_window(new_width, new_height);
}
// calculate display refresh rate
this->hori_total = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP >> 2], 0, 9) + 1) * 8;
this->vert_total = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP >> 2], 0, 11) + 1;
this->hori_total = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP], 0, 9) + 1) * 8;
this->vert_total = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP], 0, 11) + 1;
this->refresh_rate = this->pixel_clock / this->hori_total / this->vert_total;

View File

@ -136,14 +136,14 @@ ATIRage::ATIRage(uint16_t dev_id)
};
// stuff default values into chip registers
this->regs[ATI_CONFIG_CHIP_ID >> 2] = (asic_id << 24) | dev_id;
this->regs[ATI_CONFIG_CHIP_ID] = (asic_id << 24) | dev_id;
// initialize display identification
this->disp_id = std::unique_ptr<DisplayID> (new DisplayID());
uint8_t mon_code = this->disp_id->read_monitor_sense(0, 0);
this->regs[ATI_GP_IO >> 2] = ((mon_code & 6) << 11) | ((mon_code & 1) << 8);
this->regs[ATI_GP_IO] = ((mon_code & 6) << 11) | ((mon_code & 1) << 8);
}
void ATIRage::notify_bar_change(int bar_num)
@ -212,16 +212,16 @@ uint32_t ATIRage::read_reg(uint32_t reg_offset, uint32_t size) {
uint64_t result;
uint32_t offset = reg_offset & 3;
switch (reg_offset & ~3) {
switch (reg_offset >> 2) {
case ATI_CLOCK_CNTL:
result = this->regs[ATI_CLOCK_CNTL >> 2];
result = this->regs[ATI_CLOCK_CNTL];
if ((offset + size - 1) >= 2) {
uint8_t pll_addr = (this->regs[ATI_CLOCK_CNTL >> 2] >> 10) & 0x3F;
uint8_t pll_addr = (this->regs[ATI_CLOCK_CNTL] >> 10) & 0x3F;
insert_bits<uint64_t>(result, this->plls[pll_addr], 16, 8);
}
break;
case ATI_DAC_REGS:
result = this->regs[ATI_DAC_REGS >> 2];
result = this->regs[ATI_DAC_REGS];
switch (reg_offset) {
case ATI_DAC_W_INDEX:
insert_bits<uint64_t>(result, this->dac_wr_index, 0, 8);
@ -260,74 +260,75 @@ uint32_t ATIRage::read_reg(uint32_t reg_offset, uint32_t size) {
}
void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
uint32_t offset = reg_offset & 3;
uint32_t offset = reg_offset & 3;
reg_offset >>= 2;
if (offset || size != 4) { // slow path
if ((offset + size) > 4) {
ABORT_F("%s: unaligned DWORD writes not implemented", this->name.c_str());
}
uint64_t old_val = this->regs[reg_offset >> 2];
uint64_t old_val = this->regs[reg_offset];
insert_bits<uint64_t>(old_val, value, offset * 8, size * 8);
value = old_val;
}
switch (reg_offset & ~3) {
switch (reg_offset) {
case ATI_CRTC_H_TOTAL_DISP:
LOG_F(9, "%s: ATI_CRTC_H_TOTAL_DISP set to 0x%08X", this->name.c_str(), value);
break;
case ATI_CRTC_OFF_PITCH:
this->regs[reg_offset >> 2] = value;
this->regs[reg_offset] = value;
this->fb_pitch = extract_bits<uint32_t>(value, 22, 10) * 8;
this->fb_ptr = &this->vram_ptr[extract_bits<uint32_t>(value, 0, 20) * 8];
if (bit_set(this->regs[ATI_CRTC_GEN_CNTL >> 2], 25) &&
!bit_set(this->regs[ATI_CRTC_GEN_CNTL >> 2], 6)) {
if (bit_set(this->regs[ATI_CRTC_GEN_CNTL], 25) &&
!bit_set(this->regs[ATI_CRTC_GEN_CNTL], 6)) {
this->crtc_update();
}
break;
case ATI_CRTC_GEN_CNTL:
if (bit_changed(this->regs[reg_offset >> 2], value, 6)) {
if (bit_changed(this->regs[reg_offset], value, 6)) {
if (value & 0x40) {
this->regs[reg_offset >> 2] |= (1 << 6);
this->regs[reg_offset] |= (1 << 6);
this->blank_on = true;
this->blank_display();
} else {
this->regs[reg_offset >> 2] &= ~(1 << 6);
this->regs[reg_offset] &= ~(1 << 6);
this->blank_on = false;
}
}
if (bit_changed(this->regs[reg_offset >> 2], value, 25)) {
this->regs[reg_offset >> 2] = value;
if (bit_set(this->regs[reg_offset >> 2], 25) &&
!bit_set(this->regs[reg_offset >> 2], 6)) {
if (bit_changed(this->regs[reg_offset], value, 25)) {
this->regs[reg_offset] = value;
if (bit_set(this->regs[reg_offset], 25) &&
!bit_set(this->regs[reg_offset], 6)) {
this->crtc_update();
}
return;
}
break;
case ATI_GP_IO:
this->regs[reg_offset >> 2] = value;
this->regs[reg_offset] = value;
if (offset < 2 && (offset + size - 1) >= 1) {
uint8_t gpio_levels = (this->regs[ATI_GP_IO >> 2] >> 8) & 0xFFU;
uint8_t gpio_levels = (this->regs[ATI_GP_IO] >> 8) & 0xFFU;
gpio_levels = ((gpio_levels & 0x30) >> 3) | (gpio_levels & 1);
uint8_t gpio_dirs = (this->regs[ATI_GP_IO >> 2] >> 24) & 0xFFU;
uint8_t gpio_dirs = (this->regs[ATI_GP_IO] >> 24) & 0xFFU;
gpio_dirs = ((gpio_dirs & 0x30) >> 3) | (gpio_dirs & 1);
gpio_levels = this->disp_id->read_monitor_sense(gpio_levels, gpio_dirs);
insert_bits<uint32_t>(this->regs[ATI_GP_IO >> 2],
insert_bits<uint32_t>(this->regs[ATI_GP_IO],
((gpio_levels & 6) << 3) | (gpio_levels & 1), 8, 8);
}
return;
case ATI_CLOCK_CNTL:
this->regs[reg_offset >> 2] = value;
if ((offset + size - 1) >= 2 && bit_set(this->regs[ATI_CLOCK_CNTL >> 2], 9)) {
uint8_t pll_addr = (this->regs[ATI_CLOCK_CNTL >> 2] >> 10) & 0x3F;
this->regs[reg_offset] = value;
if ((offset + size - 1) >= 2 && bit_set(this->regs[ATI_CLOCK_CNTL], 9)) {
uint8_t pll_addr = (this->regs[ATI_CLOCK_CNTL] >> 10) & 0x3F;
uint8_t pll_data = (value >> 16) & 0xFF;
this->plls[pll_addr] = pll_data;
LOG_F(9, "%s: PLL #%d set to 0x%02X", this->name.c_str(), pll_addr, pll_data);
}
return;
case ATI_DAC_REGS:
switch (reg_offset) {
switch (reg_offset * 4 + offset) {
case ATI_DAC_W_INDEX:
this->dac_wr_index = value & 0xFFU;
this->comp_index = 0;
@ -350,17 +351,17 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
}
return;
case ATI_GEN_TEST_CNTL:
if (bit_changed(this->regs[reg_offset >> 2], value, 7)) {
if (bit_changed(this->regs[reg_offset], value, 7)) {
if (bit_set(value, 7))
this->setup_hw_cursor();
else
this->cursor_on = false;
}
if (bit_changed(this->regs[reg_offset >> 2], value, 8)) {
if (bit_changed(this->regs[reg_offset], value, 8)) {
if (!bit_set(value, 8))
LOG_F(9, "%s: reset GUI engine", this->name.c_str());
}
if (bit_changed(this->regs[reg_offset >> 2], value, 9)) {
if (bit_changed(this->regs[reg_offset], value, 9)) {
if (bit_set(value, 9))
LOG_F(9, "%s: reset memory controller", this->name.c_str());
}
@ -373,7 +374,7 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
return; // prevent writes to this read-only register
}
this->regs[reg_offset >> 2] = value;
this->regs[reg_offset] = value;
}
bool ATIRage::io_access_allowed(uint32_t offset) {
@ -457,7 +458,7 @@ void ATIRage::verbose_pixel_format(int crtc_index) {
return;
}
uint32_t fmt = extract_bits<uint32_t>(this->regs[ATI_CRTC_GEN_CNTL >> 2], 8, 3);
uint32_t fmt = extract_bits<uint32_t>(this->regs[ATI_CRTC_GEN_CNTL], 8, 3);
const char* what = "Pixel format:";
@ -467,7 +468,7 @@ void ATIRage::verbose_pixel_format(int crtc_index) {
break;
case 2:
// check the undocumented DAC_DIRECT bit
if (bit_set(this->regs[ATI_DAC_CNTL >> 2], 10)) {
if (bit_set(this->regs[ATI_DAC_CNTL], 10)) {
LOG_F(INFO, "%s 8 bpp direct color (RGB322)", what);
} else {
LOG_F(INFO, "%s 8 bpp with DAC palette", what);
@ -494,7 +495,7 @@ void ATIRage::crtc_update() {
uint32_t new_width, new_height, new_htotal, new_vtotal;
// check for unsupported modes and fail early
if (!bit_set(this->regs[ATI_CRTC_GEN_CNTL >> 2], 24))
if (!bit_set(this->regs[ATI_CRTC_GEN_CNTL], 24))
ABORT_F("%s: VGA not supported", this->name.c_str());
if ((this->plls[PLL_VCLK_CNTL] & 3) != 3)
@ -502,16 +503,16 @@ void ATIRage::crtc_update() {
bool need_recalc = false;
new_width = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP >> 2], 16, 8) + 1) * 8;
new_height = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP >> 2], 16, 11) + 1;
new_width = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP], 16, 8) + 1) * 8;
new_height = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP], 16, 11) + 1;
if (new_width != this->active_width || new_height != this->active_height) {
this->create_display_window(new_width, new_height);
need_recalc = true;
}
new_htotal = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP >> 2], 0, 9) + 1) * 8;
new_vtotal = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP >> 2], 0, 11) + 1;
new_htotal = (extract_bits<uint32_t>(this->regs[ATI_CRTC_H_TOTAL_DISP], 0, 9) + 1) * 8;
new_vtotal = extract_bits<uint32_t>(this->regs[ATI_CRTC_V_TOTAL_DISP], 0, 11) + 1;
if (new_htotal != this->hori_total || new_vtotal != this->vert_total) {
this->hori_total = new_htotal;
@ -523,7 +524,7 @@ void ATIRage::crtc_update() {
return;
// look up which VPLL ouput is requested
int clock_sel = this->regs[ATI_CLOCK_CNTL >> 2] & 3;
int clock_sel = this->regs[ATI_CLOCK_CNTL] & 3;
// calculate VPLL output frequency
float vpll_freq = calc_pll_freq(2, this->plls[VCLK0_FB_DIV + clock_sel]);
@ -541,11 +542,11 @@ void ATIRage::crtc_update() {
this->refresh_rate = pixel_clock / this->hori_total / this->vert_total;
// set up frame buffer converter
int pix_fmt = extract_bits<uint32_t>(this->regs[ATI_CRTC_GEN_CNTL >> 2], 8, 3);
int pix_fmt = extract_bits<uint32_t>(this->regs[ATI_CRTC_GEN_CNTL], 8, 3);
switch (pix_fmt) {
case 2:
if (bit_set(this->regs[ATI_DAC_CNTL >> 2], 10)) {
if (bit_set(this->regs[ATI_DAC_CNTL], 10)) {
ABORT_F("%s: DAC_DIRECT set!", this->name.c_str());
}
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
@ -558,7 +559,7 @@ void ATIRage::crtc_update() {
LOG_F(INFO, "%s: primary CRT controller enabled:", this->name.c_str());
LOG_F(INFO, "Video mode: %s",
bit_set(this->regs[ATI_CRTC_GEN_CNTL >> 2], 24) ? "extended" : "VGA");
bit_set(this->regs[ATI_CRTC_GEN_CNTL], 24) ? "extended" : "VGA");
LOG_F(INFO, "Video width: %d px", this->active_width);
LOG_F(INFO, "Video height: %d px", this->active_height);
verbose_pixel_format(0);
@ -584,14 +585,14 @@ void ATIRage::crtc_update() {
void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) {
uint8_t *src_buf, *src_row, *dst_row, px4;
int vert_offset = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_OFF >> 2], 16, 5);
int vert_offset = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_OFF], 16, 5);
src_buf = &this->vram_ptr[this->regs[ATI_CUR_OFFSET >> 2] * 8];
src_buf = &this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8];
int cur_height = 64 - vert_offset;
uint32_t color0 = this->regs[ATI_CUR_CLR0 >> 2] | 0x000000FFUL;
uint32_t color1 = this->regs[ATI_CUR_CLR1 >> 2] | 0x000000FFUL;
uint32_t color0 = this->regs[ATI_CUR_CLR0] | 0x000000FFUL;
uint32_t color1 = this->regs[ATI_CUR_CLR1] | 0x000000FFUL;
for (int h = 0; h < cur_height; h++) {
dst_row = &dst_buf[h * dst_pitch];
@ -620,8 +621,8 @@ void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) {
}
void ATIRage::get_cursor_position(int& x, int& y) {
x = this->regs[ATI_CUR_HORZ_VERT_POSN >> 2] & 0xFFFFU;
y = (this->regs[ATI_CUR_HORZ_VERT_POSN >> 2] >> 16) & 0xFFFFU;
x = this->regs[ATI_CUR_HORZ_VERT_POSN] & 0xFFFFU;
y = (this->regs[ATI_CUR_HORZ_VERT_POSN] >> 16) & 0xFFFFU;
}
static const PropMap AtiRage_Properties = {