mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-24 13:30:26 +00:00
commit
467e4df7dc
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
54
memaccess.h
54
memaccess.h
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user