xbox.cpp: add simple superio support and more usb (nw)

Bytes sent to the supoerio's first rs232 port wil be echoed on the console, this way
it is possible to see the ouput of the OutputDebugString function.
This commit is contained in:
yz70s 2016-01-11 22:20:33 +01:00
parent 9a9a89c716
commit 0802d60f8a
3 changed files with 187 additions and 25 deletions

View File

@ -364,14 +364,11 @@ Thanks to Alex, Mr Mudkips, and Philip Burke for this info.
#include "emu.h"
#include "cpu/i386/i386.h"
#include "machine/lpci.h"
#include "machine/pic8259.h"
#include "machine/pit8253.h"
#include "machine/idectrl.h"
#include "machine/idehd.h"
#include "machine/naomigd.h"
#include "video/poly.h"
#include "bitmap.h"
#include "debug/debugcon.h"
#include "debug/debugcmd.h"
#include "debug/debugcpu.h"

View File

@ -39,6 +39,8 @@ struct OHCIIsochronousTransferDescriptor {
UINT32 nexttd; // NextTD
UINT32 be; // BufferEnd
UINT32 offset[8]; // Offset/PacketStatusWord
UINT32 word0;
UINT32 word1;
};
enum OHCIRegisters {
@ -193,7 +195,11 @@ public:
int execute_transfer(int address, int endpoint, int pid, UINT8 *buffer, int size);
private:
int address;
int controldir;
int newaddress;
int controldirection;
int controltype;
int controlrecipient;
bool settingaddress;
int remain;
UINT8 *position;
};
@ -214,6 +220,10 @@ public:
DECLARE_WRITE32_MEMBER(usbctrl_w);
DECLARE_READ32_MEMBER(smbus_r);
DECLARE_WRITE32_MEMBER(smbus_w);
DECLARE_READ8_MEMBER(superio_read);
DECLARE_WRITE8_MEMBER(superio_write);
DECLARE_READ8_MEMBER(superiors232_read);
DECLARE_WRITE8_MEMBER(superiors232_write);
DECLARE_READ32_MEMBER(audio_apu_r);
DECLARE_WRITE32_MEMBER(audio_apu_w);
DECLARE_READ32_MEMBER(audio_ac93_r);
@ -232,6 +242,7 @@ public:
void usb_ohci_read_transfer_descriptor(UINT32 address);
void usb_ohci_writeback_transfer_descriptor(UINT32 address);
void usb_ohci_read_isochronous_transfer_descriptor(UINT32 address);
void usb_ohci_writeback_isochronous_transfer_descriptor(UINT32 address);
void dword_write_le(UINT8 *addr, UINT32 d);
void word_write_le(UINT8 *addr, UINT16 d);
void debug_generate_irq(int irq, bool active);
@ -309,6 +320,13 @@ public:
OHCITransferDescriptor transfer_descriptor;
OHCIIsochronousTransferDescriptor isochronous_transfer_descriptor;
} ohcist;
struct superio_state
{
bool configuration_mode;
int index;
int selected;
UINT8 registers[16][256]; // 256 registers for up to 16 devices, registers 0-0x2f common to all
} superiost;
UINT8 pic16lc_buffer[0xff];
std::unique_ptr<nv2a_renderer> nvidia_nv2a;
bool debug_irq_active;

View File

