mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-06-27 21:29:32 +00:00
Compare commits
12 Commits
8d7ca7fb03
...
5f37421ceb
Author | SHA1 | Date | |
---|---|---|---|
|
5f37421ceb | ||
|
6f64e729c8 | ||
|
288e088f8a | ||
|
3797fdbf1b | ||
|
3036f4676d | ||
|
e14b6677b2 | ||
|
76f966845d | ||
|
288d97f24c | ||
|
755dd7f60a | ||
|
e6d669d187 | ||
|
0d1a2d3010 | ||
|
51af94f12d |
|
@ -68,9 +68,7 @@ ViaCuda::ViaCuda() {
|
|||
|
||||
// intialize counters/timers
|
||||
this->t1_counter = 0xFFFF;
|
||||
this->t1_active = false;
|
||||
this->t2_counter = 0xFFFF;
|
||||
this->t2_active = false;
|
||||
|
||||
// calculate VIA clock duration in ns
|
||||
this->via_clk_dur = 1.0f / VIA_CLOCK_HZ * NS_PER_SEC;
|
||||
|
@ -102,17 +100,17 @@ ViaCuda::ViaCuda() {
|
|||
|
||||
ViaCuda::~ViaCuda()
|
||||
{
|
||||
if (this->sr_timer_on) {
|
||||
if (this->sr_timer_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->sr_timer_id);
|
||||
this->sr_timer_on = false;
|
||||
this->sr_timer_id = 0;
|
||||
}
|
||||
if (this->t1_active) {
|
||||
if (this->t1_timer_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->t1_timer_id);
|
||||
this->t1_active = false;
|
||||
this->t1_timer_id = 0;
|
||||
}
|
||||
if (this->t2_active) {
|
||||
if (this->t2_timer_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->t2_timer_id);
|
||||
this->t2_active = false;
|
||||
this->t2_timer_id = 0;
|
||||
}
|
||||
if (this->treq_timer_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->treq_timer_id);
|
||||
|
@ -226,9 +224,9 @@ void ViaCuda::write(int reg, uint8_t value) {
|
|||
ABORT_F("Unsupported VIA T1 mode, ACR=0x%X", this->via_regs[VIA_ACR]);
|
||||
}
|
||||
// cancel active T1 timer task
|
||||
if (this->t1_active) {
|
||||
if (this->t1_timer_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->t1_timer_id);
|
||||
this->t1_active = false;
|
||||
this->t1_timer_id = 0;
|
||||
}
|
||||
// clear T1 flag in IFR
|
||||
this->_via_ifr &= ~VIA_IF_T1;
|
||||
|
@ -242,19 +240,19 @@ void ViaCuda::write(int reg, uint8_t value) {
|
|||
this->t1_timer_id = TimerManager::get_instance()->add_oneshot_timer(
|
||||
static_cast<uint64_t>(this->via_clk_dur * (this->t1_counter + 3) + 0.5f),
|
||||
[this]() {
|
||||
this->t1_timer_id = 0;
|
||||
this->assert_t1_int();
|
||||
}
|
||||
);
|
||||
this->t1_active = true;
|
||||
break;
|
||||
case VIA_T2CH:
|
||||
if (this->via_regs[VIA_ACR] & 0x20) {
|
||||
ABORT_F("VIA T2 pulse count mode not supported!");
|
||||
}
|
||||
// cancel active T2 timer task
|
||||
if (this->t2_active) {
|
||||
if (this->t2_timer_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->t2_timer_id);
|
||||
this->t2_active = false;
|
||||
this->t2_timer_id = 0;
|
||||
}
|
||||
// clear T2 flag in IFR
|
||||
this->_via_ifr &= ~VIA_IF_T2;
|
||||
|
@ -268,10 +266,10 @@ void ViaCuda::write(int reg, uint8_t value) {
|
|||
this->t2_timer_id = TimerManager::get_instance()->add_oneshot_timer(
|
||||
static_cast<uint64_t>(this->via_clk_dur * (this->t2_counter + 3) + 0.5f),
|
||||
[this]() {
|
||||
this->t2_timer_id = 0;
|
||||
this->assert_t2_int();
|
||||
}
|
||||
);
|
||||
this->t2_active = true;
|
||||
break;
|
||||
case VIA_SR:
|
||||
this->_via_ifr &= ~VIA_IF_SR;
|
||||
|
@ -310,20 +308,17 @@ void ViaCuda::update_irq()
|
|||
}
|
||||
|
||||
void ViaCuda::assert_sr_int() {
|
||||
this->sr_timer_on = false;
|
||||
this->_via_ifr |= VIA_IF_SR;
|
||||
update_irq();
|
||||
}
|
||||
|
||||
void ViaCuda::assert_t1_int() {
|
||||
this->_via_ifr |= VIA_IF_T1;
|
||||
this->t1_active = false;
|
||||
update_irq();
|
||||
}
|
||||
|
||||
void ViaCuda::assert_t2_int() {
|
||||
this->_via_ifr |= VIA_IF_T2;
|
||||
this->t2_active = false;
|
||||
update_irq();
|
||||
}
|
||||
|
||||
|
@ -356,14 +351,17 @@ void ViaCuda::assert_ctrl_line(ViaLine line)
|
|||
}
|
||||
|
||||
void ViaCuda::schedule_sr_int(uint64_t timeout_ns) {
|
||||
if (this->sr_timer_on) {
|
||||
if (this->sr_timer_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->sr_timer_id);
|
||||
this->sr_timer_on = false;
|
||||
this->sr_timer_id = 0;
|
||||
}
|
||||
this->sr_timer_id = TimerManager::get_instance()->add_oneshot_timer(
|
||||
timeout_ns,
|
||||
[this]() { this->assert_sr_int(); });
|
||||
this->sr_timer_on = true;
|
||||
[this]() {
|
||||
this->sr_timer_id = 0;
|
||||
this->assert_sr_int();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void ViaCuda::write(uint8_t new_state) {
|
||||
|
|
|
@ -182,16 +182,13 @@ private:
|
|||
|
||||
// VIA internal state
|
||||
uint32_t sr_timer_id = 0;
|
||||
bool sr_timer_on = false;
|
||||
|
||||
// timer 1 state
|
||||
bool t1_active;
|
||||
uint16_t t1_counter;
|
||||
uint32_t t1_timer_id = 0;
|
||||
uint64_t t1_start_time = 0;
|
||||
|
||||
// timer 2 state
|
||||
bool t2_active;
|
||||
uint16_t t2_counter;
|
||||
uint32_t t2_timer_id = 0;
|
||||
uint64_t t2_start_time = 0;
|
||||
|
|
|
@ -34,7 +34,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
using namespace Platinum;
|
||||
|
||||
PlatinumCtrl::PlatinumCtrl() : MemCtrlBase(), VideoCtrlBase(640, 480) {
|
||||
PlatinumCtrl::PlatinumCtrl() : MemCtrlBase(), VideoCtrlBase() {
|
||||
set_name("Platinum");
|
||||
|
||||
supports_types(HWCompType::MEM_CTRL | HWCompType::MMIO_DEV);
|
||||
|
|
|
@ -123,7 +123,7 @@ static const std::map<uint16_t, std::string> rgb514_reg_names = {
|
|||
};
|
||||
|
||||
AtiMach64Gx::AtiMach64Gx()
|
||||
: PCIDevice("ati-mach64-gx"), VideoCtrlBase(1024, 768)
|
||||
: PCIDevice("ati-mach64-gx"), VideoCtrlBase()
|
||||
{
|
||||
supports_types(HWCompType::MMIO_DEV | HWCompType::PCI_DEV);
|
||||
|
||||
|
@ -148,10 +148,10 @@ AtiMach64Gx::AtiMach64Gx()
|
|||
}
|
||||
|
||||
// initialize display identification
|
||||
this->disp_id = std::unique_ptr<DisplayID> (new DisplayID(0x07, 0x3A));
|
||||
this->disp_id = std::unique_ptr<DisplayID> (new DisplayID());
|
||||
|
||||
// allocate video RAM
|
||||
this->vram_size = 2 << 20; // 2MB ; up to 6MB supported
|
||||
this->vram_size = GET_INT_PROP("gfxmem_size") << 20; // convert MBs to bytes
|
||||
this->vram_ptr = std::unique_ptr<uint8_t[]> (new uint8_t[this->vram_size]);
|
||||
|
||||
// set up RAMDAC identification
|
||||
|
@ -362,6 +362,15 @@ uint32_t AtiMach64Gx::read_reg(uint32_t reg_offset, uint32_t size)
|
|||
return static_cast<uint32_t>(result);
|
||||
}
|
||||
|
||||
#define WRITE_VALUE_AND_LOG() \
|
||||
do { \
|
||||
this->regs[reg_num] = new_value; \
|
||||
LOG_F(9, "%s: write %s %04x.%c = %0*x = %08x", this->name.c_str(), \
|
||||
get_reg_name(reg_num), reg_offset, SIZE_ARG(size), size * 2, \
|
||||
(uint32_t)extract_bits<uint64_t>(value, offset * 8, size * 8), new_value \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
void AtiMach64Gx::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size)
|
||||
{
|
||||
uint32_t reg_num = reg_offset >> 2;
|
||||
|
@ -389,6 +398,7 @@ void AtiMach64Gx::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size)
|
|||
break;
|
||||
case ATI_CRTC_OFF_PITCH:
|
||||
new_value = value;
|
||||
WRITE_VALUE_AND_LOG();
|
||||
this->crtc_update();
|
||||
return;
|
||||
case ATI_CRTC_INT_CNTL:
|
||||
|
@ -502,6 +512,44 @@ void AtiMach64Gx::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ATI_OVR_CLR:
|
||||
case ATI_OVR_WID_LEFT_RIGHT:
|
||||
case ATI_OVR_WID_TOP_BOTTOM:
|
||||
new_value = value;
|
||||
WRITE_VALUE_AND_LOG();
|
||||
if (value != 0) {
|
||||
LOG_F(ERROR, "%s: Unhandled value 0x%08x.", this->name.c_str(), value);
|
||||
}
|
||||
return;
|
||||
case ATI_CUR_CLR0:
|
||||
case ATI_CUR_CLR1:
|
||||
new_value = value;
|
||||
this->cursor_dirty = true;
|
||||
draw_fb = true;
|
||||
WRITE_VALUE_AND_LOG();
|
||||
return;
|
||||
case ATI_CUR_OFFSET:
|
||||
new_value = value;
|
||||
if (old_value != new_value)
|
||||
this->cursor_dirty = true;
|
||||
draw_fb = true;
|
||||
WRITE_VALUE_AND_LOG();
|
||||
return;
|
||||
case ATI_CUR_HORZ_VERT_OFF:
|
||||
new_value = value;
|
||||
if (
|
||||
extract_bits<uint32_t>(new_value, ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size) !=
|
||||
extract_bits<uint32_t>(old_value, ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size)
|
||||
)
|
||||
this->cursor_dirty = true;
|
||||
draw_fb = true;
|
||||
WRITE_VALUE_AND_LOG();
|
||||
return;
|
||||
case ATI_CUR_HORZ_VERT_POSN:
|
||||
new_value = value;
|
||||
draw_fb = true;
|
||||
WRITE_VALUE_AND_LOG();
|
||||
return;
|
||||
case ATI_DAC_REGS:
|
||||
new_value = old_value; // no change
|
||||
if (size == 1) { // only byte accesses are allowed for DAC registers
|
||||
|
@ -539,7 +587,7 @@ uint32_t AtiMach64Gx::read(uint32_t rgn_start, uint32_t offset, int size)
|
|||
if (offset < this->vram_size) {
|
||||
return read_mem(&this->vram_ptr[offset], size);
|
||||
}
|
||||
if (offset >= this->mm_regs_offset) {
|
||||
if (offset >= this->mm_regs_offset && offset < this->mm_regs_offset + 0x400) {
|
||||
return BYTESWAP_SIZED(read_reg(offset - this->mm_regs_offset, size), size);
|
||||
}
|
||||
return 0;
|
||||
|
@ -559,9 +607,10 @@ void AtiMach64Gx::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int
|
|||
{
|
||||
if (rgn_start == this->aperture_base[0]) {
|
||||
if (offset < this->vram_size) {
|
||||
draw_fb = true;
|
||||
return write_mem(&this->vram_ptr[offset], value, size);
|
||||
}
|
||||
if (offset >= this->mm_regs_offset) {
|
||||
if (offset >= this->mm_regs_offset && offset < this->mm_regs_offset + 0x400) {
|
||||
return write_reg(offset - this->mm_regs_offset, BYTESWAP_SIZED(value, size), size);
|
||||
}
|
||||
return;
|
||||
|
@ -574,9 +623,6 @@ void AtiMach64Gx::verbose_pixel_format(int crtc_index) {
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
int fmt = extract_bits<uint32_t>(this->regs[ATI_CRTC_GEN_CNTL], ATI_CRTC_PIX_WIDTH, ATI_CRTC_PIX_WIDTH_size);
|
||||
*/
|
||||
int pix_fmt = this->pixel_format;
|
||||
|
||||
const char* what = "Pixel format:";
|
||||
|
@ -680,6 +726,8 @@ void AtiMach64Gx::crtc_update()
|
|||
if (!need_recalc)
|
||||
return;
|
||||
|
||||
this->draw_fb = true;
|
||||
|
||||
// calculate display refresh rate
|
||||
this->refresh_rate = this->pixel_clock / this->hori_total / this->vert_total;
|
||||
|
||||
|
@ -693,26 +741,31 @@ void AtiMach64Gx::crtc_update()
|
|||
switch (this->pixel_format) {
|
||||
case 2:
|
||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||
draw_fb = false;
|
||||
this->convert_frame_4bpp_indexed(dst_buf, dst_pitch);
|
||||
};
|
||||
break;
|
||||
case 3:
|
||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||
draw_fb = false;
|
||||
this->convert_frame_8bpp_indexed(dst_buf, dst_pitch);
|
||||
};
|
||||
break;
|
||||
case 4:
|
||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||
draw_fb = false;
|
||||
this->convert_frame_15bpp_BE(dst_buf, dst_pitch);
|
||||
};
|
||||
break;
|
||||
case 5:
|
||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||
draw_fb = false;
|
||||
this->convert_frame_24bpp(dst_buf, dst_pitch);
|
||||
};
|
||||
break;
|
||||
case 6:
|
||||
this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) {
|
||||
draw_fb = false;
|
||||
this->convert_frame_32bpp_BE(dst_buf, dst_pitch);
|
||||
};
|
||||
break;
|
||||
|
@ -815,6 +868,7 @@ void AtiMach64Gx::rgb514_write_reg(uint8_t reg_addr, uint8_t value)
|
|||
clut_color[1], clut_color[2], 0xFF);
|
||||
this->clut_index++;
|
||||
this->comp_index = 0;
|
||||
draw_fb = true;
|
||||
}
|
||||
break;
|
||||
case Rgb514::CLUT_MASK:
|
||||
|
@ -864,8 +918,15 @@ void AtiMach64Gx::rgb514_write_ind_reg(uint8_t reg_addr, uint8_t value)
|
|||
}
|
||||
}
|
||||
|
||||
static const PropMap AtiMach64gx_Properties = {
|
||||
{"gfxmem_size",
|
||||
new IntProperty( 2, vector<uint32_t>({2, 4, 6}))},
|
||||
{"mon_id",
|
||||
new StrProperty("")},
|
||||
};
|
||||
|
||||
static const DeviceDescription AtiMach64Gx_Descriptor = {
|
||||
AtiMach64Gx::create, {}, {}
|
||||
AtiMach64Gx::create, {}, AtiMach64gx_Properties
|
||||
};
|
||||
|
||||
REGISTER_DEVICE(AtiMach64Gx, AtiMach64Gx_Descriptor);
|
||||
|
|
|
@ -89,7 +89,7 @@ static const std::map<uint16_t, std::string> mach64_reg_names = {
|
|||
};
|
||||
|
||||
ATIRage::ATIRage(uint16_t dev_id)
|
||||
: PCIDevice("ati-rage"), VideoCtrlBase(640, 480)
|
||||
: PCIDevice("ati-rage"), VideoCtrlBase()
|
||||
{
|
||||
uint8_t asic_id;
|
||||
|
||||
|
@ -275,6 +275,17 @@ uint32_t ATIRage::read_reg(uint32_t reg_offset, uint32_t size) {
|
|||
return static_cast<uint32_t>(result);
|
||||
}
|
||||
|
||||
#define WRITE_VALUE_AND_LOG(level) \
|
||||
do { \
|
||||
this->regs[reg_num] = new_value; \
|
||||
if (reg_num != ATI_CRTC_INT_CNTL) { \
|
||||
LOG_F(level, "%s: write %s %04x.%c = %0*x = %08x", this->name.c_str(), \
|
||||
get_reg_name(reg_num), reg_offset, SIZE_ARG(size), size * 2, \
|
||||
(uint32_t)extract_bits<uint64_t>(value, offset * 8, size * 8), new_value \
|
||||
); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
|
||||
uint32_t reg_num = reg_offset >> 2;
|
||||
uint32_t offset = reg_offset & 3;
|
||||
|
@ -301,11 +312,9 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
|
|||
break;
|
||||
case ATI_CRTC_OFF_PITCH:
|
||||
new_value = value;
|
||||
if (old_value != new_value) {
|
||||
this->regs[reg_num] = new_value;
|
||||
this->crtc_update();
|
||||
}
|
||||
break;
|
||||
WRITE_VALUE_AND_LOG(9);
|
||||
this->crtc_update();
|
||||
return;
|
||||
case ATI_CRTC_INT_CNTL: {
|
||||
uint32_t bits_read_only =
|
||||
(1 << ATI_CRTC_VBLANK) |
|
||||
|
@ -395,11 +404,29 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
|
|||
break;
|
||||
case ATI_CUR_CLR0:
|
||||
case ATI_CUR_CLR1:
|
||||
this->setup_hw_cursor();
|
||||
// fallthrough
|
||||
new_value = value;
|
||||
this->cursor_dirty = true;
|
||||
draw_fb = true;
|
||||
WRITE_VALUE_AND_LOG(9);
|
||||
return;
|
||||
case ATI_CUR_OFFSET:
|
||||
case ATI_CUR_HORZ_VERT_POSN:
|
||||
new_value = value;
|
||||
if (old_value != new_value)
|
||||
this->cursor_dirty = true;
|
||||
draw_fb = true;
|
||||
WRITE_VALUE_AND_LOG(9);
|
||||
return;
|
||||
case ATI_CUR_HORZ_VERT_OFF:
|
||||
new_value = value;
|
||||
if (
|
||||
extract_bits<uint32_t>(new_value, ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size) !=
|
||||
extract_bits<uint32_t>(old_value, ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size)
|
||||
)
|
||||
this->cursor_dirty = true;
|
||||
draw_fb = true;
|
||||
WRITE_VALUE_AND_LOG(9);
|
||||
return;
|
||||
case ATI_CUR_HORZ_VERT_POSN:
|
||||
new_value = value;
|
||||
draw_fb = true;
|
||||
break;
|
||||
|
@ -463,7 +490,7 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
|
|||
new_value = value;
|
||||
if (bit_changed(old_value, new_value, ATI_GEN_CUR_ENABLE)) {
|
||||
if (bit_set(new_value, ATI_GEN_CUR_ENABLE))
|
||||
this->setup_hw_cursor();
|
||||
this->cursor_on = true;
|
||||
else
|
||||
this->cursor_on = false;
|
||||
draw_fb = true;
|
||||
|
@ -503,7 +530,7 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
|
|||
break;
|
||||
}
|
||||
|
||||
this->regs[reg_num] = new_value;
|
||||
WRITE_VALUE_AND_LOG(9);
|
||||
}
|
||||
|
||||
bool ATIRage::io_access_allowed(uint32_t offset) {
|
||||
|
@ -564,6 +591,15 @@ uint32_t ATIRage::read(uint32_t rgn_start, uint32_t offset, int size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// memory mapped expansion ROM region
|
||||
if (rgn_start == this->exp_rom_addr) {
|
||||
if (offset < this->exp_rom_size)
|
||||
return read_mem(&this->exp_rom_data[offset], size);
|
||||
LOG_F(WARNING, "%s: read unmapped ROM region %08x.%c",
|
||||
this->name.c_str(), offset, SIZE_ARG(size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_F(WARNING, "%s: read unmapped aperture region %08x.%c",
|
||||
this->name.c_str(), offset, SIZE_ARG(size));
|
||||
return 0;
|
||||
|
@ -699,6 +735,21 @@ void ATIRage::crtc_update() {
|
|||
need_recalc = true;
|
||||
}
|
||||
|
||||
static uint8_t bits_per_pixel[8] = {0, 4, 8, 16, 16, 24, 32, 0};
|
||||
|
||||
int new_fb_pitch = extract_bits<uint32_t>(this->regs[ATI_CRTC_OFF_PITCH],
|
||||
ATI_CRTC_PITCH, ATI_CRTC_PITCH_size) * bits_per_pixel[this->pixel_format];
|
||||
if (new_fb_pitch != this->fb_pitch) {
|
||||
this->fb_pitch = new_fb_pitch;
|
||||
need_recalc = true;
|
||||
}
|
||||
uint8_t* new_fb_ptr = &this->vram_ptr[extract_bits<uint32_t>(this->regs[ATI_CRTC_OFF_PITCH],
|
||||
ATI_CRTC_OFFSET, ATI_CRTC_OFFSET_size) * 8];
|
||||
if (new_fb_ptr != this->fb_ptr) {
|
||||
this->fb_ptr = new_fb_ptr;
|
||||
need_recalc = true;
|
||||
}
|
||||
|
||||
// look up which VPLL ouput is requested
|
||||
int clock_sel = extract_bits<uint32_t>(this->regs[ATI_CLOCK_CNTL], ATI_CLOCK_SEL,
|
||||
ATI_CLOCK_SEL_size);
|
||||
|
@ -781,14 +832,6 @@ void ATIRage::crtc_update() {
|
|||
LOG_F(ERROR, "%s: unsupported pixel format %d", this->name.c_str(), this->pixel_format);
|
||||
}
|
||||
|
||||
static uint8_t bits_per_pixel[8] = {0, 4, 8, 16, 16, 24, 32, 0};
|
||||
|
||||
this->fb_pitch = extract_bits<uint32_t>(this->regs[ATI_CRTC_OFF_PITCH],
|
||||
ATI_CRTC_PITCH, ATI_CRTC_PITCH_size) * (bits_per_pixel[this->pixel_format & 7] * 8) >> 3;
|
||||
|
||||
this->fb_ptr = &this->vram_ptr[extract_bits<uint32_t>(this->regs[ATI_CRTC_OFF_PITCH],
|
||||
ATI_CRTC_OFFSET, ATI_CRTC_OFFSET_size) * 8];
|
||||
|
||||
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], ATI_CRTC_EXT_DISP_EN) ? "extended" : "VGA");
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -57,7 +57,7 @@ namespace loguru {
|
|||
}
|
||||
|
||||
ControlVideo::ControlVideo()
|
||||
: PCIDevice("Control-Video"), VideoCtrlBase(640, 480)
|
||||
: PCIDevice("Control-Video"), VideoCtrlBase()
|
||||
{
|
||||
supports_types(HWCompType::PCI_HOST | HWCompType::PCI_DEV);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-23 divingkatae and maximum
|
||||
Copyright (C) 2018-24 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
|
@ -29,26 +29,197 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include <map>
|
||||
#include <string>
|
||||
|
||||
typedef struct {
|
||||
uint16_t h;
|
||||
uint16_t v;
|
||||
float pixel_clock; // MHz
|
||||
float h_freq; // kHz
|
||||
float refresh; // Hz
|
||||
} MonitorRes;
|
||||
|
||||
typedef struct {
|
||||
uint8_t std_sense_code;
|
||||
uint8_t ext_sense_code;
|
||||
const char * apple_enum;
|
||||
const char * name;
|
||||
const char * description;
|
||||
MonitorRes resolutions[4];
|
||||
} MonitorInfo;
|
||||
|
||||
/** Mapping between monitor IDs and their sense codes. */
|
||||
static const std::map<std::string, uint16_t> MonitorIdToCode = {
|
||||
{ "MacColor21in" , 0x00FF },
|
||||
{ "PortraitGS" , 0x01FF },
|
||||
{ "MacRGB12in" , 0x02FF },
|
||||
{ "TwoPageGS" , 0x03FF },
|
||||
{ "NTSC" , 0x04FF },
|
||||
{ "MacRGB15in" , 0x05FF },
|
||||
{ "HiRes12-14in" , 0x06FF },
|
||||
{ "Multiscan15in" , 0x0603 },
|
||||
{ "Multiscan17in" , 0x060B },
|
||||
{ "Multiscan20in" , 0x0623 },
|
||||
{ "AppleVision1710" , 0x062B }, // this code is assigned to several different monitors!
|
||||
{ "PALEncoder" , 0x0700 }, // no clue what it means
|
||||
{ "NTSCEncoder" , 0x0714 }, // no clue what it means
|
||||
{ "VGA-SVGA" , 0x0717 },
|
||||
{ "MacRGB16in" , 0x072D },
|
||||
{ "MacRGB19in" , 0x073A },
|
||||
{ "PAL" , 0x0730 },
|
||||
{ "NotConnected" , 0x07FF }
|
||||
static const std::map<std::string, MonitorInfo> MonitorIdToCode = {
|
||||
{ "MacColor21in", {
|
||||
0, 0x00,
|
||||
"kESCZero21Inch",
|
||||
"21\" RGB",
|
||||
"RGB 21\", 21\" Color, Apple 21S Color", {
|
||||
{1152, 870, 100 , 68.7 , 75 }
|
||||
}
|
||||
}},
|
||||
{ "PortraitGS", {
|
||||
1, 0x14,
|
||||
"kESCOnePortraitMono",
|
||||
"Portrait Monochrome",
|
||||
"B&W 15\", Apple Portrait", {
|
||||
{ 640, 870, 57.2832, 68.9 , 75 }
|
||||
}
|
||||
}},
|
||||
{ "MacRGB12in", {
|
||||
2, 0x21,
|
||||
"kESCTwo12Inch",
|
||||
"12\" RGB",
|
||||
"12\" Apple RGB", {
|
||||
{ 512, 384, 15.6672, 24.48 , 60.15}
|
||||
}
|
||||
}},
|
||||
{ "Radius21in", {
|
||||
3, 0x31,
|
||||
"kESCThree21InchRadius",
|
||||
"21\" RGB (Radius)",
|
||||
"", {
|
||||
{1152, 870, 100 , 68.7 , 75 }
|
||||
}
|
||||
}},
|
||||
{ "Radius21inGS", {
|
||||
3, 0x34,
|
||||
"kESCThree21InchMonoRadius",
|
||||
"21\" Monochrome (Radius)",
|
||||
"", {
|
||||
{1152, 870, 100 , 68.7 , 75 }
|
||||
}
|
||||
}},
|
||||
{ "TwoPageGS", {
|
||||
3, 0x35,
|
||||
"kESCThree21InchMono",
|
||||
"21\" Monochrome",
|
||||
"B&W 21\", Apple 2 Page Mono", {
|
||||
{1152, 870, 100 , 68.7 , 75 }
|
||||
}
|
||||
}},
|
||||
{ "NTSC", {
|
||||
4, 0x0A,
|
||||
"kESCFourNTSC",
|
||||
"NTSC",
|
||||
"NTSC underscan 512x384, overscan", {
|
||||
{ 640, 480, 12.2727, 15.7 , 59.94}
|
||||
}
|
||||
}},
|
||||
{ "MacRGB15in", {
|
||||
5, 0x1E,
|
||||
"kESCFivePortrait",
|
||||
"Portrait RGB",
|
||||
"RGB 15\", 15\" Tilt", {
|
||||
{ 640, 870, 57.2834, 0 , 0 }
|
||||
}
|
||||
}},
|
||||
{ "Multiscan15in", {
|
||||
6, 0x03,
|
||||
"kESCSixMSB1",
|
||||
"MultiScan Band-1 (12\" thru 16\")",
|
||||
"Multiple Scan 13, 14\"", {
|
||||
{ 640, 480, 67 , 0 , 0 },
|
||||
{ 832, 624, 75 , 0 , 0 }
|
||||
}
|
||||
}},
|
||||
{ "Multiscan17in", {
|
||||
6, 0x0B,
|
||||
"kESCSixMSB2",
|
||||
"MultiScan Band-2 (13\" thru 19\")",
|
||||
"Multiple Scan 16, 17\"", {
|
||||
{ 640, 480, 67 , 0 , 0 },
|
||||
{ 832, 624, 75 , 0 , 0 },
|
||||
{1024, 768, 75 , 0 , 0 }
|
||||
}
|
||||
}},
|
||||
{ "Multiscan20in", {
|
||||
6, 0x23,
|
||||
"kESCSixMSB3",
|
||||
"MultiScan Band-3 (13\" thru 21\")",
|
||||
"Multiple Scan 20, 21\"", {
|
||||
{ 640, 480, 67 , 0 , 0 },
|
||||
{ 832, 624, 75 , 0 , 0 },
|
||||
{1024, 768, 75 , 0 , 0 },
|
||||
{1152, 870, 75 , 0 , 0 }
|
||||
}
|
||||
}},
|
||||
{ "HiRes12-14in", {
|
||||
6, 0x2B,
|
||||
"kESCSixStandard",
|
||||
"13\"/14\" RGB or 12\" Monochrome",
|
||||
"B&W 12\", 12\" Apple Monochrome, 13\" Apple RGB, Hi-Res 12-14\"", {
|
||||
{ 640, 480, 30.24 , 35.0 , 66.7 },
|
||||
}
|
||||
}},
|
||||
{ "PALEncoder", {
|
||||
7, 0x00,
|
||||
"kESCSevenPAL",
|
||||
"PAL",
|
||||
"PAL, NTSC/PAL (Option 1)", {
|
||||
{ 640, 480, 14.75 , 15.625, 50 },
|
||||
{ 768, 576, 14.75 , 15.625, 50 }
|
||||
}
|
||||
}},
|
||||
{ "NTSCEncoder", {
|
||||
7, 0x14,
|
||||
"kESCSevenNTSC",
|
||||
"NTSC",
|
||||
"NTSC w/convolution (Alternate)", {
|
||||
{ 640, 480, 12.2727, 0 , 0 }
|
||||
}
|
||||
}},
|
||||
{ "VGA-SVGA", {
|
||||
7, 0x17,
|
||||
"kESCSevenVGA",
|
||||
"VGA",
|
||||
"VGA", {
|
||||
{ 640, 480, 25.175 , 31.47 , 59.95},
|
||||
{ 800, 600, 36 , 35.16 , 56 },
|
||||
{1024, 768, 35.16 , 60 }
|
||||
}
|
||||
}},
|
||||
{ "MacRGB16in", {
|
||||
7, 0x2D,
|
||||
"kESCSeven16Inch",
|
||||
"16\" RGB (GoldFish)",
|
||||
"RGB 16\", 16\" Color", {
|
||||
{ 832, 624, 57.2832, 49.7 , 75 }
|
||||
}
|
||||
}},
|
||||
{ "PAL", {
|
||||
7, 0x30,
|
||||
"kESCSevenPALAlternate",
|
||||
"PAL (Alternate)",
|
||||
"PAL w/convolution (Alternate) (Option 2)", {
|
||||
{ 640, 480, 14.75 , 15.625, 50 },
|
||||
{ 768, 576, 14.75 , 15.625, 50 }
|
||||
}
|
||||
}},
|
||||
{ "MacRGB19in", {
|
||||
7, 0x3A,
|
||||
"kESCSeven19Inch",
|
||||
"Third-Party 19",
|
||||
"RGB 19\", 19\" Color", {
|
||||
{1024, 768, 80 , 0 , 0 }
|
||||
}
|
||||
}},
|
||||
{ "DDC", {
|
||||
7, 0x3E,
|
||||
"kESCSevenDDC",
|
||||
"DDC display",
|
||||
"EDID", {
|
||||
{1024, 768, 80 , 0 , 0 }
|
||||
}
|
||||
}},
|
||||
{ "NotConnected", {
|
||||
7, 0x3F,
|
||||
"kESCSevenNoDisplay",
|
||||
"No display connected",
|
||||
"no-connect"
|
||||
}},
|
||||
};
|
||||
|
||||
static const std::map<std::string, std::string> MonitorAliasToId = {
|
||||
{ "AppleVision1710", "HiRes12-14in" }
|
||||
};
|
||||
|
||||
DisplayID::DisplayID()
|
||||
|
@ -58,14 +229,17 @@ DisplayID::DisplayID()
|
|||
|
||||
std::string mon_id = GET_STR_PROP("mon_id");
|
||||
if (!mon_id.empty()) {
|
||||
if (MonitorAliasToId.count(mon_id)) {
|
||||
mon_id = MonitorAliasToId.at(mon_id);
|
||||
}
|
||||
if (MonitorIdToCode.count(mon_id)) {
|
||||
auto sense_code = MonitorIdToCode.at(mon_id);
|
||||
this->std_sense_code = (sense_code >> 8) & 0xFFU;
|
||||
this->ext_sense_code = (sense_code >> 0) & 0xFFU;
|
||||
auto monitor = MonitorIdToCode.at(mon_id);
|
||||
this->std_sense_code = monitor.std_sense_code;
|
||||
this->ext_sense_code = monitor.ext_sense_code;
|
||||
this->id_kind = Disp_Id_Kind::AppleSense;
|
||||
LOG_F(INFO, "DisplayID mode set to AppleSense");
|
||||
LOG_F(INFO, "Standard sense code: 0x%d", this->std_sense_code);
|
||||
LOG_F(INFO, "Extended sense code: 0x%X", this->ext_sense_code);
|
||||
LOG_F(INFO, "Standard sense code: %d", this->std_sense_code);
|
||||
LOG_F(INFO, "Extended sense code: 0x%02X", this->ext_sense_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
#include <string>
|
||||
|
||||
TaosVideo::TaosVideo() : VideoCtrlBase(640, 480) {
|
||||
TaosVideo::TaosVideo() : VideoCtrlBase() {
|
||||
set_name("Taos");
|
||||
|
||||
supports_types(HWCompType::MMIO_DEV);
|
||||
|
|
Loading…
Reference in New Issue
Block a user