Merge pull request #32 from joevt/master

PCI fixes
This commit is contained in:
dingusdev 2022-09-02 07:42:01 -07:00 committed by GitHub
commit 467e4df7dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 311 additions and 161 deletions

View File

@ -81,15 +81,27 @@ uint32_t Bandit::pci_cfg_read(uint32_t reg_offs, uint32_t size)
if (reg_offs < 64) {
return PCIDevice::pci_cfg_read(reg_offs, size);
}
switch (reg_offs) {
case BANDIT_ADDR_MASK:
return BYTESWAP_32(this->addr_mask);
default:
LOG_F(WARNING, "%s: reading from unimplemented config register at 0x%X",
this->pci_name.c_str(), reg_offs);
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned read @%02x.%c",
this->name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
}
if (reg_offs == BANDIT_ADDR_MASK) {
return pci_cfg_rev_read(this->addr_mask, offset, size);
}
LOG_F(
WARNING, "%s: reading from unimplemented config register @%02x.%c",
this->name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
return 0;
}
@ -100,15 +112,27 @@ void Bandit::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
return;
}
switch (reg_offs) {
case BANDIT_ADDR_MASK:
this->addr_mask = BYTESWAP_32(value);
this->verbose_address_space();
break;
default:
LOG_F(WARNING, "%s: writing to unimplemented config register at 0x%X",
this->pci_name.c_str(), reg_offs);
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned write @%02x.%c = %0*x",
this->name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
if (reg_offs == BANDIT_ADDR_MASK) {
this->addr_mask = pci_cfg_rev_write(this->addr_mask, offset, size, value);
this->verbose_address_space();
return;
}
LOG_F(
WARNING, "%s: writing to unimplemented config register @%02x.%c = %0*x",
this->name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
uint32_t Bandit::read(uint32_t rgn_start, uint32_t offset, int size)
@ -147,10 +171,10 @@ uint32_t Bandit::read(uint32_t rgn_start, uint32_t offset, int size)
}
if (idsel == BANDIT_ID_SEL) { // access to myself
result = this->pci_cfg_read(reg_offs, size);
result = this->pci_cfg_read(reg_offs + (offset & 3), size);
} else {
if (this->dev_map.count(idsel)) {
result = this->dev_map[idsel]->pci_cfg_read(reg_offs, size);
result = this->dev_map[idsel]->pci_cfg_read(reg_offs + (offset & 3), size);
} else {
dev_num = WHAT_BIT_SET(idsel) + 11;
LOG_F(
@ -196,7 +220,7 @@ void Bandit::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size
LOG_F(
WARNING, "%s: write config cycle type 1 not supported yet %02x:%02x.%x @%02x.%c = %0*x",
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3),
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, value
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
return;
}
@ -208,24 +232,24 @@ void Bandit::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size
ERROR, "%s: write invalid IDSEL=0x%X config:0x%X ??:??.%x? @%02x?.%c = %0*x",
this->name.c_str(), idsel, this->config_addr,
fun_num, reg_offs + (offset & 3),
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, value
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
return;
}
if (idsel == BANDIT_ID_SEL) { // access to myself
this->pci_cfg_write(reg_offs, value, size);
this->pci_cfg_write(reg_offs + (offset & 3), value, size);
return;
}
if (this->dev_map.count(idsel)) {
this->dev_map[idsel]->pci_cfg_write(reg_offs, value, size);
this->dev_map[idsel]->pci_cfg_write(reg_offs + (offset & 3), value, size);
} else {
dev_num = WHAT_BIT_SET(idsel) + 11;
LOG_F(
ERROR, "%s err: write attempt to non-existing PCI device ??:%02x.%x @%02x.%c = %0*x",
this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3),
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, value
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
} else {
@ -320,7 +344,7 @@ uint32_t Chaos::read(uint32_t rgn_start, uint32_t offset, int size)
}
if (this->dev_map.count(idsel)) {
result = this->dev_map[idsel]->pci_cfg_read(reg_offs, size);
result = this->dev_map[idsel]->pci_cfg_read(reg_offs + (offset & 3), size);
} else {
dev_num = WHAT_BIT_SET(idsel) + 11;
LOG_F(
@ -358,7 +382,7 @@ void Chaos::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
LOG_F(
WARNING, "%s: write config cycle type 1 not supported yet %02x:%02x.%x @%02x.%c = %0*x",
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3),
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, value
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
return;
}
@ -370,19 +394,19 @@ void Chaos::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
ERROR, "%s: write invalid IDSEL=0x%X config:0x%X ??:??.%x? @%02x?.%c = %0*x",
this->name.c_str(), idsel, this->config_addr,
fun_num, reg_offs + (offset & 3),
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, value
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
return;
}
if (this->dev_map.count(idsel)) {
this->dev_map[idsel]->pci_cfg_write(reg_offs, value, size);
this->dev_map[idsel]->pci_cfg_write(reg_offs + (offset & 3), value, size);
} else {
dev_num = WHAT_BIT_SET(idsel) + 11;
LOG_F(
ERROR, "%s err: write attempt to non-existing VCI device ??:%02x.%x @%02x.%c = %0*x",
this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3),
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, value
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
} else {

View File

@ -52,6 +52,16 @@ uint32_t PCIDevice::pci_cfg_read(uint32_t reg_offs, uint32_t size)
{
uint32_t result;
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned read @%02x.%c",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
}
switch (reg_offs) {
case PCI_CFG_DEV_ID:
result = (this->device_id << 16) | (this->vendor_id);
@ -89,31 +99,32 @@ uint32_t PCIDevice::pci_cfg_read(uint32_t reg_offs, uint32_t size)
default:
LOG_F(
WARNING, "%s: attempt to read from reserved/unimplemented register @%02x.%c",
this->pci_name.c_str(), reg_offs,
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
return 0;
}
if (size == 4) {
return BYTESWAP_32(result);
} else {
return read_mem_rev(((uint8_t *)&result) + (reg_offs & 3), size);
}
return pci_cfg_rev_read(result, offset, size);
}
void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
{
uint32_t data;
if (size == 4) {
data = BYTESWAP_32(value);
} else {
// get current register content as DWORD and update it partially
data = BYTESWAP_32(this->pci_cfg_read(reg_offs, 4));
write_mem_rev(((uint8_t *)&data) + (reg_offs & 3), value, size);
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned write @%02x.%c = %0*x",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
// get current register content as DWORD and update it partially
data = pci_cfg_rev_write(size == 4 ? 0 : BYTESWAP_32(this->pci_cfg_read(reg_offs, 4)), offset, size, value);
switch (reg_offs) {
case PCI_CFG_STAT_CMD:
this->pci_wr_stat(data >> 16);
@ -137,10 +148,10 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
}
break;
case PCI_CFG_ROM_BAR:
if (data == 0xFFFFF800UL) {
this->exp_rom_bar = this->exp_bar_cfg;
if ((data & this->exp_bar_cfg) == this->exp_bar_cfg) {
this->exp_rom_bar = (data & (this->exp_bar_cfg | 1));
} else {
this->exp_rom_bar = (data & 0xFFFFF801UL);
this->exp_rom_bar = (data & (this->exp_bar_cfg | 1));
if (this->exp_rom_bar & 1) {
this->map_exp_rom_mem();
} else {
@ -156,7 +167,7 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
LOG_F(
WARNING, "%s: attempt to write to reserved/unimplemented register @%02x.%c = %0*x",
this->pci_name.c_str(), reg_offs,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, value
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
}
@ -243,7 +254,7 @@ void PCIDevice::set_bar_value(int bar_num, uint32_t value)
{
uint32_t bar_cfg = this->bars_cfg[bar_num];
if (bar_cfg & 1) {
this->bars[bar_num] = (value & 0xFFFFFFFCUL) | 1;
this->bars[bar_num] = (value & 0xFFFFFFFCUL) | (bar_cfg & 3);
} else {
if (bar_cfg & 6) {
ABORT_F("Invalid or unsupported PCI space type: %d", (bar_cfg >> 1) & 3);
@ -257,7 +268,7 @@ void PCIDevice::map_exp_rom_mem()
{
uint32_t rom_addr, rom_size;
rom_addr = this->exp_rom_bar & 0xFFFFF800UL;
rom_addr = this->exp_rom_bar & this->exp_bar_cfg;
rom_size = ~this->exp_bar_cfg + 1;
if (!this->exp_rom_addr || this->exp_rom_addr != rom_addr) {

View File

@ -64,7 +64,7 @@ static FlopImgType identify_image(std::ifstream& img_file)
}
}
return FlopImgType::UNKNOWN;
return FlopImgType::RAW;
}
static int64_t get_hfs_vol_size(const uint8_t *mdb_data)
@ -133,17 +133,16 @@ int RawFloppyImg::calc_phys_params()
} else if (buf[0] == 0xD2 && buf[1] == 0xD7) {
// check MFS volume size
} else {
LOG_F(ERROR, "RawFloppyImg: unknown volume type!");
return -1;
LOG_F(WARNING, "RawFloppyImg: unknown volume type!");
}
if (vol_size > this->img_size) {
if (vol_size && (vol_size > this->img_size)) {
LOG_F(INFO, "RawFloppyImg: volume size > image size!");
LOG_F(INFO, "Volume size: %llu, Image size: %d", vol_size, this->img_size);
return -1;
}
// raw images don't include anything than raw disk data
// raw images don't include anything other than raw disk data
this->data_size = this->img_size;
// guess disk format from image file size

View File

@ -89,7 +89,7 @@ uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) {
} else {
if (offset >= 0x200000) {
if (this->config_addr & 0x80) // process only if bit E (enable) is set
return pci_read(size);
return pci_read(offset & 3, size);
}
}
@ -113,39 +113,39 @@ void MPC106::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size
this->config_addr = value;
} else {
if (this->config_addr & 0x80) // process only if bit E (enable) is set
return pci_write(value, size);
return pci_write(offset & 3, value, size);
}
}
}
uint32_t MPC106::pci_read(uint32_t size) {
uint32_t MPC106::pci_read(uint32_t offset, uint32_t size) {
int bus_num, dev_num, fun_num, reg_offs;
bus_num = (this->config_addr >> 8) & 0xFF;
bus_num = (this->config_addr >> 8) & 0xFF;
dev_num = (this->config_addr >> 19) & 0x1F;
fun_num = (this->config_addr >> 16) & 0x07;
reg_offs = (this->config_addr >> 24) & 0xFC;
if (bus_num) {
LOG_F(
ERROR,
"%s err: read attempt from non-local PCI bus, config_addr = %x %02x:%02x.%x @%02x.%c",
this->name.c_str(), this->config_addr, bus_num, dev_num, fun_num, reg_offs,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
LOG_F(
ERROR,
"%s err: read attempt from non-local PCI bus, config_addr = %x, offset = %x %02x:%02x.%x @%02x.%c",
this->name.c_str(), this->config_addr, offset, bus_num, dev_num, fun_num, reg_offs,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
return 0xFFFFFFFFUL; // PCI spec §6.1
}
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
return this->pci_cfg_read(reg_offs, size);
return this->pci_cfg_read(reg_offs + offset, size);
} else {
if (this->dev_map.count(dev_num)) {
return this->dev_map[dev_num]->pci_cfg_read(reg_offs, size);
return this->dev_map[dev_num]->pci_cfg_read(reg_offs + offset, size);
} else {
LOG_F(
ERROR,
"%s err: read attempt from non-existing PCI device %02x:%02x.%x @%02x.%c",
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs,
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
return 0xFFFFFFFFUL; // PCI spec §6.1
@ -155,10 +155,10 @@ uint32_t MPC106::pci_read(uint32_t size) {
return 0;
}
void MPC106::pci_write(uint32_t value, uint32_t size) {
void MPC106::pci_write(uint32_t offset, uint32_t value, uint32_t size) {
int bus_num, dev_num, fun_num, reg_offs;
bus_num = (this->config_addr >> 8) & 0xFF;
bus_num = (this->config_addr >> 8) & 0xFF;
dev_num = (this->config_addr >> 19) & 0x1F;
fun_num = (this->config_addr >> 16) & 0x07;
reg_offs = (this->config_addr >> 24) & 0xFC;
@ -166,26 +166,26 @@ void MPC106::pci_write(uint32_t value, uint32_t size) {
if (bus_num) {
LOG_F(
ERROR,
"%s err: write attempt to non-local PCI bus, config_addr = %x %02x:%02x.%x @%02x.%c = %0*x",
this->name.c_str(), this->config_addr, bus_num, dev_num, fun_num, reg_offs,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size,
size * 2, value
);
"%s err: write attempt to non-local PCI bus, config_addr = %x, offset = %x %02x:%02x.%x @%02x.%c = %0*x",
this->name.c_str(), this->config_addr, offset, bus_num, dev_num, fun_num, reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size,
size * 2, flip_sized(value, size)
);
return;
}
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
this->pci_cfg_write(reg_offs, value, size);
this->pci_cfg_write(reg_offs + offset, value, size);
} else {
if (this->dev_map.count(dev_num)) {
this->dev_map[dev_num]->pci_cfg_write(reg_offs, value, size);
this->dev_map[dev_num]->pci_cfg_write(reg_offs + offset, value, size);
} else {
LOG_F(
ERROR,
"%s err: write attempt to non-existing PCI device %02x:%02x.%x @%02x.%c = %0*x",
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs,
this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size,
size * 2, value
size * 2, flip_sized(value, size)
);
}
}
@ -200,7 +200,17 @@ uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size) {
return PCIDevice::pci_cfg_read(reg_offs, size);
}
return read_mem(&this->my_pci_cfg_hdr[reg_offs], size);
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned read @%02x.%c",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
}
return pci_cfg_rev_read(READ_DWORD_LE_A(&this->my_pci_cfg_hdr[reg_offs]), offset, size);
}
void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) {
@ -213,9 +223,20 @@ void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) {
return;
}
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned write @%02x.%c = %0*x",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
// FIXME: implement write-protection for read-only registers
write_mem(&this->my_pci_cfg_hdr[reg_offs], value, size);
uint32_t *addr = (uint32_t *)&this->my_pci_cfg_hdr[reg_offs];
WRITE_DWORD_LE_A(addr, pci_cfg_rev_write(READ_DWORD_LE_A(addr), offset, size, value));
if (this->my_pci_cfg_hdr[0xF2] & 8) {
#ifdef MPC106_DEBUG

View File

@ -59,8 +59,8 @@ public:
protected:
/* PCI access */
uint32_t pci_read(uint32_t size);
void pci_write(uint32_t value, uint32_t size);
uint32_t pci_read(uint32_t offset, uint32_t size);
void pci_write(uint32_t offset, uint32_t value, uint32_t size);
/* my own PCI configuration registers access */
uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size);

View File

@ -167,11 +167,25 @@ uint32_t ATIRage::pci_cfg_read(uint32_t reg_offs, uint32_t size)
return PCIDevice::pci_cfg_read(reg_offs, size);
}
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned read @%02x.%c",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
}
switch (reg_offs) {
case 0x40:
return this->user_cfg;
return pci_cfg_rev_read(this->user_cfg, offset, size);
default:
LOG_F(WARNING, "ATIRage: reading from unimplemented config register at 0x%X", reg_offs);
LOG_F(
WARNING, "%s: reading from unimplemented config register @%02x.%c",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size
);
}
return 0;
@ -181,14 +195,29 @@ void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
{
if (reg_offs < 64) {
PCIDevice::pci_cfg_write(reg_offs, value, size);
} else {
switch (reg_offs) {
case 0x40:
this->user_cfg = value;
break;
default:
LOG_F(WARNING, "ATIRage: writing to unimplemented config register at 0x%X", reg_offs);
}
return;
}
uint32_t offset = reg_offs & 3;
reg_offs &= ~3;
if (~-size & offset) {
LOG_F(
WARNING, "%s: unaligned write @%02x.%c = %0*x",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
switch (reg_offs) {
case 0x40:
this->user_cfg = pci_cfg_rev_write(this->user_cfg, offset, size, value);
break;
default:
LOG_F(
WARNING, "%s: writing to unimplemented config register @%02x.%c = %0*x",
this->pci_name.c_str(), reg_offs + offset,
size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, size * 2, flip_sized(value, size)
);
}
}

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;

View File

@ -177,6 +177,60 @@ inline uint32_t read_mem_rev(const uint8_t* buf, uint32_t size) {
}
}
/* value is dword from PCI config. MSB..LSB of value is stored in PCI config as 0:LSB..3:MSB.
result is part of value at byte offset from LSB and size bytes (with wrap around) and flipped as required for pci_cfg_read result. */
inline uint32_t pci_cfg_rev_read(uint32_t value, uint32_t offset, uint32_t size) {
switch (size << 2 | offset) {
case 0x04: return value & 0xff; // 0
case 0x05: return (value >> 8) & 0xff; // 1
case 0x06: return (value >> 16) & 0xff; // 2
case 0x07: return (value >> 24) & 0xff; // 3
case 0x08: return ((value & 0xff) << 8) | ((value >> 8) & 0xff); // 0 1
case 0x09: return ( value & 0xff00) | ((value >> 16) & 0xff); // 1 2
case 0x0a: return ((value >> 8) & 0xff00) | ((value >> 24) & 0xff); // 2 3
case 0x0b: return ((value >> 16) & 0xff00) | ( value & 0xff); // 3 0
case 0x10: return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value >> 8) & 0xff00) | ((value >> 24) & 0xff); // 0 1 2 3
case 0x11: return ((value & 0xff00) << 16) | ( value & 0xff0000) | ((value >> 16) & 0xff00) | ( value & 0xff); // 1 2 3 0
case 0x12: return ((value & 0xff0000) << 8) | ((value >> 8) & 0xff0000) | ((value & 0xff) << 8) | ((value >> 8) & 0xff); // 2 3 0 1
case 0x13: return ( value & 0xff000000) | ((value & 0xff) << 16) | ( value & 0xff00) | ((value >> 16) & 0xff); // 3 0 1 2
default: LOG_F(ERROR, "pci_cfg_rev: invalid offset %d for size %d!", offset, size); return 0xffffffff;
}
}
/* value is dword from PCI config. MSB..LSB of value (3.2.1.0) is stored in PCI config as 0:LSB..3:MSB.
data is flipped bytes (d0.d1.d2.d3, as passed to pci_cfg_write) to be merged into value.
result is part of value at byte offset from LSB and size bytes (with wrap around) modified by data. */
inline uint32_t pci_cfg_rev_write(uint32_t value, uint32_t offset, uint32_t size, uint32_t data) {
switch (size << 2 | offset) {
case 0x04: return (value & 0xffffff00) | (data & 0xff); // 3 2 1 d0
case 0x05: return (value & 0xffff00ff) | ((data & 0xff) << 8); // 3 2 d0 0
case 0x06: return (value & 0xff00ffff) | ((data & 0xff) << 16); // 3 d0 1 0
case 0x07: return (value & 0x00ffffff) | ((data & 0xff) << 24); // d0 2 1 0
case 0x08: return (value & 0xffff0000) | ((data >> 8) & 0xff) | ((data & 0xff) << 8); // 3 2 d1 d0
case 0x09: return (value & 0xff0000ff) | (data & 0xff00) | ((data & 0xff) << 16); // 3 d1 d0 0
case 0x0a: return (value & 0x0000ffff) | ((data & 0xff00) << 8) | ((data & 0xff) << 24); // d1 d0 1 0
case 0x0b: return (value & 0x00ffff00) | ((data & 0xff00) << 16) | (data & 0xff); // d0 2 1 d1
case 0x10: return ((data & 0xff) << 24) | ((data & 0xff00) << 8) | ((data >> 8) & 0xff00) | ((data >> 24) & 0xff); // d3 d2 d1 d0
case 0x11: return ((data & 0xff00) << 16) | ( data & 0xff0000) | ((data >> 16) & 0xff00) | ( data & 0xff); // d2 d1 d0 d3
case 0x12: return ((data & 0xff0000) << 8) | ((data >> 8) & 0xff0000) | ((data & 0xff) << 8) | ((data >> 8) & 0xff); // d1 d0 d3 d2
case 0x13: return ( data & 0xff000000) | ((data & 0xff) << 16) | ( data & 0xff00) | ((data >> 16) & 0xff); // d0 d3 d2 d1
default: LOG_F(ERROR, "pci_cfg_rev: invalid offset %d for size %d!", offset, size); return 0xffffffff;
}
}
inline uint32_t flip_sized(uint32_t value, uint32_t size) {
switch (size) {
case 1: return value;
case 2: return BYTESWAP_16(value);
case 4: return BYTESWAP_32(value);
default: LOG_F(ERROR, "flip_sized: invalid size %d!", size); return 0xffffffff;
}
}
/* write the specified value of the specified size to memory pointed
to by addr, perform necessary byte swapping so that the byte order
of the destination remains unchanged. */