@ -7,7 +7,6 @@
#include "machine/pic8259.h"
#include "machine/pit8253.h"
#include "machine/idectrl.h"
#include "machine/idehd.h"
#include "video/poly.h"
#include "bitmap.h"
#include "debug/debugcon.h"
@ -17,6 +16,7 @@
#include "includes/xbox.h"
#define LOG_PCI
//#define LOG_AUDIO
//#define LOG_OHCI
//#define USB_ENABLED
@ -827,14 +827,17 @@ static USBStandardDeviceDscriptor devdesc = {18,1,0x201,0xff,0x34,0x56,64,0x100,
ohci_function_device::ohci_function_device()
{
address = 0;
controldir = 0;
newaddress = 0;
controldirection = 0;
remain = 0;
position = nullptr;
settingaddress = false;
}
void ohci_function_device::execute_reset()
{
address = 0;
newaddress = 0;
}
int ohci_function_device::execute_transfer(int address, int endpoint, int pid, UINT8 *buffer, int size)
@ -842,35 +845,69 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U
if (endpoint == 0) {
if (pid == SetupPid) {
struct USBSetupPacket *p=(struct USBSetupPacket *)buffer;
// define direction
controldir = p->bmRequestType & 128;
// case !=0, in data stage and out status stage
// case ==0, out data stage and in status stage
// define direction 0:host->device 1:device->host
controldirection = (p->bmRequestType & 128) >> 7;
// case ==1, IN data stage and OUT status stage
// case ==0, OUT data stage and IN status stage
// data stage is optional, IN status stage
controltype = (p->bmRequestType & 0x60) >> 5;
controlrecipient = p->bmRequestType & 0x1f;
position = nullptr;
remain = p->wLength;
if ((p->bmRequestType & 0x60) == 0) {
// if standard
if (controltype == 0) {
switch (p->bRequest) {
case GET_STATUS:
case CLEAR_FEATURE:
case SET_FEATURE:
break;
case SET_ADDRESS:
newaddress = p->wValue;
settingaddress = true;
break;
case GET_DESCRIPTOR:
if ((p->wValue >> 8) == 1) { // device descriptor
if ((p->wValue >> 8) == DEVICE) { // device descriptor
//p->wValue & 255;
position = (UINT8 *)&devdesc;
remain = sizeof(devdesc);
}
else if ((p->wValue >> 8) == CONFIGURATION) { // configuration descriptor
remain = 0;
}
if (remain > p->wLength)
remain = p->wLength;
break;
case SET_ADDRESS:
//p->wValue;
break;
case SET_DESCRIPTOR:
case GET_CONFIGURATION:
case SET_CONFIGURATION:
case GET_INTERFACE:
case SET_INTERFACE:
case SYNCH_FRAME:
default:
break;
}
}
}
else if (pid == InPid) {
// case !=0, give data
// if no data has been transferred (except for the setup stage)
// and the lenght of this IN transaction is 0
// assume this is the status stage
if (size == 0) {
if (settingaddress == true)
{
// set of address is active at end of status stage
address = newaddress;
settingaddress = false;
}
return 0;
}
// case ==1, give data
// case ==0, nothing
if (size > remain)
size = remain;
if (controldir != 0) {
// if device->host
if (controldirection == 1) {
// data stage
if (size > remain)
size = remain;
if (position != nullptr)
memcpy(buffer, position, size);
position = position + size;
@ -878,11 +915,13 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U
}
}
else if (pid == OutPid) {
// case !=0, nothing
// case ==1, nothing
// case ==0, give data
if (size > remain)
size = remain;
if (controldir == 0) {
// if host->device
if (controldirection == 0) {
// data stage
if (size > remain)
size = remain;
if (position != nullptr)
memcpy(position, buffer, size);
position = position + size;
@ -966,11 +1005,14 @@ void xbox_base_state::usb_ohci_read_isochronous_transfer_descriptor(UINT32 addre
UINT32 w;
w = ohcist.space->read_dword(address);
ohcist.isochronous_transfer_descriptor.word0 = w;
ohcist.isochronous_transfer_descriptor.cc = (w >> 28) & 15;
ohcist.isochronous_transfer_descriptor.fc = (w >> 24) & 7;
ohcist.isochronous_transfer_descriptor.di = (w >> 21) & 7;
ohcist.isochronous_transfer_descriptor.sf = w & 0xffff;
ohcist.isochronous_transfer_descriptor.bp0 = ohcist.space->read_dword(address + 4) & 0xfffff000;
w = ohcist.space->read_dword(address + 4);
ohcist.isochronous_transfer_descriptor.word1 = w;
ohcist.isochronous_transfer_descriptor.bp0 = w & 0xfffff000;
ohcist.isochronous_transfer_descriptor.nexttd = ohcist.space->read_dword(address + 8);
ohcist.isochronous_transfer_descriptor.be = ohcist.space->read_dword(address + 12);
w = ohcist.space->read_dword(address + 16);
@ -987,13 +1029,37 @@ void xbox_base_state::usb_ohci_read_isochronous_transfer_descriptor(UINT32 addre
ohcist.isochronous_transfer_descriptor.offset[7] = (w >> 16) & 0xffff;
}
void xbox_base_state::usb_ohci_writeback_isochronous_transfer_descriptor(UINT32 address)
{
UINT32 w;
w = ohcist.isochronous_transfer_descriptor.word0 & 0x1f0000;
w = w | (ohcist.isochronous_transfer_descriptor.cc << 28) | (ohcist.isochronous_transfer_descriptor.fc << 24) | (ohcist.isochronous_transfer_descriptor.di << 21) | ohcist.isochronous_transfer_descriptor.sf;
ohcist.space->write_dword(address, w);
w = ohcist.isochronous_transfer_descriptor.word1 & 0xfff;
w = w | ohcist.isochronous_transfer_descriptor.bp0;
ohcist.space->write_dword(address + 4, w);
ohcist.space->write_dword(address + 8, ohcist.isochronous_transfer_descriptor.nexttd);
ohcist.space->write_dword(address + 12, ohcist.isochronous_transfer_descriptor.be);
w = (ohcist.isochronous_transfer_descriptor.offset[1] << 16) | ohcist.isochronous_transfer_descriptor.offset[0];
ohcist.space->write_dword(address + 16, w);
w = (ohcist.isochronous_transfer_descriptor.offset[3] << 16) | ohcist.isochronous_transfer_descriptor.offset[2];
ohcist.space->write_dword(address + 20, w);
w = (ohcist.isochronous_transfer_descriptor.offset[5] << 16) | ohcist.isochronous_transfer_descriptor.offset[4];
ohcist.space->write_dword(address + 24, w);
w = (ohcist.isochronous_transfer_descriptor.offset[7] << 16) | ohcist.isochronous_transfer_descriptor.offset[6];
ohcist.space->write_dword(address + 28, w);
}
/*
* Audio
*/
READ32_MEMBER(xbox_base_state::audio_apu_r)
{
#ifdef LOG_AUDIO
logerror("Audio_APU: read from %08X mask %08X\n", 0xfe800000 + offset * 4, mem_mask);
#endif
if (offset == 0x20010 / 4) // some kind of internal counter or state value
return 0x20 + 4 + 8 + 0x48 + 0x80;
return apust.memory[offset];
@ -1004,7 +1070,9 @@ WRITE32_MEMBER(xbox_base_state::audio_apu_w)
//UINT32 old;
UINT32 v;
#ifdef LOG_AUDIO
logerror("Audio_APU: write at %08X mask %08X value %08X\n", 0xfe800000 + offset * 4, mem_mask, data);
#endif
//old = apust.memory[offset];
apust.memory[offset] = data;
if (offset == 0x02040 / 4) // address of memory area with scatter-gather info (gpdsp scratch dma)
@ -1110,7 +1178,9 @@ READ32_MEMBER(xbox_base_state::audio_ac93_r)
{
UINT32 ret = 0;
#ifdef LOG_AUDIO
logerror("Audio_AC3: read from %08X mask %08X\n", 0xfec00000 + offset * 4, mem_mask);
#endif
if (offset < 0x80 / 4)
{
ret = ac97st.mixer_regs[offset];
@ -1137,7 +1207,9 @@ READ32_MEMBER(xbox_base_state::audio_ac93_r)
WRITE32_MEMBER(xbox_base_state::audio_ac93_w)
{
#ifdef LOG_AUDIO
logerror("Audio_AC3: write at %08X mask %08X value %08X\n", 0xfec00000 + offset * 4, mem_mask, data);
#endif
if (offset < 0x80 / 4)
{
COMBINE_DATA(ac97st.mixer_regs + offset);
@ -1421,6 +1493,76 @@ WRITE32_MEMBER(xbox_base_state::smbus_w)
smbusst.command = data;
}
/*
* SuperIO
*/
READ8_MEMBER(xbox_base_state::superio_read)
{
if (superiost.configuration_mode == false)
return 0;
if (offset == 0) // index port 0x2e
return superiost.index;
if (offset == 1)
{
// data port 0x2f
if (superiost.index < 0x30)
return superiost.registers[0][superiost.index];
return superiost.registers[superiost.selected][superiost.index];
}
return 0;
}
WRITE8_MEMBER(xbox_base_state::superio_write)
{
if (superiost.configuration_mode == false)
{
// config port 0x2e
if ((offset == 0) && (data == 0x55))
superiost.configuration_mode = true;
return;
}
if ((offset == 0) && (data == 0xaa))
{
// config port 0x2e
superiost.configuration_mode = false;
return;
}
if (offset == 0)
{
// index port 0x2e
superiost.index = data;
}
if (offset == 1)
{
// data port 0x2f
if (superiost.index < 0x30)
{
superiost.registers[0][superiost.index] = data;
superiost.selected = superiost.registers[0][7];
} else
{
superiost.registers[superiost.selected][superiost.index] = data;
//if ((superiost.selected == 4) && (superiost.index == 0x30) && (data != 0))
// ; // add handlers 0x3f8- +7
}
}
}
READ8_MEMBER(xbox_base_state::superiors232_read)
{
if (offset == 5)
return 0x20;
return 0;
}
WRITE8_MEMBER(xbox_base_state::superiors232_write)
{
if (offset == 0)
{
printf("%c", data);
}
}
ADDRESS_MAP_START(xbox_base_map, AS_PROGRAM, 32, xbox_base_state)
AM_RANGE(0x00000000, 0x07ffffff) AM_RAM AM_SHARE("nv2a_share") // 128 megabytes
AM_RANGE(0xf0000000, 0xf7ffffff) AM_RAM AM_SHARE("nv2a_share") // 3d accelerator wants this
@ -1433,9 +1575,11 @@ ADDRESS_MAP_END
ADDRESS_MAP_START(xbox_base_map_io, AS_IO, 32, xbox_base_state)
AM_RANGE(0x0020, 0x0023) AM_DEVREADWRITE8("pic8259_1", pic8259_device, read, write, 0xffffffff)
AM_RANGE(0x002c, 0x002f) AM_READWRITE8(superio_read, superio_write, 0xffff0000)
AM_RANGE(0x0040, 0x0043) AM_DEVREADWRITE8("pit8254", pit8254_device, read, write, 0xffffffff)
AM_RANGE(0x00a0, 0x00a3) AM_DEVREADWRITE8("pic8259_2", pic8259_device, read, write, 0xffffffff)
AM_RANGE(0x01f0, 0x01f7) AM_DEVREADWRITE("ide", bus_master_ide_controller_device, read_cs0, write_cs0)
AM_RANGE(0x03f8, 0x03ff) AM_READWRITE8(superiors232_read, superiors232_write, 0xffffffff)
AM_RANGE(0x0cf8, 0x0cff) AM_DEVREADWRITE("pcibus", pci_bus_legacy_device, read, write)
AM_RANGE(0x8000, 0x80ff) AM_READWRITE(dummy_r, dummy_w)
AM_RANGE(0xc000, 0xc0ff) AM_READWRITE(smbus_r, smbus_w)
@ -1472,11 +1616,11 @@ void xbox_base_state::machine_start()
pic16lc_buffer[0x1d] = 0x0d;
pic16lc_buffer[0x1e] = 0x0e;
pic16lc_buffer[0x1f] = 0x0f;
#ifdef USB_ENABLED
ohcist.hc_regs[HcRevision] = 0x10;
ohcist.hc_regs[HcFmInterval] = 0x2edf;
ohcist.hc_regs[HcLSThreshold] = 0x628;
ohcist.hc_regs[HcRhDescriptorA] = 4;
#ifdef USB_ENABLED
ohcist.interruptbulkratio = 1;
ohcist.writebackdonehadcounter = 7;
ohcist.space = &m_maincpu->space();
@ -1484,6 +1628,9 @@ void xbox_base_state::machine_start()
ohcist.timer->enable(false);
usb_ohci_plug(1, new ohci_function_device()); // test connect
#endif
memset(&superiost, 0, sizeof(superiost));
superiost.configuration_mode = false;
superiost.registers[0][0x26] = 0x2e; // Configuration port address byte 0
// savestates
save_item(NAME(debug_irq_active));
save_item(NAME(debug_irq_number));