diff --git a/src/mame/drivers/chihiro.c b/src/mame/drivers/chihiro.c index 1fe778e3726..e54154eaee1 100644 --- a/src/mame/drivers/chihiro.c +++ b/src/mame/drivers/chihiro.c @@ -376,6 +376,7 @@ Thanks to Alex, Mr Mudkips, and Philip Burke for this info. #define LOG_PCI //#define LOG_OHCI //#define LOG_BASEBOARD +//#define USB_ENABLED class chihiro_state : public driver_device { @@ -410,6 +411,10 @@ public: int smbus_pic16lc(int command, int rw, int data); int smbus_cx25871(int command, int rw, int data); int smbus_eeprom(int command, int rw, int data); + void usb_ohci_interrupts(); + void usb_ohci_read_endpoint_descriptor(UINT32 address); + void usb_ohci_read_transfer_descriptor(UINT32 address); + void usb_ohci_read_isochronous_transfer_descriptor(UINT32 address); void baseboard_ide_event(int type, UINT8 *read, UINT8 *write); UINT8 *baseboard_ide_dimmboard(UINT32 lba); void dword_write_le(UINT8 *addr, UINT32 d); @@ -426,6 +431,7 @@ public: DECLARE_WRITE_LINE_MEMBER(chihiro_pit8254_out2_changed); IRQ_CALLBACK_MEMBER(irq_callback); TIMER_CALLBACK_MEMBER(audio_apu_timer); + TIMER_CALLBACK_MEMBER(usb_ohci_timer); struct chihiro_devices { pic8259_device *pic8259_1; @@ -468,6 +474,49 @@ public: UINT32 mixer_regs[0x80 / 4]; UINT32 controller_regs[0x38 / 4]; } ac97st; + struct ohci_state { + UINT32 hc_regs[255]; + int ports[4 + 1]; + emu_timer *timer; + int state; + UINT32 framenumber; + address_space *space; + struct { + int mps; // MaximumPacketSize + int f; // Format + int k; // sKip + int s; // Speed + int d; // Direction + int en; // EndpointNumber + int fa; // FunctionAddress + UINT32 tailp; // TDQueueTailPointer + UINT32 headp; // TDQueueHeadPointer + UINT32 nexted; // NextED + int c; // toggleCarry + int h; // Halted + } endpoint_descriptor; + struct { + int cc; // ConditionCode + int ec; // ErrorCount + int t; // DataToggle + int di; // DelayInterrupt + int dp; // Direction/PID + int r; // bufferRounding + UINT32 cbp; // CurrentBufferPointer + UINT32 nexttd; // NextTD + UINT32 be; // BufferEnd + } transfer_descriptor; + struct { + int cc; // ConditionCode + int fc; // FrameCount + int di; // DelayInterrupt + int sf; // StartingFrame + UINT32 bp0; // BufferPage0 + UINT32 nexttd; // NextTD + UINT32 be; // BufferEnd + UINT32 offset[8]; // Offset/PacketStatusWord + } isochronous_transfer_descriptor; + } ohcist; UINT8 pic16lc_buffer[0xff]; nv2a_renderer *nvidia_nv2a; bool debug_irq_active; @@ -477,6 +526,50 @@ public: int usbhack_index; int usbhack_counter; required_device m_maincpu; + + enum OHCIRegisters { + HcRevision=0, + HcControl, + HcCommandStatus, + HcInterruptStatus, + HcInterruptEnable, + HcInterruptDisable, + HcHCCA, + HcPeriodCurrentED, + HcControlHeadED, + HcControlCurrentED, + HcBulkHeadED, + HcBulkCurrentED, + HcDoneHead, + HcFmInterval, + HcFmRemaining, + HcFmNumber, + HcPeriodicStart, + HcLSThreshold, + HcRhDescriptorA, + HcRhDescriptorB, + HcRhStatus, + HcRhPortStatus0 + }; + + enum OHCIHostControllerFunctionalState { + UsbReset=0, + UsbResume, + UsbOperational, + UsbSuspend + }; + + enum OHCIInterrupt { + SchedulingOverrun=1, + WritebackDoneHead=2, + StartofFrame=4, + ResumeDetected=8, + UnrecoverableError=16, + FrameNumberOverflow=32, + RootHubStatusChange=64, + OwnershipChange=0x40000000, + MasterInterruptEnable=0x80000000 + }; }; /* jamtable instructions for Chihiro (different from console) @@ -721,6 +814,62 @@ static void dump_list_command(running_machine &machine, int ref, int params, con } } +static void dump_dpc_command(running_machine &machine, int ref, int params, const char **param) +{ + chihiro_state *state = machine.driver_data(); + address_space &space = state->m_maincpu->space(); + UINT64 addr; + offs_t address; + + if (params < 1) + return; + if (!debug_command_parameter_number(machine, param[0], &addr)) + return; + address = (offs_t)addr; + if (!debug_cpu_translate(space, TRANSLATE_READ_DEBUG, &address)) + { + debug_console_printf(machine, "Address is unmapped.\n"); + return; + } + debug_console_printf(machine, "Type %d word\n", space.read_word_unaligned(address)); + debug_console_printf(machine, "Inserted %d byte\n", space.read_byte(address + 2)); + debug_console_printf(machine, "Padding %d byte\n", space.read_byte(address + 3)); + debug_console_printf(machine, "DpcListEntry {%08X,%08X} _LIST_ENTRY\n", space.read_dword_unaligned(address + 4), space.read_dword_unaligned(address + 8)); + debug_console_printf(machine, "DeferredRoutine %08X dword\n", space.read_dword_unaligned(address + 12)); + debug_console_printf(machine, "DeferredContext %08X dword\n", space.read_dword_unaligned(address + 16)); + debug_console_printf(machine, "SystemArgument1 %08X dword\n", space.read_dword_unaligned(address + 20)); + debug_console_printf(machine, "SystemArgument2 %08X dword\n", space.read_dword_unaligned(address + 24)); +} + +static void dump_timer_command(running_machine &machine, int ref, int params, const char **param) +{ + chihiro_state *state = machine.driver_data(); + address_space &space = state->m_maincpu->space(); + UINT64 addr; + offs_t address; + + if (params < 1) + return; + if (!debug_command_parameter_number(machine, param[0], &addr)) + return; + address = (offs_t)addr; + if (!debug_cpu_translate(space, TRANSLATE_READ_DEBUG, &address)) + { + debug_console_printf(machine, "Address is unmapped.\n"); + return; + } + debug_console_printf(machine, "Header.Type %d byte\n", space.read_byte(address)); + debug_console_printf(machine, "Header.Absolute %d byte\n", space.read_byte(address + 1)); + debug_console_printf(machine, "Header.Size %d byte\n", space.read_byte(address + 2)); + debug_console_printf(machine, "Header.Inserted %d byte\n", space.read_byte(address + 3)); + debug_console_printf(machine, "Header.SignalState %08X dword\n", space.read_dword_unaligned(address + 4)); + debug_console_printf(machine, "Header.WaitListEntry {%08X,%08X} _LIST_ENTRY\n", space.read_dword_unaligned(address + 8), space.read_dword_unaligned(address + 12)); + debug_console_printf(machine, "DueTime %I64d qword\n", (INT64)space.read_qword_unaligned(address + 16)); + debug_console_printf(machine, "TimerListEntry {%08X,%08X} _LIST_ENTRY\n", space.read_dword_unaligned(address + 24), space.read_dword_unaligned(address + 28)); + debug_console_printf(machine, "Dpc %08X dword\n", space.read_dword_unaligned(address + 32)); + debug_console_printf(machine, "Period %d dword\n", space.read_dword_unaligned(address + 36)); +} + static void curthread_command(running_machine &machine, int ref, int params, const char **param) { chihiro_state *state = machine.driver_data(); @@ -878,6 +1027,8 @@ static void help_command(running_machine &machine, int ref, int params, const ch debug_console_printf(machine, " chihiro dump_string,
-- Dump _STRING object at
\n"); debug_console_printf(machine, " chihiro dump_process,
-- Dump _PROCESS object at
\n"); debug_console_printf(machine, " chihiro dump_list,
[,] -- Dump _LIST_ENTRY chain starting at
\n"); + debug_console_printf(machine, " chihiro dump_dpc,
-- Dump _KDPC object at
\n"); + debug_console_printf(machine, " chihiro dump_timer,
-- Dump _KTIMER object at
\n"); debug_console_printf(machine, " chihiro curthread -- Print information about current thread\n"); debug_console_printf(machine, " chihiro irq, -- Generate interrupt with irq number 0-15\n"); debug_console_printf(machine, " chihiro nv2a_combiners -- Toggle use of register combiners\n"); @@ -900,6 +1051,10 @@ static void chihiro_debug_commands(running_machine &machine, int ref, int params dump_process_command(machine, ref, params - 1, param + 1); else if (strcmp("dump_list", param[0]) == 0) dump_list_command(machine, ref, params - 1, param + 1); + else if (strcmp("dump_dpc", param[0]) == 0) + dump_dpc_command(machine, ref, params - 1, param + 1); + else if (strcmp("dump_timer", param[0]) == 0) + dump_timer_command(machine, ref, params - 1, param + 1); else if (strcmp("curthread", param[0]) == 0) curthread_command(machine, ref, params - 1, param + 1); else if (strcmp("irq", param[0]) == 0) @@ -1022,7 +1177,7 @@ static void geforce_pci_w(device_t *busdevice, device_t *device, int function, i } /* - * ohci usb controller placeholder + * ohci usb controller (placeholder for now) */ #ifdef LOG_OHCI @@ -1063,9 +1218,20 @@ static const struct { READ32_MEMBER(chihiro_state::usbctrl_r) { - int a, p; + UINT32 ret; +#ifdef LOG_OHCI + if (offset >= 0x54 / 4) + logerror("usb controller 0 register HcRhPortStatus[%d] read\n", (offset - 0x54 / 4) + 1); + else + logerror("usb controller 0 register %s read\n", usbregnames[offset]); +#endif + ret=ohcist.hc_regs[offset]; if (offset == 0) { /* hacks needed until usb (and jvs) is implemented */ +#ifdef USB_ENABLED +#else + int p; + if (usbhack_counter == 0) p = 0; else if (usbhack_counter == 1) // after game loaded @@ -1073,31 +1239,198 @@ READ32_MEMBER(chihiro_state::usbctrl_r) else p = -1; if (p >= 0) { - for (a = 0; a < 16; a++) { + for (int a = 0; a < 16; a++) { if (hacks[p].modify[a].address == 0) break; m_maincpu->space(0).write_byte(hacks[p].modify[a].address, hacks[p].modify[a].write_byte); } } usbhack_counter++; - } -#ifdef LOG_OHCI - if (offset >= 0x54 / 4) - logerror("usb controller 0 register HcRhPortStatus[%d] read\n", (offset - 0x54 / 4) + 1); - else - logerror("usb controller 0 register %s read\n", usbregnames[offset]); #endif - return 0; + } + return ret; } WRITE32_MEMBER(chihiro_state::usbctrl_w) { +#ifdef USB_ENABLED + UINT32 old = ohcist.hc_regs[offset]; +#endif + #ifdef LOG_OHCI if (offset >= 0x54 / 4) logerror("usb controller 0 register HcRhPortStatus[%d] write %08X\n", (offset - 0x54 / 4) + 1, data); else logerror("usb controller 0 register %s write %08X\n", usbregnames[offset], data); #endif +#ifdef USB_ENABLED + if (offset == HcRhStatus) { + if (data & 0x80000000) + ohcist.hc_regs[HcRhStatus] &= ~0x8000; + if (data & 0x00020000) + ohcist.hc_regs[HcRhStatus] &= ~0x0002; + if (data & 0x00010000) + ohcist.hc_regs[HcRhStatus] &= ~0x0001; + return; + } + if (offset == HcControl) { + int hcfs; + + hcfs = (data >> 6) & 3; + if (hcfs == UsbOperational) { + ohcist.timer->enable(); + ohcist.timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1)); + } + else + ohcist.timer->enable(false); + ohcist.state = hcfs; + } + if (offset == HcCommandStatus) { + if (data & 1) + ohcist.hc_regs[HcControl] |= 3 << 6; + } + if (offset == HcInterruptStatus) { + ohcist.hc_regs[HcInterruptStatus] &= ~data; + usb_ohci_interrupts(); + return; + } + if (offset == HcInterruptEnable) { + ohcist.hc_regs[HcInterruptEnable] |= data; + usb_ohci_interrupts(); + return; + } + if (offset == HcInterruptDisable) { + ohcist.hc_regs[HcInterruptEnable] &= ~data; + usb_ohci_interrupts(); + return; + } + if (offset >= HcRhPortStatus0) { + int port = offset - HcRhPortStatus0 + 1; // port 0 not used + // bit 0 ClearPortEnable: 1 clears PortEnableStatus + // bit 1 SetPortEnable: 1 sets PortEnableStatus + // bit 2 SetPortSuspend: 1 sets PortSuspendStatus + // bit 3 ClearSuspendStatus: 1 clears PortSuspendStatus + // bit 4 SetPortReset: 1 sets PortResetStatus + if (data & 0x10) { + ohcist.hc_regs[offset] |= 0x10; + // after 10ms set PortResetStatusChange and clear PortResetStatus and set PortEnableStatus + ohcist.ports[port] = 10; + } + // bit 8 SetPortPower: 1 sets PortPowerStatus + // bit 9 ClearPortPower: 1 clears PortPowerStatus + // bit 16 1 clears ConnectStatusChange + // bit 17 1 clears PortEnableStatusChange + // bit 18 1 clears PortSuspendStatusChange + // bit 19 1 clears PortOverCurrentIndicatorChange + // bit 20 1 clears PortResetStatusChange + if (ohcist.hc_regs[offset] != old) + ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; + usb_ohci_interrupts(); + return; + } +#endif + ohcist.hc_regs[offset] = data; +} + +TIMER_CALLBACK_MEMBER(chihiro_state::usb_ohci_timer) +{ + UINT32 hcca; + int changed = 0; + + if (ohcist.state == UsbOperational) { + ohcist.framenumber=(ohcist.framenumber+1) & 0xffff; + hcca = ohcist.hc_regs[HcHCCA]; + ohcist.space->write_dword(hcca + 0x80, ohcist.framenumber); + ohcist.hc_regs[HcFmNumber] = ohcist.framenumber; + } + for (int p = 1; p <= 4; p++) { + if (ohcist.ports[p] > 0) { + ohcist.ports[p]--; + if (ohcist.ports[p] == 0) { + ohcist.hc_regs[HcRhPortStatus0 + p - 1] = (ohcist.hc_regs[HcRhPortStatus0 + p - 1] & ~(1 << 4)) | (1 << 20) | (1 << 1); + changed = 1; + } + } + } + if (ohcist.state == UsbOperational) { + if (ohcist.framenumber == 0) + ohcist.hc_regs[HcInterruptStatus] |= FrameNumberOverflow; + ohcist.hc_regs[HcInterruptStatus] |= StartofFrame; + } + if (changed != 0) { + ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; + } + usb_ohci_interrupts(); +} + +void chihiro_state::usb_ohci_interrupts() +{ + if (((ohcist.hc_regs[HcInterruptStatus] & ohcist.hc_regs[HcInterruptEnable]) != 0) && ((ohcist.hc_regs[HcInterruptEnable] & MasterInterruptEnable) != 0)) + chihiro_devs.pic8259_1->ir1_w(1); + else + chihiro_devs.pic8259_1->ir1_w(0); +} + +void chihiro_state::usb_ohci_read_endpoint_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.space->read_dword(address); + ohcist.endpoint_descriptor.fa = w & 0x7f; + ohcist.endpoint_descriptor.en = (w >> 7) & 15; + ohcist.endpoint_descriptor.d = (w >> 11) & 3; + ohcist.endpoint_descriptor.s = (w >> 13) & 1; + ohcist.endpoint_descriptor.k = (w >> 14) & 1; + ohcist.endpoint_descriptor.f = (w >> 15) & 1; + ohcist.endpoint_descriptor.mps = (w >> 16) & 0x7ff; + ohcist.endpoint_descriptor.tailp = ohcist.space->read_dword(address + 4); + w = ohcist.space->read_dword(address + 8); + ohcist.endpoint_descriptor.headp = w & 0xfffffffc; + ohcist.endpoint_descriptor.h = w & 1; + ohcist.endpoint_descriptor.c = (w >> 1) & 1; + ohcist.endpoint_descriptor.nexted = ohcist.space->read_dword(address + 12); +} + +void chihiro_state::usb_ohci_read_transfer_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.space->read_dword(address); + ohcist.transfer_descriptor.cc = (w >> 28) & 15; + ohcist.transfer_descriptor.ec= (w >> 16) & 3; + ohcist.transfer_descriptor.t= (w >> 24) & 3; + ohcist.transfer_descriptor.di= (w >> 21) & 7; + ohcist.transfer_descriptor.dp= (w >> 19) & 3; + ohcist.transfer_descriptor.r = (w >> 18) & 1; + ohcist.transfer_descriptor.cbp = ohcist.space->read_dword(address + 4); + ohcist.transfer_descriptor.nexttd = ohcist.space->read_dword(address + 8); + ohcist.transfer_descriptor.be = ohcist.space->read_dword(address + 12); +} + +void chihiro_state::usb_ohci_read_isochronous_transfer_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.space->read_dword(address); + 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; + 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); + ohcist.isochronous_transfer_descriptor.offset[0] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[1] = (w >> 16) & 0xffff; + w = ohcist.space->read_dword(address + 20); + ohcist.isochronous_transfer_descriptor.offset[2] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[3] = (w >> 16) & 0xffff; + w = ohcist.space->read_dword(address + 24); + ohcist.isochronous_transfer_descriptor.offset[4] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[5] = (w >> 16) & 0xffff; + w = ohcist.space->read_dword(address + 28); + ohcist.isochronous_transfer_descriptor.offset[6] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[7] = (w >> 16) & 0xffff; } /* @@ -1792,6 +2125,17 @@ void chihiro_state::machine_start() apust.timer->enable(false); if (machine().debug_flags & DEBUG_FLAG_ENABLED) debug_console_register_command(machine(), "chihiro", CMDFLAG_NONE, 0, 1, 4, chihiro_debug_commands); + memset(&ohcist, 0, sizeof(ohcist)); +#ifdef USB_ENABLED + ohcist.hc_regs[HcRevision] = 0x10; + ohcist.hc_regs[HcFmInterval] = 0x2edf; + ohcist.hc_regs[HcLSThreshold] = 0x628; + ohcist.hc_regs[HcRhDescriptorA] = 4; + ohcist.hc_regs[HcRhPortStatus0] = 1; // test connect + ohcist.space = &m_maincpu->space(); + ohcist.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(chihiro_state::usb_ohci_timer), this), (void *)"USB OHCI Timer"); + ohcist.timer->enable(false); +#endif usbhack_index = -1; for (int a = 1; a < 2; a++) if (strcmp(machine().basename(), hacks[a].game_name) == 0) {