Merge branch 'master' into cpu-refactor2
This commit is contained in:
commit
3c3d0b46db
File diff suppressed because it is too large
Load Diff
|
@ -24,12 +24,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
typedef struct PPCDisasmContext {
|
typedef struct PPCDisasmContext {
|
||||||
uint32_t instr_addr;
|
uint32_t instr_addr;
|
||||||
uint32_t instr_code;
|
uint32_t instr_code;
|
||||||
std::string instr_str;
|
std::string instr_str;
|
||||||
bool simplified; /* true if we should output simplified mnemonics */
|
bool simplified; /* true if we should output simplified mnemonics */
|
||||||
|
std::vector<std::string> regs_in;
|
||||||
|
std::vector<std::string> regs_out;
|
||||||
} PPCDisasmContext;
|
} PPCDisasmContext;
|
||||||
|
|
||||||
std::string disassemble_single(PPCDisasmContext* ctx);
|
std::string disassemble_single(PPCDisasmContext* ctx);
|
||||||
|
|
|
@ -115,7 +115,7 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
|
||||||
ppc_state.spr[SPR::SRR1] = (ppc_state.msr & 0x0000FF73) | srr1_bits;
|
ppc_state.spr[SPR::SRR1] = (ppc_state.msr & 0x0000FF73) | srr1_bits;
|
||||||
ppc_state.msr &= 0xFFFB1041;
|
ppc_state.msr &= 0xFFFB1041;
|
||||||
/* copy MSR[ILE] to MSR[LE] */
|
/* copy MSR[ILE] to MSR[LE] */
|
||||||
ppc_state.msr = (ppc_state.msr & 0xFFFFFFFE) | ((ppc_state.msr >> 16) & 1);
|
ppc_state.msr = (ppc_state.msr & ~MSR::LE) | !!(ppc_state.msr & MSR::ILE);
|
||||||
|
|
||||||
if (ppc_state.msr & MSR::IP) {
|
if (ppc_state.msr & MSR::IP) {
|
||||||
ppc_next_instruction_address |= 0xFFF00000;
|
ppc_next_instruction_address |= 0xFFF00000;
|
||||||
|
|
|
@ -94,7 +94,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
uint32_t ppc_result_b = ppc_state.gpr[reg_b];
|
uint32_t ppc_result_b = ppc_state.gpr[reg_b];
|
||||||
|
|
||||||
#define ppc_store_iresult_reg(reg, ppc_result)\
|
#define ppc_store_iresult_reg(reg, ppc_result)\
|
||||||
ppc_state.gpr[(reg)] = ppc_result;
|
ppc_state.gpr[reg] = ppc_result;
|
||||||
|
|
||||||
#define ppc_store_sfpresult_int(reg, ppc_result64_d)\
|
#define ppc_store_sfpresult_int(reg, ppc_result64_d)\
|
||||||
ppc_state.fpr[(reg)].int64_r = ppc_result64_d;
|
ppc_state.fpr[(reg)].int64_r = ppc_result64_d;
|
||||||
|
|
|
@ -391,7 +391,7 @@ void mmu_change_mode()
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// user mode can't disable translations
|
// user mode can't disable translations
|
||||||
LOG_F(ERROR, "instruction mmu mode 1 is invalid!");
|
//LOG_F(ERROR, "instruction mmu mode 1 is invalid!"); // this happens alot. Maybe it's not invalid?
|
||||||
mmu_mode = 3;
|
mmu_mode = 3;
|
||||||
case 3: // user mode with instruction translation enabled
|
case 3: // user mode with instruction translation enabled
|
||||||
pCurITLB1 = &itlb1_mode3[0];
|
pCurITLB1 = &itlb1_mode3[0];
|
||||||
|
|
|
@ -528,7 +528,7 @@ void dppc_interpreter::ppc_mulli() {
|
||||||
|
|
||||||
template <bool rec, bool ov>
|
template <bool rec, bool ov>
|
||||||
void dppc_interpreter::ppc_divw() {
|
void dppc_interpreter::ppc_divw() {
|
||||||
uint32_t ppc_result_d;
|
uint32_t ppc_result_d = 0;
|
||||||
ppc_grab_regsdab(ppc_cur_instruction);
|
ppc_grab_regsdab(ppc_cur_instruction);
|
||||||
|
|
||||||
if (!ppc_result_b) { /* handle the "anything / 0" case */
|
if (!ppc_result_b) { /* handle the "anything / 0" case */
|
||||||
|
@ -564,7 +564,7 @@ template void dppc_interpreter::ppc_divw<RC1, OV1>();
|
||||||
|
|
||||||
template <bool rec, bool ov>
|
template <bool rec, bool ov>
|
||||||
void dppc_interpreter::ppc_divwu() {
|
void dppc_interpreter::ppc_divwu() {
|
||||||
uint32_t ppc_result_d;
|
uint32_t ppc_result_d = 0;
|
||||||
ppc_grab_regsdab(ppc_cur_instruction);
|
ppc_grab_regsdab(ppc_cur_instruction);
|
||||||
|
|
||||||
if (!ppc_result_b) { /* division by zero */
|
if (!ppc_result_b) { /* division by zero */
|
||||||
|
|
|
@ -96,7 +96,7 @@ uint8_t AdbBus::process_command(const uint8_t* in_data, int data_size) {
|
||||||
if (!this->got_answer)
|
if (!this->got_answer)
|
||||||
return ADB_STAT_TIMEOUT;
|
return ADB_STAT_TIMEOUT;
|
||||||
} else {
|
} else {
|
||||||
ABORT_F("%s: unsupported ADB command 0x%X", this->name.c_str(), cmd_byte);
|
LOG_F(ERROR, "%s: unsupported ADB command 0x%X", this->name.c_str(), cmd_byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ADB_STAT_OK;
|
return ADB_STAT_OK;
|
||||||
|
|
|
@ -130,7 +130,7 @@ void DMAChannel::finish_cmd() {
|
||||||
this->cur_cmd = cmd_desc[3] >> 4;
|
this->cur_cmd = cmd_desc[3] >> 4;
|
||||||
|
|
||||||
// all commands except STOP update cmd.xferStatus and
|
// all commands except STOP update cmd.xferStatus and
|
||||||
// perform actions under control of "i", "b" and "w" bits
|
// perform actions under control of "i" interrupt, "b" branch, and "w" wait bits
|
||||||
if (this->cur_cmd < DBDMA_Cmd::STOP) {
|
if (this->cur_cmd < DBDMA_Cmd::STOP) {
|
||||||
// react to cmd.w (wait) bits
|
// react to cmd.w (wait) bits
|
||||||
if (cmd_desc[2] & 3) {
|
if (cmd_desc[2] & 3) {
|
||||||
|
@ -258,7 +258,10 @@ void DMAChannel::update_irq() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cond) {
|
if (cond) {
|
||||||
this->int_ctrl->ack_dma_int(this->irq_id, 1);
|
if (int_ctrl)
|
||||||
|
this->int_ctrl->ack_dma_int(this->irq_id, 1);
|
||||||
|
else
|
||||||
|
LOG_F(ERROR, "%s Interrupt ignored", this->get_name().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,8 +347,10 @@ void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size) {
|
||||||
break;
|
break;
|
||||||
case DMAReg::CH_STAT:
|
case DMAReg::CH_STAT:
|
||||||
break; // ingore writes to ChannelStatus
|
break; // ingore writes to ChannelStatus
|
||||||
case DMAReg::CMD_PTR_HI: // Mac OS X writes this optional register with zero
|
case DMAReg::CMD_PTR_HI:
|
||||||
LOG_F(9, "CommandPtrHi set to 0x%X", value);
|
if (value != 0) {
|
||||||
|
LOG_F(WARNING, "%s: Unsupported DMA channel register write @%02x.%c = %0*x", this->get_name().c_str(), offset, SIZE_ARG(size), size * 2, value);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DMAReg::CMD_PTR_LO:
|
case DMAReg::CMD_PTR_LO:
|
||||||
if (!(this->ch_stat & CH_STAT_RUN) && !(this->ch_stat & CH_STAT_ACTIVE)) {
|
if (!(this->ch_stat & CH_STAT_RUN) && !(this->ch_stat & CH_STAT_ACTIVE)) {
|
||||||
|
@ -462,11 +467,11 @@ void DMAChannel::start() {
|
||||||
|
|
||||||
this->queue_len = 0;
|
this->queue_len = 0;
|
||||||
|
|
||||||
|
this->cmd_in_progress = false;
|
||||||
|
|
||||||
if (this->start_cb)
|
if (this->start_cb)
|
||||||
this->start_cb();
|
this->start_cb();
|
||||||
|
|
||||||
this->cmd_in_progress = false;
|
|
||||||
|
|
||||||
// some DBDMA programs contain commands that don't transfer data
|
// some DBDMA programs contain commands that don't transfer data
|
||||||
// between a device and memory (LOAD_QUAD, STORE_QUAD, NOP and STOP).
|
// between a device and memory (LOAD_QUAD, STORE_QUAD, NOP and STOP).
|
||||||
// We thus interprete the DBDMA program until a data transfer between
|
// We thus interprete the DBDMA program until a data transfer between
|
||||||
|
|
|
@ -40,28 +40,48 @@ class InterruptCtrl;
|
||||||
enum DMAReg : uint32_t {
|
enum DMAReg : uint32_t {
|
||||||
CH_CTRL = 0,
|
CH_CTRL = 0,
|
||||||
CH_STAT = 4,
|
CH_STAT = 4,
|
||||||
CMD_PTR_HI = 8,
|
CMD_PTR_HI = 8, // not implemented
|
||||||
CMD_PTR_LO = 12,
|
CMD_PTR_LO = 12,
|
||||||
INT_SELECT = 16,
|
INT_SELECT = 16,
|
||||||
BRANCH_SELECT = 20,
|
BRANCH_SELECT = 20,
|
||||||
WAIT_SELECT = 24,
|
WAIT_SELECT = 24,
|
||||||
|
// TANSFER_MODES = 28,
|
||||||
|
// DATA_2_PTR_HI = 32, // not implemented
|
||||||
|
// DATA_2_PTR_LO = 36,
|
||||||
|
// RESERVED_1 = 40,
|
||||||
|
// ADDRESS_HI = 44,
|
||||||
|
// RESERVED_2_0 = 48,
|
||||||
|
// RESERVED_2_1 = 52,
|
||||||
|
// RESERVED_2_2 = 56,
|
||||||
|
// RESERVED_2_3 = 60,
|
||||||
|
// UNIMPLEMENTED = 64,
|
||||||
|
// UNDEFINED = 128,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Channel Status bits (DBDMA spec, 5.5.3) */
|
/** Channel Status bits (DBDMA spec, 5.5.3) */
|
||||||
enum : uint16_t {
|
enum : uint16_t {
|
||||||
CH_STAT_ACTIVE = 0x400,
|
CH_STAT_S0 = 0x0001, // general purpose status and control
|
||||||
CH_STAT_DEAD = 0x800,
|
CH_STAT_S1 = 0x0002, // general purpose status and control
|
||||||
CH_STAT_WAKE = 0x1000,
|
CH_STAT_S2 = 0x0004, // general purpose status and control
|
||||||
CH_STAT_FLUSH = 0x2000,
|
CH_STAT_S3 = 0x0008, // general purpose status and control
|
||||||
CH_STAT_PAUSE = 0x4000,
|
CH_STAT_S4 = 0x0010, // general purpose status and control
|
||||||
CH_STAT_RUN = 0x8000
|
CH_STAT_S5 = 0x0020, // general purpose status and control
|
||||||
|
CH_STAT_S6 = 0x0040, // general purpose status and control
|
||||||
|
CH_STAT_S7 = 0x0080, // general purpose status and control
|
||||||
|
CH_STAT_BT = 0x0100, // hardware status bit
|
||||||
|
CH_STAT_ACTIVE = 0x0400, // hardware status bit
|
||||||
|
CH_STAT_DEAD = 0x0800, // hardware status bit
|
||||||
|
CH_STAT_WAKE = 0x1000, // command bit set by software and cleared by hardware once the action has been performed
|
||||||
|
CH_STAT_FLUSH = 0x2000, // command bit set by software and cleared by hardware once the action has been performed
|
||||||
|
CH_STAT_PAUSE = 0x4000, // control bit set and cleared by software
|
||||||
|
CH_STAT_RUN = 0x8000 // control bit set and cleared by software
|
||||||
};
|
};
|
||||||
|
|
||||||
/** DBDMA command (DBDMA spec, 5.6.1) - all fields are little-endian! */
|
/** DBDMA command (DBDMA spec, 5.6.1) - all fields are little-endian! */
|
||||||
typedef struct DMACmd {
|
typedef struct DMACmd {
|
||||||
uint16_t req_count;
|
uint16_t req_count;
|
||||||
uint8_t cmd_bits;
|
uint8_t cmd_bits; // wait: & 3, branch: & 0xC, interrupt: & 0x30, reserved: & 0xc0
|
||||||
uint8_t cmd_key;
|
uint8_t cmd_key; // key: & 7, reserved: & 8, cmd: >> 4
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
uint32_t cmd_arg;
|
uint32_t cmd_arg;
|
||||||
uint16_t res_count;
|
uint16_t res_count;
|
||||||
|
|
|
@ -36,4 +36,7 @@ public:
|
||||||
virtual ~MMIODevice() = default;
|
virtual ~MMIODevice() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SIZE_ARG(size) (size == 4 ? 'l' : size == 2 ? 'w' : \
|
||||||
|
size == 1 ? 'b' : '0' + size)
|
||||||
|
|
||||||
#endif /* MMIO_DEVICE_H */
|
#endif /* MMIO_DEVICE_H */
|
||||||
|
|
|
@ -197,9 +197,6 @@ inline uint32_t pci_cfg_log(uint32_t value, AccessDetails &details) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SIZE_ARG(size) (size == 4 ? 'l' : size == 2 ? 'w' : \
|
|
||||||
size == 1 ? 'b' : '0' + size)
|
|
||||||
|
|
||||||
#define LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER() \
|
#define LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER() \
|
||||||
do { if ((details.flags & PCI_CONFIG_DIRECTION) == PCI_CONFIG_READ) { \
|
do { if ((details.flags & PCI_CONFIG_DIRECTION) == PCI_CONFIG_READ) { \
|
||||||
VLOG_F( \
|
VLOG_F( \
|
||||||
|
|
|
@ -185,6 +185,10 @@ uint16_t Sc53C94::pseudo_dma_read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
LOG_F(ERROR, "SC53C94: FIFO underrun %d", data_fifo_pos);
|
||||||
|
data_word = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// see if we need to refill FIFO
|
// see if we need to refill FIFO
|
||||||
if (!this->data_fifo_pos && !is_done) {
|
if (!this->data_fifo_pos && !is_done) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
#include <machines/machineproperties.h>
|
#include <machines/machineproperties.h>
|
||||||
#include <memaccess.h>
|
#include <memaccess.h>
|
||||||
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -239,7 +238,7 @@ static char Apple_Copyright_Page_Data[] = "APPLE COMPUTER, INC ";
|
||||||
void ScsiCdrom::mode_sense()
|
void ScsiCdrom::mode_sense()
|
||||||
{
|
{
|
||||||
uint8_t page_code = this->cmd_buf[2] & 0x3F;
|
uint8_t page_code = this->cmd_buf[2] & 0x3F;
|
||||||
uint8_t alloc_len = this->cmd_buf[4];
|
//uint8_t alloc_len = this->cmd_buf[4];
|
||||||
|
|
||||||
int num_blocks = this->size_blocks;
|
int num_blocks = this->size_blocks;
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,8 @@ void AwacsBase::dma_out_start() {
|
||||||
|
|
||||||
if (!this->out_stream_running) {
|
if (!this->out_stream_running) {
|
||||||
if ((err = snd_server->start_out_stream())) {
|
if ((err = snd_server->start_out_stream())) {
|
||||||
LOG_F(ERROR, "%s: could not start sound output stream", this->name.c_str());
|
LOG_F(ERROR, "%s: could not start sound output stream: %d",
|
||||||
|
this->name.c_str(), err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,9 @@ uint32_t BurgundyCodec::snd_ctrl_read(uint32_t offset, int size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BurgundyCodec::snd_ctrl_write(uint32_t offset, uint32_t value, int size) {
|
void BurgundyCodec::snd_ctrl_write(uint32_t offset, uint32_t value, int size) {
|
||||||
uint8_t reg_addr, cur_byte, last_byte;
|
uint8_t reg_addr;
|
||||||
|
uint8_t cur_byte;
|
||||||
|
//uint8_t last_byte;
|
||||||
|
|
||||||
value = BYTESWAP_32(value);
|
value = BYTESWAP_32(value);
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ void BurgundyCodec::snd_ctrl_write(uint32_t offset, uint32_t value, int size) {
|
||||||
this->last_ctrl_data = value;
|
this->last_ctrl_data = value;
|
||||||
reg_addr = (value >> 12) & 0xFF;
|
reg_addr = (value >> 12) & 0xFF;
|
||||||
cur_byte = (value >> 8) & 3;
|
cur_byte = (value >> 8) & 3;
|
||||||
last_byte = (value >> 10) & 3;
|
//last_byte = (value >> 10) & 3;
|
||||||
if (value & BURGUNDY_REG_WR) {
|
if (value & BURGUNDY_REG_WR) {
|
||||||
uint32_t mask = 0xFFU << (cur_byte * 8);
|
uint32_t mask = 0xFFU << (cur_byte * 8);
|
||||||
this->reg_array[reg_addr] = (this->reg_array[reg_addr] & ~mask) |
|
this->reg_array[reg_addr] = (this->reg_array[reg_addr] & ~mask) |
|
||||||
|
|
|
@ -686,28 +686,21 @@ void AtiMach64Gx::crtc_update()
|
||||||
this->crtc_on = true;
|
this->crtc_on = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtiMach64Gx::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) {
|
void AtiMach64Gx::draw_hw_cursor(uint8_t *dst_row, 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], ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size);
|
int vert_offset = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_OFF], ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size);
|
||||||
//int horz_offset = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_OFF], ATI_CUR_HORZ_OFF, ATI_CUR_HORZ_OFF_size);
|
|
||||||
|
|
||||||
src_buf = &this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8];
|
|
||||||
|
|
||||||
int cur_height = 64 - vert_offset;
|
int cur_height = 64 - vert_offset;
|
||||||
|
|
||||||
uint32_t color0 = this->regs[ATI_CUR_CLR0] | 0x000000FFUL;
|
uint32_t color0 = this->regs[ATI_CUR_CLR0] | 0x000000FFUL;
|
||||||
uint32_t color1 = this->regs[ATI_CUR_CLR1] | 0x000000FFUL;
|
uint32_t color1 = this->regs[ATI_CUR_CLR1] | 0x000000FFUL;
|
||||||
|
|
||||||
for (int h = 0; h < cur_height; h++) {
|
uint64_t *src_row = (uint64_t *)&this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8];
|
||||||
dst_row = &dst_buf[h * dst_pitch];
|
dst_pitch -= 64 * 4;
|
||||||
src_row = &src_buf[h * 16];
|
|
||||||
|
|
||||||
for (int x = 0; x < 16; x++) {
|
for (int h = cur_height; h > 0; h--) {
|
||||||
px4 = src_row[x];
|
for (int x = 2; x > 0; x--) {
|
||||||
|
uint64_t px = *src_row++;
|
||||||
for (int p = 0; p < 4; p++, px4 >>= 2, dst_row += 4) {
|
for (int p = 32; p > 0; p--, px >>= 2, dst_row += 4) {
|
||||||
switch(px4 & 3) {
|
switch(px & 3) {
|
||||||
case 0: // cursor color 0
|
case 0: // cursor color 0
|
||||||
WRITE_DWORD_BE_A(dst_row, color0);
|
WRITE_DWORD_BE_A(dst_row, color0);
|
||||||
break;
|
break;
|
||||||
|
@ -718,15 +711,18 @@ void AtiMach64Gx::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) {
|
||||||
WRITE_DWORD_BE_A(dst_row, 0);
|
WRITE_DWORD_BE_A(dst_row, 0);
|
||||||
break;
|
break;
|
||||||
case 3: // 1's complement of display pixel
|
case 3: // 1's complement of display pixel
|
||||||
|
WRITE_DWORD_BE_A(dst_row, 0x0000007F);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dst_row += dst_pitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtiMach64Gx::get_cursor_position(int& x, int& y) {
|
void AtiMach64Gx::get_cursor_position(int& x, int& y) {
|
||||||
x = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size);
|
x = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size) -
|
||||||
|
extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_OFF ], ATI_CUR_HORZ_OFF , ATI_CUR_HORZ_OFF_size );
|
||||||
y = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_VERT_POSN, ATI_CUR_VERT_POSN_size);
|
y = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_VERT_POSN, ATI_CUR_VERT_POSN_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -385,6 +385,16 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ATI_CUR_CLR0:
|
||||||
|
case ATI_CUR_CLR1:
|
||||||
|
this->setup_hw_cursor();
|
||||||
|
// fallthrough
|
||||||
|
case ATI_CUR_OFFSET:
|
||||||
|
case ATI_CUR_HORZ_VERT_POSN:
|
||||||
|
case ATI_CUR_HORZ_VERT_OFF:
|
||||||
|
new_value = value;
|
||||||
|
draw_fb = true;
|
||||||
|
break;
|
||||||
case ATI_GP_IO:
|
case ATI_GP_IO:
|
||||||
new_value = value;
|
new_value = value;
|
||||||
if (offset <= 1 && offset + size > 1) {
|
if (offset <= 1 && offset + size > 1) {
|
||||||
|
@ -446,6 +456,7 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
|
||||||
this->setup_hw_cursor();
|
this->setup_hw_cursor();
|
||||||
else
|
else
|
||||||
this->cursor_on = false;
|
this->cursor_on = false;
|
||||||
|
draw_fb = true;
|
||||||
}
|
}
|
||||||
if (bit_changed(old_value, new_value, ATI_GEN_GUI_RESETB)) {
|
if (bit_changed(old_value, new_value, ATI_GEN_GUI_RESETB)) {
|
||||||
if (!bit_set(new_value, ATI_GEN_GUI_RESETB))
|
if (!bit_set(new_value, ATI_GEN_GUI_RESETB))
|
||||||
|
@ -549,9 +560,11 @@ void ATIRage::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int siz
|
||||||
{
|
{
|
||||||
if (rgn_start == this->aperture_base[0] && offset < this->aperture_size[0]) {
|
if (rgn_start == this->aperture_base[0] && offset < this->aperture_size[0]) {
|
||||||
if (offset < this->vram_size) { // little-endian VRAM region
|
if (offset < this->vram_size) { // little-endian VRAM region
|
||||||
|
draw_fb = true;
|
||||||
return write_mem(&this->vram_ptr[offset], value, size);
|
return write_mem(&this->vram_ptr[offset], value, size);
|
||||||
}
|
}
|
||||||
if (offset >= BE_FB_OFFSET) { // big-endian VRAM region
|
if (offset >= BE_FB_OFFSET) { // big-endian VRAM region
|
||||||
|
draw_fb = true;
|
||||||
return write_mem(&this->vram_ptr[offset & (BE_FB_OFFSET - 1)], value, size);
|
return write_mem(&this->vram_ptr[offset & (BE_FB_OFFSET - 1)], value, size);
|
||||||
}
|
}
|
||||||
//if (!bit_set(this->regs[ATI_BUS_CNTL], ATI_BUS_APER_REG_DIS)) {
|
//if (!bit_set(this->regs[ATI_BUS_CNTL], ATI_BUS_APER_REG_DIS)) {
|
||||||
|
@ -695,38 +708,45 @@ void ATIRage::crtc_update() {
|
||||||
switch (this->pixel_format) {
|
switch (this->pixel_format) {
|
||||||
case 1:
|
case 1:
|
||||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||||
|
draw_fb = false;
|
||||||
this->convert_frame_4bpp_indexed(dst_buf, dst_pitch);
|
this->convert_frame_4bpp_indexed(dst_buf, dst_pitch);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (bit_set(this->regs[ATI_DAC_CNTL], ATI_DAC_DIRECT)) {
|
if (bit_set(this->regs[ATI_DAC_CNTL], ATI_DAC_DIRECT)) {
|
||||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||||
|
draw_fb = false;
|
||||||
this->convert_frame_8bpp(dst_buf, dst_pitch);
|
this->convert_frame_8bpp(dst_buf, dst_pitch);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||||
|
draw_fb = false;
|
||||||
this->convert_frame_8bpp_indexed(dst_buf, dst_pitch);
|
this->convert_frame_8bpp_indexed(dst_buf, dst_pitch);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||||
|
draw_fb = false;
|
||||||
this->convert_frame_15bpp_BE(dst_buf, dst_pitch);
|
this->convert_frame_15bpp_BE(dst_buf, dst_pitch);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||||
|
draw_fb = false;
|
||||||
this->convert_frame_16bpp(dst_buf, dst_pitch);
|
this->convert_frame_16bpp(dst_buf, dst_pitch);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||||
|
draw_fb = false;
|
||||||
this->convert_frame_24bpp(dst_buf, dst_pitch);
|
this->convert_frame_24bpp(dst_buf, dst_pitch);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||||
|
draw_fb = false;
|
||||||
this->convert_frame_32bpp_BE(dst_buf, dst_pitch);
|
this->convert_frame_32bpp_BE(dst_buf, dst_pitch);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
@ -757,47 +777,44 @@ void ATIRage::crtc_update() {
|
||||||
this->crtc_on = true;
|
this->crtc_on = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) {
|
void ATIRage::draw_hw_cursor(uint8_t* dst_row, 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], ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size);
|
||||||
int vert_offset = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_OFF], ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size);
|
|
||||||
|
|
||||||
src_buf = &this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8];
|
|
||||||
|
|
||||||
int cur_height = 64 - vert_offset;
|
int cur_height = 64 - vert_offset;
|
||||||
|
|
||||||
uint32_t color0 = this->regs[ATI_CUR_CLR0] | 0x000000FFUL;
|
uint32_t color0 = this->regs[ATI_CUR_CLR0] | 0x000000FFUL;
|
||||||
uint32_t color1 = this->regs[ATI_CUR_CLR1] | 0x000000FFUL;
|
uint32_t color1 = this->regs[ATI_CUR_CLR1] | 0x000000FFUL;
|
||||||
|
|
||||||
for (int h = 0; h < cur_height; h++) {
|
uint64_t* src_row = (uint64_t*)&this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8];
|
||||||
dst_row = &dst_buf[h * dst_pitch];
|
dst_pitch -= 64 * 4;
|
||||||
src_row = &src_buf[h * 16];
|
|
||||||
|
|
||||||
for (int x = 0; x < 16; x++) {
|
for (int h = cur_height; h > 0; h--) {
|
||||||
px4 = src_row[x];
|
for (int x = 2; x > 0; x--) {
|
||||||
|
uint64_t px = *src_row++;
|
||||||
for (int p = 0; p < 4; p++, px4 >>= 2, dst_row += 4) {
|
for (int p = 32; p > 0; p--, px >>= 2, dst_row += 4) {
|
||||||
switch(px4 & 3) {
|
switch (px & 3) {
|
||||||
case 0: // cursor color 0
|
case 0: // cursor color 0
|
||||||
WRITE_DWORD_BE_A(dst_row, color0);
|
WRITE_DWORD_BE_A(dst_row, color0);
|
||||||
break;
|
break;
|
||||||
case 1: // cursor color 1
|
case 1: // cursor color 1
|
||||||
WRITE_DWORD_BE_A(dst_row, color1);
|
WRITE_DWORD_BE_A(dst_row, color1);
|
||||||
break;
|
break;
|
||||||
case 2: // transparent
|
case 2: // transparent
|
||||||
WRITE_DWORD_BE_A(dst_row, 0);
|
WRITE_DWORD_BE_A(dst_row, 0);
|
||||||
break;
|
break;
|
||||||
case 3: // 1's complement of display pixel
|
case 3: // 1's complement of display pixel
|
||||||
WRITE_DWORD_BE_A(dst_row, 0x0000007F);
|
WRITE_DWORD_BE_A(dst_row, 0x0000007F);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dst_row += dst_pitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATIRage::get_cursor_position(int& x, int& y) {
|
void ATIRage::get_cursor_position(int& x, int& y) {
|
||||||
x = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size);
|
x = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size) -
|
||||||
|
extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_OFF ], ATI_CUR_HORZ_OFF , ATI_CUR_HORZ_OFF_size );
|
||||||
y = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_VERT_POSN, ATI_CUR_VERT_POSN_size);
|
y = extract_bits<uint32_t>(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_VERT_POSN, ATI_CUR_VERT_POSN_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,15 @@ void VideoCtrlBase::update_screen()
|
||||||
this->get_cursor_position(cursor_x, cursor_y);
|
this->get_cursor_position(cursor_x, cursor_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->display.update(
|
if (draw_fb) {
|
||||||
this->convert_fb_cb, this->cursor_ovl_cb,
|
if (this->cursor_dirty) {
|
||||||
this->cursor_on, cursor_x, cursor_y);
|
this->setup_hw_cursor();
|
||||||
|
this->cursor_dirty = false;
|
||||||
|
}
|
||||||
|
this->display.update(
|
||||||
|
this->convert_fb_cb, this->cursor_ovl_cb,
|
||||||
|
this->cursor_on, cursor_x, cursor_y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoCtrlBase::start_refresh_task() {
|
void VideoCtrlBase::start_refresh_task() {
|
||||||
|
|
|
@ -75,6 +75,7 @@ protected:
|
||||||
bool crtc_on = false;
|
bool crtc_on = false;
|
||||||
bool blank_on = true;
|
bool blank_on = true;
|
||||||
bool cursor_on = false;
|
bool cursor_on = false;
|
||||||
|
bool cursor_dirty = false;
|
||||||
int active_width; // width of the visible display area
|
int active_width; // width of the visible display area
|
||||||
int active_height; // height of the visible display area
|
int active_height; // height of the visible display area
|
||||||
int hori_total = 0;
|
int hori_total = 0;
|
||||||
|
@ -85,6 +86,7 @@ protected:
|
||||||
int pixel_format;
|
int pixel_format;
|
||||||
float pixel_clock;
|
float pixel_clock;
|
||||||
float refresh_rate;
|
float refresh_rate;
|
||||||
|
bool draw_fb = true;
|
||||||
|
|
||||||
uint32_t palette[256]; // internal DAC palette in RGBA format
|
uint32_t palette[256]; // internal DAC palette in RGBA format
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,7 @@ int MachineFactory::load_boot_rom(string& rom_filepath) {
|
||||||
size_t file_size;
|
size_t file_size;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
uint32_t rom_load_addr;
|
uint32_t rom_load_addr;
|
||||||
AddressMapEntry *rom_reg;
|
//AddressMapEntry *rom_reg;
|
||||||
|
|
||||||
rom_file.open(rom_filepath, ios::in | ios::binary);
|
rom_file.open(rom_filepath, ios::in | ios::binary);
|
||||||
if (rom_file.fail()) {
|
if (rom_file.fail()) {
|
||||||
|
@ -373,7 +373,7 @@ int MachineFactory::load_boot_rom(string& rom_filepath) {
|
||||||
MemCtrlBase* mem_ctrl = dynamic_cast<MemCtrlBase*>(
|
MemCtrlBase* mem_ctrl = dynamic_cast<MemCtrlBase*>(
|
||||||
gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
|
gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
|
||||||
|
|
||||||
if ((rom_reg = mem_ctrl->find_rom_region())) {
|
if ((/*rom_reg = */mem_ctrl->find_rom_region())) {
|
||||||
mem_ctrl->set_data(rom_load_addr, sysrom_mem, (uint32_t)file_size);
|
mem_ctrl->set_data(rom_load_addr, sysrom_mem, (uint32_t)file_size);
|
||||||
} else {
|
} else {
|
||||||
LOG_F(ERROR, "Could not locate physical ROM region!");
|
LOG_F(ERROR, "Could not locate physical ROM region!");
|
||||||
|
|
Loading…
Reference in New Issue