Add BAR 0 to control

BAR 0 exists on a real Power Mac 8600 and the dingusppc 7500.

On a Power Mac 8600, the initial value is 0x84000003. In Open Firmware, you can write to all bits of the BAR and read the value back except the 2 least significant bits are always %11. Bit 0 indicates I/O space. Bit 1 is reserved and should be zero so maybe this is not a real I/O space BAR. 0x8400000 is written to the BAR by Open Firmware. It doesn't look like a normal I/O address which are usually 16 bits.

On the emulated 7500, 0x02000000 is written to the BAR by Open Firmware sometime during probe-all. The BAR did not behave as it does in the Power Mac 8600. This commit fixes that.

Two questions remain:
1) Which fcode writes to the BAR? Is it the probe fcode or is it the control fcode? There's no config-_! in the control fcode.
2) What is the purpose of the BAR? Writing to it can cause a hang. The testbits code below seems to succeed - it restores the original value after reading the result of testing each bit and before displaying the result. The values shown for the MSB (0x84 on the 8600 and 0x02 on the 7500) could be three flag bits.

```
dev vci0
: testbits { adr ; org }
	cr
	adr config-l@ dup -> org ." original : " 8 u.r cr
	20 0 do
		1 1f i - << dup 8 u.r ."  : "
		adr config-l!
		adr config-l@
		org adr config-l!
		8 u.r cr
	loop
	;

15810 testbits \ 15810 is the address of the BAR on the emulated 7500.
```
This commit is contained in:
joevt 2022-09-02 00:18:00 -07:00
parent a24840803c
commit a08e70781a
2 changed files with 85 additions and 73 deletions

View File

