From an emulation point of view, this doesn't matter too much, although looking at how the device is supposed to be initialized clarifies some things that previously didn't make sense to me in VF3's SCSI logic. For completeness' sake, we should eventually make the SCSI emulator more strictly correct. More importantly, though, this is definitely one of the reasons my SCSI DMA code failed. I'd like to try to run another test, possibly this Saturday (though I won't be able to do much more than that even if it succeeds), since I'll be at my parents' for the weekend.
I'll eventually need to check for any other PCI devices (like the Real3D itself) that may not be getting initialized properly. While not really important from an emulation perspective, it is important for understanding how to bring the device up when trying to run new code on it. I was assuming Supermodel was accurate enough and was simply trapping all writes to hardware I was interested in bringing up, and then replicating those sequences in my Model 3 test program. This obviously isn't sufficient if Supermodel is skipping over important initialization routines!
Here's VF3's init routine. Note the test it performs to ensure that an LSI 53c810a SCSI controller is actually present on the PCI bus. Unsure yet whether there are other routines that need to run, too.
- Code: Select all
void Sub619B0()
{
uint32_t device_and_vendor_id = ReadPCIConfig(0, 0xe, 0, 0); // device in high 16 bits, vendor in low 16 bits
uint32_t lsi53c810a_id = 0x11000;
if (device_and_vendor_id != lsi53c810a_id)
goto _61a2c;
WritePCIConfig(0x14, 0xe, 0, 0, 0xc0000000); // set device base address
WritePCIConfig(0x0c, 0xe, 0, 0, 0xff00); // cache line size and latency timer
WritePCIConfig(4, 0xe, 0, 0, 6); // enable bus mastering and memory space
scsi_regs[0x38] = 0xc1; // DMODE (DMA Mode) = 0xc1 (16-transfer burst, manual start mode)
scsi_regs[0x39] = scsi_regs[0x39] | 0x08; // DIEN (DMA Interrupt Enable) |= 0x08 (enable single-step interrupt)
_61a2c:
_6c4f = 0x00;
_6c50 = 0x00;
return device_and_vendor_id
}
uint32_t ReadPCIConfig(uint32_t pci_reg, uint32_t pci_device, uint32_t pci_bus, uint32_t pci_function)
{
uint32_t cmd = 0x80000000;
cmd |= (pci_reg & 0xfc);
cmd |= ((pci_device << 11) & 0xf800);
cmd |= ((pci_bus << 16) & 0x00ff0000);
cmd |= ((pci_function << 8) & 0x700);
ppc_stwbrx(0xf0800cf8, cmd);
return ppc_lwbrx(0xf0c00cfc);
}
void WritePCIConfig(uint32_t pci_reg, uint32_t pci_device, uint32_t pci_bus, uint32_t pci_function, uint32_t data)
{
uint32_t cmd = 0x80000000;
cmd |= (pci_reg & 0xfc);
cmd |= ((pci_device << 11) & 0xf800);
cmd |= ((pci_bus << 16) & 0xff0000);
cmd |= ((pci_function << 8) & 0x700);
ppc_stwbrx(0xf0800cf8, cmd);
ppc_stwbrx(0xf0c00cfc, data);
}