@ -59,6 +59,7 @@ ControlVideo::ControlVideo()
this->vendor_id = PCI_VENDOR_APPLE;
this->device_id = 3;
this->class_rev = 0;
this->bars_cfg[0] = 0xFFFFFFFFUL; // I/O region (4 bytes but it's weird because bit 1 is set)
this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB)
this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB)
@ -84,6 +85,10 @@ ControlVideo::ControlVideo()
void ControlVideo::notify_bar_change(int bar_num)
{
switch (bar_num) {
case 0:
this->io_base = this->bars[bar_num] & ~3;
LOG_F(INFO, "Control: I/O space address set to 0x%08X", this->io_base);
break;
case 1:
if (this->regs_base != (this->bars[bar_num] & 0xFFFFFFF0UL)) {
this->regs_base = this->bars[bar_num] & 0xFFFFFFF0UL;
@ -116,18 +121,22 @@ uint32_t ControlVideo::read(uint32_t rgn_start, uint32_t offset, int size)
}
}
switch (offset >> 4) {
case ControlRegs::TEST:
result = this->test;
break;
case ControlRegs::MON_SENSE:
result = this->cur_mon_id << 6;
break;
default:
LOG_F(INFO, "read from 0x%08X:0x%08X", rgn_start, offset);
if (rgn_start == this->regs_base) {
switch (offset >> 4) {
case ControlRegs::TEST:
result = this->test;
break;
case ControlRegs::MON_SENSE:
result = this->cur_mon_id << 6;
break;
default:
LOG_F(INFO, "read from 0x%08X:0x%08X", rgn_start, offset);
}
return BYTESWAP_32(result);
}
return BYTESWAP_32(result);
return 0;
}
void ControlVideo::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
@ -141,75 +150,77 @@ void ControlVideo::write(uint32_t rgn_start, uint32_t offset, uint32_t value, in
return;
}
value = BYTESWAP_32(value);
if (rgn_start == this->regs_base) {
value = BYTESWAP_32(value);
switch (offset >> 4) {
case ControlRegs::VFPEQ:
case ControlRegs::VFP:
case ControlRegs::VAL:
case ControlRegs::VBP:
case ControlRegs::VBPEQ:
case ControlRegs::VSYNC:
case ControlRegs::VHLINE:
case ControlRegs::PIPED:
case ControlRegs::HPIX:
case ControlRegs::HFP:
case ControlRegs::HAL:
case ControlRegs::HBWAY:
case ControlRegs::HSP:
case ControlRegs::HEQ:
case ControlRegs::HLFLN:
case ControlRegs::HSERR:
this->swatch_params[(offset >> 4) - 1] = value;
break;
case ControlRegs::TEST:
if (this->test != value) {
if ((this->test & ~TEST_STROBE) != (value & ~TEST_STROBE)) {
this->test = value;
this->test_shift = 0;
LOG_F(9, "New TEST value: 0x%08X", this->test);
} else {
LOG_F(9, "TEST strobe bit flipped, new value: 0x%08X", value);
this->test = value;
if (++this->test_shift >= 3) {
LOG_F(9, "Received TEST reg value: 0x%08X", this->test & ~TEST_STROBE);
if ((this->test ^ this->prev_test) & 0x400) {
if (this->test & 0x400) {
this->disable_display();
} else {
this->enable_display();
switch (offset >> 4) {
case ControlRegs::VFPEQ:
case ControlRegs::VFP:
case ControlRegs::VAL:
case ControlRegs::VBP:
case ControlRegs::VBPEQ:
case ControlRegs::VSYNC:
case ControlRegs::VHLINE:
case ControlRegs::PIPED:
case ControlRegs::HPIX:
case ControlRegs::HFP:
case ControlRegs::HAL:
case ControlRegs::HBWAY:
case ControlRegs::HSP:
case ControlRegs::HEQ:
case ControlRegs::HLFLN:
case ControlRegs::HSERR:
this->swatch_params[(offset >> 4) - 1] = value;
break;
case ControlRegs::TEST:
if (this->test != value) {
if ((this->test & ~TEST_STROBE) != (value & ~TEST_STROBE)) {
this->test = value;
this->test_shift = 0;
LOG_F(9, "New TEST value: 0x%08X", this->test);
} else {
LOG_F(9, "TEST strobe bit flipped, new value: 0x%08X", value);
this->test = value;
if (++this->test_shift >= 3) {
LOG_F(9, "Received TEST reg value: 0x%08X", this->test & ~TEST_STROBE);
if ((this->test ^ this->prev_test) & 0x400) {
if (this->test & 0x400) {
this->disable_display();
} else {
this->enable_display();
}
this->prev_test = this->test;
}
this->prev_test = this->test;
}
}
}
break;
case ControlRegs::GBASE:
this->fb_base = value;
break;
case ControlRegs::ROW_WORDS:
this->row_words = value;
break;
case ControlRegs::MON_SENSE:
LOG_F(9, "Control: monitor sense written with 0x%X", value);
value = (value >> 3) & 7;
this->cur_mon_id = this->display_id->read_monitor_sense(value & 7, value ^ 7);
break;
case ControlRegs::ENABLE:
this->flags = value;
break;
case ControlRegs::GSC_DIVIDE:
this->clock_divider = value;
break;
case ControlRegs::REFRESH_COUNT:
LOG_F(INFO, "Control: refresh count set to 0x%08X", value);
break;
case ControlRegs::INT_ENABLE:
this->int_enable = value;
break;
default:
LOG_F(INFO, "write 0x%08X to 0x%08X:0x%08X", value, rgn_start, offset);
}
break;
case ControlRegs::GBASE:
this->fb_base = value;
break;
case ControlRegs::ROW_WORDS:
this->row_words = value;
break;
case ControlRegs::MON_SENSE:
LOG_F(9, "Control: monitor sense written with 0x%X", value);
value = (value >> 3) & 7;
this->cur_mon_id = this->display_id->read_monitor_sense(value & 7, value ^ 7);
break;
case ControlRegs::ENABLE:
this->flags = value;
break;
case ControlRegs::GSC_DIVIDE:
this->clock_divider = value;
break;
case ControlRegs::REFRESH_COUNT:
LOG_F(INFO, "Control: refresh count set to 0x%08X", value);
break;
case ControlRegs::INT_ENABLE:
this->int_enable = value;
break;
default:
LOG_F(INFO, "write 0x%08X to 0x%08X:0x%08X", value, rgn_start, offset);
}
}

View File

@ -117,6 +117,7 @@ private:
std::unique_ptr<uint8_t[]> vram_ptr;
uint32_t vram_size;
uint32_t io_base = 0;
uint32_t vram_base = 0;
uint32_t regs_base = 0;
uint32_t prev_test = 0x433;