├── apps ├── CMakeLists.txt └── cli │ ├── src │ ├── pch.cpp │ └── pch.hpp │ └── CMakeLists.txt ├── modules ├── CMakeLists.txt └── core │ ├── src │ ├── common │ │ ├── strikebox │ │ │ ├── hw │ │ │ │ ├── sm │ │ │ │ │ ├── sm.cpp │ │ │ │ │ ├── tvenc.cpp │ │ │ │ │ ├── eeprom.cpp │ │ │ │ │ ├── adm1032.cpp │ │ │ │ │ └── tvenc_conexant.cpp │ │ │ │ ├── basic │ │ │ │ │ ├── char.cpp │ │ │ │ │ ├── irq.cpp │ │ │ │ │ ├── gsi.cpp │ │ │ │ │ ├── mcpx.cpp │ │ │ │ │ └── char_null.cpp │ │ │ │ ├── pci │ │ │ │ │ ├── pci_irq.cpp │ │ │ │ │ ├── mcpx_ram.cpp │ │ │ │ │ ├── agpbridge.cpp │ │ │ │ │ ├── ac97.cpp │ │ │ │ │ └── usb_pci.cpp │ │ │ │ ├── ata │ │ │ │ │ ├── drvs │ │ │ │ │ │ ├── util.cpp │ │ │ │ │ │ ├── drv_null.cpp │ │ │ │ │ │ ├── ata_device_driver.cpp │ │ │ │ │ │ ├── drv_vdvd_dummy.cpp │ │ │ │ │ │ └── drv_vhd_dummy.cpp │ │ │ │ │ ├── cmds │ │ │ │ │ │ ├── cmd_packet.cpp │ │ │ │ │ │ ├── cmd_read_dma.cpp │ │ │ │ │ │ ├── cmd_write_dma.cpp │ │ │ │ │ │ ├── ata_command.cpp │ │ │ │ │ │ ├── cmd_security_unlock.cpp │ │ │ │ │ │ ├── proto_nondata.cpp │ │ │ │ │ │ └── cmd_identify_packet_device.cpp │ │ │ │ │ ├── ata_device.cpp │ │ │ │ │ └── ata_common.cpp │ │ │ │ ├── gpu │ │ │ │ │ ├── engines │ │ │ │ │ │ ├── pramin.cpp │ │ │ │ │ │ ├── prma.cpp │ │ │ │ │ │ ├── prom.cpp │ │ │ │ │ │ ├── pstraps.cpp │ │ │ │ │ │ ├── pcounter.cpp │ │ │ │ │ │ ├── prmdio.cpp │ │ │ │ │ │ ├── pnvio.cpp │ │ │ │ │ │ ├── prmcio.cpp │ │ │ │ │ │ ├── pfb.cpp │ │ │ │ │ │ ├── pcrtc.cpp │ │ │ │ │ │ ├── pvideo.cpp │ │ │ │ │ │ ├── pramdac.cpp │ │ │ │ │ │ └── pbus.cpp │ │ │ │ │ └── engine.cpp │ │ │ │ ├── bus │ │ │ │ │ └── isabus.cpp │ │ │ │ └── atapi │ │ │ │ │ ├── cmds │ │ │ │ │ ├── atapi_command.cpp │ │ │ │ │ ├── proto_nondata.cpp │ │ │ │ │ ├── proto_data_in.cpp │ │ │ │ │ ├── cmd_test_unit_ready.cpp │ │ │ │ │ └── cmd_read_capacity.cpp │ │ │ │ │ └── atapi_common.cpp │ │ │ ├── util │ │ │ │ ├── fifo.cpp │ │ │ │ └── invoke_later.cpp │ │ │ ├── log.cpp │ │ │ ├── timer.cpp │ │ │ └── core.cpp │ │ ├── pch.cpp │ │ └── pch.hpp │ ├── linux │ │ └── thread.cpp │ └── windows │ │ ├── thread.cpp │ │ └── strikebox │ │ └── hw │ │ └── basic │ │ └── win32 │ │ └── char_serial.h │ ├── include │ └── strikebox │ │ ├── hw │ │ ├── basic │ │ │ ├── ioapic.h │ │ │ ├── interrupt.h │ │ │ ├── mcpx.h │ │ │ ├── gsi.h │ │ │ ├── char_null.h │ │ │ ├── irq.h │ │ │ ├── i8254.h │ │ │ ├── superio.h │ │ │ ├── i8259.h │ │ │ ├── cmos.h │ │ │ └── char.h │ │ ├── sm │ │ │ ├── smc.h │ │ │ ├── tvenc.h │ │ │ ├── sm.h │ │ │ ├── tvenc_conexant.h │ │ │ ├── eeprom.h │ │ │ ├── led.h │ │ │ └── adm1032.h │ │ ├── ata │ │ │ ├── drvs │ │ │ │ ├── util.h │ │ │ │ ├── drv_vhd_dummy.h │ │ │ │ ├── drv_vdvd_dummy.h │ │ │ │ ├── drv_vhd_image.h │ │ │ │ ├── drv_vdvd_image.h │ │ │ │ └── drv_vdvd_base.h │ │ │ ├── cmds │ │ │ │ ├── cmd_packet.h │ │ │ │ ├── cmd_read_dma.h │ │ │ │ ├── cmd_write_dma.h │ │ │ │ ├── cmd_init_dev_params.h │ │ │ │ ├── cmd_identify_device.h │ │ │ │ ├── cmd_security_unlock.h │ │ │ │ ├── cmd_identify_packet_device.h │ │ │ │ ├── cmd_set_features.h │ │ │ │ ├── proto_nondata.h │ │ │ │ ├── proto_dma.h │ │ │ │ ├── proto_pio_data_in.h │ │ │ │ └── proto_pio_data_out.h │ │ │ ├── ata.h │ │ │ ├── ata_common.h │ │ │ └── ata_device.h │ │ ├── bus │ │ │ ├── isabus.h │ │ │ ├── pcibus.h │ │ │ └── smbus.h │ │ ├── pci │ │ │ ├── agpbridge.h │ │ │ ├── mcpx_ram.h │ │ │ ├── pci_common.h │ │ │ ├── hostbridge.h │ │ │ ├── pci_irq.h │ │ │ ├── usb_pci.h │ │ │ ├── ac97.h │ │ │ ├── nvapu.h │ │ │ ├── nvnet.h │ │ │ ├── pcibridge.h │ │ │ ├── nv2a.h │ │ │ ├── bmide.h │ │ │ └── lpc.h │ │ ├── utils.h │ │ ├── gpu │ │ │ ├── engines │ │ │ │ ├── prom.h │ │ │ │ ├── prma.h │ │ │ │ ├── user.h │ │ │ │ ├── prmdio.h │ │ │ │ ├── pnvio.h │ │ │ │ ├── prmcio.h │ │ │ │ ├── pramin.h │ │ │ │ ├── pfb.h │ │ │ │ ├── pcounter.h │ │ │ │ ├── pvideo.h │ │ │ │ ├── pcrtc.h │ │ │ │ ├── pbus.h │ │ │ │ └── pstraps.h │ │ │ ├── engine.h │ │ │ └── nv2a.h │ │ ├── defs.h │ │ └── atapi │ │ │ ├── atapi_xbox.h │ │ │ └── cmds │ │ │ ├── cmd_test_unit_ready.h │ │ │ ├── cmd_mode_sense_10.h │ │ │ ├── cmd_read_capacity.h │ │ │ ├── proto_nondata.h │ │ │ ├── cmd_read_dvd_structure.h │ │ │ └── cmd_read_10.h │ │ ├── thread.h │ │ ├── alloc.h │ │ ├── core.h │ │ ├── timer.h │ │ ├── debug.h │ │ ├── mem.h │ │ ├── log.h │ │ ├── util │ │ ├── invoke_later.h │ │ └── fifo.h │ │ ├── util.h │ │ ├── status.h │ │ ├── dynamic_variant.h │ │ └── io.h │ └── cmake │ └── Config.cmake.in ├── .gdbinit ├── .gitignore ├── LICENSE ├── cmake └── VSHelpers.cmake └── CMakeLists.txt /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Add apps 2 | add_subdirectory(cli) 3 | -------------------------------------------------------------------------------- /modules/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Add modules 2 | add_subdirectory(core) 3 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/sm/sm.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/sm/sm.h" 2 | 3 | namespace strikebox { 4 | 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/util/fifo.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/util/fifo.h" 2 | 3 | namespace strikebox { 4 | 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/ioapic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace strikebox { 4 | 5 | #define IOAPIC_NUM_PINS 24 6 | 7 | } 8 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/sm/smc.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StrikerX3/StrikeBox/HEAD/modules/core/include/strikebox/hw/sm/smc.h -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/basic/char.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/basic/char.h" 2 | 3 | namespace strikebox { 4 | 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /modules/core/src/common/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.hpp" 2 | 3 | // This file exists for the sole purpose of telling CMake that there is a 4 | // precompiled header file to be... well, precompiled. 5 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdint.h" 4 | 5 | namespace strikebox { 6 | 7 | /*! 8 | * Sets the current thread's name. 9 | */ 10 | void Thread_SetName(const char *name); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /modules/core/src/linux/thread.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/thread.h" 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | void Thread_SetName(const char *threadName) { 8 | pthread_setname_np(pthread_self(), threadName); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/drvs/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | namespace hw { 7 | namespace ata { 8 | 9 | void padString(uint8_t *dest, const char *src, uint32_t length); 10 | 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/alloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | #ifdef _WIN32 8 | #define valloc(size) _aligned_malloc((size), 4096) 9 | #define vfree _aligned_free 10 | #else 11 | #define vfree free 12 | #endif 13 | 14 | } 15 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/core.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strikebox/xbox.h" 4 | 5 | namespace strikebox { 6 | 7 | struct StrikeBoxInfo { 8 | const char *version; 9 | const uint64_t versionId; 10 | }; 11 | 12 | const struct StrikeBoxInfo * GetStrikeBoxInfo(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/bus/isabus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../basic/irq.h" 4 | 5 | namespace strikebox { 6 | 7 | #define ISA_NUM_IRQS 16 8 | 9 | class ISABus { 10 | public: 11 | ISABus(IRQ *irqs); 12 | ~ISABus(); 13 | 14 | IRQ *GetIRQ(uint8_t isaIRQ); 15 | private: 16 | IRQ *m_irqs; 17 | }; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/interrupt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace strikebox { 4 | namespace hw { 5 | 6 | class InterruptTrigger { 7 | public: 8 | virtual void Assert() = 0; 9 | virtual void Negate() = 0; 10 | }; 11 | 12 | class InterruptHook { 13 | public: 14 | virtual void OnChange(bool asserted) = 0; 15 | }; 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/basic/irq.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/basic/irq.h" 2 | 3 | namespace strikebox { 4 | 5 | IRQ *AllocateIRQs(IRQHandler *handler, uint8_t numIRQs) { 6 | IRQ *irqs = new IRQ[numIRQs]; 7 | for (uint8_t i = 0; i < numIRQs; i++) { 8 | irqs[i].handler = handler; 9 | irqs[i].num = i; 10 | } 11 | return irqs; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/agpbridge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | #include "pcibridge.h" 7 | 8 | namespace strikebox { 9 | 10 | class AGPBridgeDevice : public PCIBridgeDevice { 11 | public: 12 | // constructor 13 | AGPBridgeDevice(); 14 | virtual ~AGPBridgeDevice(); 15 | 16 | // PCI Device functions 17 | void Init() override; 18 | }; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /modules/core/src/common/pch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // This is the precompiled header file for this project. 4 | 5 | #include "virt86/virt86.hpp" 6 | 7 | #include "strikebox/settings.h" 8 | #include "strikebox/log.h" 9 | #include "strikebox/util.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/basic/gsi.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/basic/gsi.h" 2 | 3 | namespace strikebox { 4 | 5 | void GSI::HandleIRQ(uint8_t irqNum, bool level) { 6 | if (irqNum < ISA_NUM_IRQS) { 7 | if (i8259IRQs[irqNum] != nullptr) { 8 | i8259IRQs[irqNum]->Handle(level); 9 | } 10 | } 11 | if (ioapicIRQs[irqNum] != nullptr) { 12 | ioapicIRQs[irqNum]->Handle(level); 13 | } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/pci/pci_irq.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/pci/pci_irq.h" 2 | 3 | namespace strikebox { 4 | 5 | uint8_t DefaultIRQMapper::MapIRQ(PCIDevice *dev, uint8_t irqNum) { 6 | return (irqNum + dev->GetPCIAddress().deviceNumber) % PCI_NUM_PINS; 7 | } 8 | 9 | bool DefaultIRQMapper::CanSetIRQ() { 10 | return false; 11 | } 12 | 13 | void DefaultIRQMapper::SetIRQ(uint8_t irqNum, int level) { 14 | // Do nothing 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/mcpx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | 7 | namespace strikebox { 8 | 9 | // MCPX ROM versions. 10 | typedef enum { 11 | MCPX_1_0, 12 | MCPX_1_1, 13 | } MCPXROMVersion; 14 | 15 | // MCPX revisions. 16 | typedef enum { 17 | MCPX_X2, 18 | MCPX_X3, 19 | } MCPXRevision; 20 | 21 | 22 | MCPXRevision MCPXRevisionFromHardwareModel(HardwareModel hardwareModel); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/drvs/util.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/ata/drvs/util.h" 2 | 3 | namespace strikebox { 4 | namespace hw { 5 | namespace ata { 6 | 7 | void padString(uint8_t *dest, const char *src, uint32_t length) { 8 | for (uint32_t i = 0; i < length; i++) { 9 | if (*src) { 10 | dest[i ^ 1] = *src++; 11 | } 12 | else { 13 | dest[i ^ 1] = ' '; 14 | } 15 | } 16 | } 17 | 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/log.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/log.h" 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | /*! 8 | * Print a message to the log 9 | */ 10 | int log_print(int level, char const *fmt, ...) 11 | { 12 | if (level > LOG_LEVEL) { 13 | return 0; 14 | } 15 | 16 | int status; 17 | va_list args; 18 | 19 | va_start(args, fmt); 20 | 21 | status = vfprintf(stdout, fmt, args); 22 | 23 | va_end(args); 24 | 25 | return status; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /.gdbinit: -------------------------------------------------------------------------------- 1 | set architecture i386 2 | set disassembly-flavor intel 3 | target remote 127.0.0.1:9269 4 | 5 | # To load symbols for your XBE, use something like this: 6 | # add-symbol-file /path/to/your/main.exe 0x17000 7 | 8 | # To debug the GDB protocol uncomment the following line: 9 | # set debug remote 1 10 | 11 | # Show disassembly and source code 12 | # layout split 13 | 14 | # If you don't have the source code, displaying the disassembly 15 | # and registers is more useful 16 | layout regs 17 | 18 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/gsi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "irq.h" 6 | #include "ioapic.h" 7 | #include "../bus/isabus.h" 8 | 9 | namespace strikebox { 10 | 11 | #define GSI_NUM_PINS IOAPIC_NUM_PINS 12 | 13 | // Global System Interrupts 14 | struct GSI : public IRQHandler { 15 | IRQ *i8259IRQs[ISA_NUM_IRQS]; 16 | IRQ *ioapicIRQs[IOAPIC_NUM_PINS]; 17 | 18 | void HandleIRQ(uint8_t irqNum, bool level) override; 19 | virtual ~GSI() {} 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/mcpx_ram.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | #include "pci.h" 7 | #include "../basic/mcpx.h" 8 | 9 | namespace strikebox { 10 | 11 | class MCPXRAMDevice : public PCIDevice { 12 | public: 13 | // constructor 14 | MCPXRAMDevice(MCPXRevision revision); 15 | virtual ~MCPXRAMDevice(); 16 | 17 | // PCI Device functions 18 | void Init(); 19 | void Reset(); 20 | private: 21 | MCPXRevision m_revision; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | using namespace std::chrono; 7 | 8 | namespace strikebox { 9 | 10 | /*! 11 | * Simple timer abstraction class for high-precision timing events 12 | */ 13 | class Timer { 14 | protected: 15 | high_resolution_clock::time_point m_start; 16 | high_resolution_clock::time_point m_end; 17 | 18 | public: 19 | Timer(); 20 | void Start(); 21 | void Stop(); 22 | uint64_t GetMillisecondsElapsed(); 23 | }; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/char_null.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "char.h" 6 | 7 | namespace strikebox { 8 | 9 | class NullCharDriver : public CharDriver { 10 | public: 11 | bool Init() override; 12 | int Write(const uint8_t *buf, int len) override; 13 | void AcceptInput() override; 14 | void Stop() override; 15 | 16 | // IOCTLs 17 | void SetBreakEnable(bool breakEnable) override; 18 | void SetSerialParameters(SerialParams *params) override; 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/pci_common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 8 | #define PCI_DEVID(bus, devfn) ((((uint16_t)(bus)) << 8) | (devfn)) 9 | 10 | typedef struct { 11 | uint8_t registerNumber : 8; 12 | uint8_t functionNumber : 3; 13 | uint8_t deviceNumber : 5; 14 | uint8_t busNumber : 8; 15 | uint8_t reserved : 7; 16 | uint8_t enable : 1; 17 | } PCIConfigAddressRegister; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/irq.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | class IRQHandler { 8 | public: 9 | virtual void HandleIRQ(uint8_t irqNum, bool level) = 0; 10 | }; 11 | 12 | struct IRQ { 13 | IRQHandler *handler; 14 | uint8_t num; 15 | 16 | inline void Handle(bool level) { 17 | if (handler != nullptr) { 18 | handler->HandleIRQ(num, level); 19 | } 20 | } 21 | }; 22 | 23 | IRQ *AllocateIRQs(IRQHandler *handler, uint8_t numIRQs); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/sm/tvenc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | #include "sm.h" 7 | 8 | namespace strikebox { 9 | 10 | // Xbox TV encoder chips. 11 | typedef enum { 12 | // http://xboxdevwiki.net/Hardware_Revisions#Video_encoder 13 | Conexant, 14 | Focus, 15 | XCalibur 16 | } TVEncoder; 17 | 18 | 19 | TVEncoder TVEncoderFromHardwareModel(HardwareModel hardwareModel); 20 | 21 | class TVEncoderDevice : public SMDevice { 22 | public: 23 | virtual ~TVEncoderDevice(); 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Visual Studio files 35 | .vs/ 36 | 37 | # CMake build folder 38 | build/ 39 | 40 | # CLion project metadata 41 | .idea/ 42 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/hostbridge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | #include "pci.h" 7 | 8 | namespace strikebox { 9 | 10 | class HostBridgeDevice : public PCIDevice { 11 | public: 12 | // constructor 13 | HostBridgeDevice(); 14 | virtual ~HostBridgeDevice(); 15 | 16 | // PCI Device functions 17 | void Init(); 18 | void Reset(); 19 | 20 | void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override; 21 | void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/pci_irq.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pci.h" 4 | 5 | namespace strikebox { 6 | 7 | #define PCI_NUM_PINS 4 8 | 9 | class IRQMapper { 10 | public: 11 | virtual ~IRQMapper() {}; 12 | virtual uint8_t MapIRQ(PCIDevice *dev, uint8_t irqNum) = 0; 13 | virtual bool CanSetIRQ() = 0; 14 | virtual void SetIRQ(uint8_t irqNum, int level) = 0; 15 | }; 16 | 17 | class DefaultIRQMapper : public IRQMapper { 18 | public: 19 | uint8_t MapIRQ(PCIDevice *dev, uint8_t irqNum) override; 20 | bool CanSetIRQ() override; 21 | void SetIRQ(uint8_t irqNum, int level) override; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/usb_pci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pci.h" 4 | 5 | namespace strikebox { 6 | 7 | 8 | class USBPCIDevice : public PCIDevice { 9 | public: 10 | USBPCIDevice(uint8_t irqn, virt86::VirtualProcessor& vp); 11 | virtual ~USBPCIDevice(); 12 | 13 | // PCI Device functions 14 | void Init(); 15 | void Reset(); 16 | 17 | void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override; 18 | void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override; 19 | private: 20 | uint8_t m_irqn; 21 | virt86::VirtualProcessor& m_vp; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/timer.h" 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | /*! 8 | * Constructor 9 | */ 10 | Timer::Timer() { 11 | } 12 | 13 | /*! 14 | * Start the timer 15 | */ 16 | void Timer::Start() { 17 | m_start = high_resolution_clock::now(); 18 | } 19 | 20 | /*! 21 | * Stop the timer 22 | */ 23 | void Timer::Stop() { 24 | m_end = high_resolution_clock::now(); 25 | } 26 | 27 | /*! 28 | * Get number of milliseconds elapsed between calls made to \a Start and 29 | * \a Stop 30 | */ 31 | uint64_t Timer::GetMillisecondsElapsed() { 32 | return duration_cast(m_end - m_start).count(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "virt86/virt86.hpp" 4 | 5 | #include "strikebox/log.h" 6 | 7 | namespace strikebox { 8 | 9 | /*! 10 | * Print the CPU registers 11 | */ 12 | void DumpCPURegisters(virt86::VirtualProcessor& vp); 13 | 14 | /*! 15 | * Dump CPU stack 16 | */ 17 | void DumpCPUStack(virt86::VirtualProcessor& vp, int32_t offsetStart = -0x20, int32_t offsetEnd = 0x10); 18 | 19 | /*! 20 | * Dump memory 21 | */ 22 | void DumpCPUMemory(virt86::VirtualProcessor& vp, uint32_t address, uint32_t size, bool physical); 23 | 24 | /*! 25 | * Disassemble memory region 26 | */ 27 | void DumpCPUDisassembly(virt86::VirtualProcessor& vp, uint32_t address, uint32_t size, bool physical); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/basic/mcpx.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/basic/mcpx.h" 2 | 3 | #include "strikebox/hw/defs.h" 4 | 5 | namespace strikebox { 6 | 7 | MCPXRevision MCPXRevisionFromHardwareModel(HardwareModel hardwareModel) { 8 | switch (hardwareModel) { 9 | case Revision1_0: 10 | case Revision1_1: 11 | case Revision1_2: 12 | case Revision1_3: 13 | case Revision1_4: 14 | case Revision1_5: 15 | case Revision1_6: 16 | return MCPXRevision::MCPX_X3; 17 | case DebugKit: 18 | // EmuWarning("Guessing MCPXVersion"); 19 | return MCPXRevision::MCPX_X2; 20 | default: 21 | // UNREACHABLE(hardwareModel); 22 | return MCPXRevision::MCPX_X3; 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/ac97.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | #include "pci.h" 7 | 8 | namespace strikebox { 9 | 10 | class AC97Device : public PCIDevice { 11 | public: 12 | // constructor 13 | AC97Device(); 14 | virtual ~AC97Device(); 15 | 16 | // PCI Device functions 17 | void Init(); 18 | void Reset(); 19 | 20 | void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override; 21 | void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override; 22 | void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override; 23 | void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override; 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/sm/sm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | class SMDevice { 8 | public: 9 | virtual void Init() = 0; 10 | virtual void Reset() = 0; 11 | 12 | virtual void QuickCommand(bool read) = 0; 13 | virtual uint8_t ReceiveByte() = 0; 14 | virtual uint8_t ReadByte(uint8_t command) = 0; 15 | virtual uint16_t ReadWord(uint8_t command) = 0; 16 | virtual int ReadBlock(uint8_t command, uint8_t *data) = 0; 17 | 18 | virtual void SendByte(uint8_t data) = 0; 19 | virtual void WriteByte(uint8_t command, uint8_t value) = 0; 20 | virtual void WriteWord(uint8_t command, uint16_t value) = 0; 21 | virtual void WriteBlock(uint8_t command, uint8_t* data, int length) = 0; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/nvapu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pci.h" 4 | 5 | namespace strikebox { 6 | 7 | #define NVNET_ADDR 0xFEF00000 8 | #define NVNET_SIZE 0x00000400 9 | 10 | class NVAPUDevice : public PCIDevice { 11 | public: 12 | NVAPUDevice(); 13 | virtual ~NVAPUDevice(); 14 | 15 | // PCI Device functions 16 | void Init(); 17 | void Reset(); 18 | 19 | void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override; 20 | void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override; 21 | void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override; 22 | void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override; 23 | }; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/nvnet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pci.h" 4 | 5 | namespace strikebox { 6 | 7 | #define NVNET_ADDR 0xFEF00000 8 | #define NVNET_SIZE 0x00000400 9 | 10 | class NVNetDevice : public PCIDevice { 11 | public: 12 | NVNetDevice(); 13 | virtual ~NVNetDevice(); 14 | 15 | // PCI Device functions 16 | void Init(); 17 | void Reset(); 18 | 19 | void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override; 20 | void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override; 21 | void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override; 22 | void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override; 23 | }; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/basic/char_null.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/basic/char_null.h" 2 | 3 | namespace strikebox { 4 | 5 | bool NullCharDriver::Init() { 6 | // Nothing to initialize 7 | return true; 8 | } 9 | 10 | int NullCharDriver::Write(const uint8_t *buf, int len) { 11 | // Discard everything 12 | return 1; 13 | } 14 | 15 | void NullCharDriver::AcceptInput() { 16 | // Nothing to do 17 | } 18 | 19 | void NullCharDriver::Stop() { 20 | // Nothing to do 21 | } 22 | 23 | // ----- IOCTLs --------------------------------------------------------------- 24 | 25 | void NullCharDriver::SetBreakEnable(bool breakEnable) { 26 | // Nothing to do 27 | } 28 | 29 | void NullCharDriver::SetSerialParameters(SerialParams *params) { 30 | // Nothing to do 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/pci/mcpx_ram.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/pci/mcpx_ram.h" 2 | 3 | #include "strikebox/log.h" 4 | 5 | namespace strikebox { 6 | 7 | MCPXRAMDevice::MCPXRAMDevice(MCPXRevision revision) 8 | : PCIDevice(PCI_HEADER_TYPE_MULTIFUNCTION, PCI_VENDOR_ID_NVIDIA, 0x02A6, 0xA1, 9 | 0x05, 0x00, 0x00) // RAM controller 10 | { 11 | m_revision = revision; 12 | } 13 | 14 | MCPXRAMDevice::~MCPXRAMDevice() { 15 | } 16 | 17 | // PCI Device functions 18 | 19 | void MCPXRAMDevice::Init() { 20 | // Initialize configuration space 21 | Write16(m_configSpace, PCI_STATUS, PCI_STATUS_66MHZ); 22 | 23 | // Unknown registers 24 | Write32(m_configSpace, 0x64, 0x1208001); 25 | Write32(m_configSpace, 0x68, 0x6c); 26 | } 27 | 28 | void MCPXRAMDevice::Reset() { 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/sm/tvenc_conexant.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "tvenc.h" 4 | 5 | namespace strikebox { 6 | 7 | class TVEncConexantDevice : public TVEncoderDevice { 8 | public: 9 | virtual ~TVEncConexantDevice(); 10 | 11 | // SMDevice functions 12 | void Init(); 13 | void Reset(); 14 | 15 | void QuickCommand(bool read); 16 | uint8_t ReceiveByte(); 17 | uint8_t ReadByte(uint8_t command); 18 | uint16_t ReadWord(uint8_t command); 19 | int ReadBlock(uint8_t command, uint8_t *data); 20 | 21 | void SendByte(uint8_t data); 22 | void WriteByte(uint8_t command, uint8_t value); 23 | void WriteWord(uint8_t command, uint16_t value); 24 | void WriteBlock(uint8_t command, uint8_t* data, int length); 25 | private: 26 | uint8_t m_registers[256]; 27 | }; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/pcibridge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | #include "pci.h" 7 | #include "../bus/pcibus.h" 8 | #include "pci_irq.h" 9 | 10 | namespace strikebox { 11 | 12 | class PCIBridgeDevice : public PCIDevice { 13 | public: 14 | // constructor 15 | PCIBridgeDevice(); 16 | virtual ~PCIBridgeDevice(); 17 | 18 | // PCI Device functions 19 | virtual void Init() override; 20 | virtual void Reset() override; 21 | 22 | void WriteConfig(uint32_t reg, uint32_t value, uint8_t size) override; 23 | 24 | inline PCIBus *GetSecondaryBus() { return m_secBus; } 25 | 26 | protected: 27 | PCIBridgeDevice(uint16_t vendorID, uint16_t deviceID, uint8_t revisionID); 28 | virtual IRQMapper *GetIRQMapper(); 29 | 30 | private: 31 | PCIBus *m_secBus; 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/mem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace strikebox { 4 | 5 | // The following physical memory ranges are reserved on all systems: 6 | // 0x00000000 - 0x00000003 :: D3D push buffer address 7 | // 0x0000f000 - 0x0000ffff :: Page directory 8 | // 9 | // On 64 MiB systems, the following ranges are also reserved: 10 | // 0x03fe0000 - 0x03feffff :: NV2A instance memory 11 | // 0x03ff0000 - 0x03ffffff :: PFN database 12 | // 13 | // On 128 MiB systems, the following ranges are also reserved: 14 | // 0x07fd0000 - 0x07feffff :: PFN database 15 | // 0x07ff0000 - 0x07ffffff :: NV2A instance memry 16 | // 17 | // The kernel image is decrypted and extracted at physical address 0x10000 and 18 | // manually mapped to virtual address 0x80010000. 19 | 20 | #define XBOX_RAM_SIZE_RETAIL (64 * MiB) 21 | #define XBOX_RAM_SIZE_DEBUG (128 * MiB) 22 | #define XBOX_ROM_AREA_SIZE (16 * MiB) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/cmds/cmd_packet.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/cmds/cmd_packet.h" 13 | 14 | #include "strikebox/log.h" 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace ata { 19 | namespace cmd { 20 | 21 | Packet::Packet(ATADevice& device) 22 | : PacketProtocolCommand(device) { 23 | } 24 | 25 | Packet::~Packet() { 26 | } 27 | 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/cmds/cmd_read_dma.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/cmds/cmd_read_dma.h" 13 | 14 | #include "strikebox/log.h" 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace ata { 19 | namespace cmd { 20 | 21 | ReadDMA::ReadDMA(ATADevice& device) 22 | : DMAProtocolCommand(device, false) { 23 | } 24 | 25 | ReadDMA::~ReadDMA() { 26 | } 27 | 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/cmds/cmd_write_dma.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/cmds/cmd_write_dma.h" 13 | 14 | #include "strikebox/log.h" 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace ata { 19 | namespace cmd { 20 | 21 | WriteDMA::WriteDMA(ATADevice& device) 22 | : DMAProtocolCommand(device, true) { 23 | } 24 | 25 | WriteDMA::~WriteDMA() { 26 | } 27 | 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/core.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/core.h" 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | #define SBX_VERSION_MAJOR 0 8 | #define SBX_VERSION_MINOR 0 9 | #define SBX_VERSION_PATCH 1 10 | #define STRFY(x) #x 11 | 12 | // TODO: add other things: 13 | // - git commit hash 14 | // - build date 15 | // - compiler name and version 16 | 17 | #define MAKE_VERSION_STRING(major, minor, patch) (STRFY(major) "." STRFY(minor) "." STRFY(patch)) 18 | #define MAKE_VERSION_ID(major, minor, patch) ((((uint64_t)major) << 48ull) | (((uint64_t)minor) << 32ull) | ((uint64_t)patch)) 19 | 20 | static const StrikeBoxInfo g_StrikeBoxInfo = { 21 | MAKE_VERSION_STRING(SBX_VERSION_MAJOR, SBX_VERSION_MINOR, SBX_VERSION_PATCH), 22 | MAKE_VERSION_ID(SBX_VERSION_MAJOR, SBX_VERSION_MINOR, SBX_VERSION_PATCH) 23 | }; 24 | 25 | const struct StrikeBoxInfo * GetStrikeBoxInfo() { 26 | return &g_StrikeBoxInfo; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /modules/core/src/windows/thread.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/thread.h" 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | const DWORD MS_VC_EXCEPTION = 0x406D1388; 8 | 9 | #pragma pack(push,8) 10 | typedef struct tagTHREADNAME_INFO { 11 | DWORD dwType; // Must be 0x1000. 12 | LPCSTR szName; // Pointer to name (in user addr space). 13 | DWORD dwThreadID; // Thread ID (-1=caller thread). 14 | DWORD dwFlags; // Reserved for future use, must be zero. 15 | } THREADNAME_INFO; 16 | #pragma pack(pop) 17 | 18 | void Thread_SetName(const char *threadName) { 19 | THREADNAME_INFO info; 20 | info.dwType = 0x1000; 21 | info.szName = threadName; 22 | info.dwThreadID = GetCurrentThreadId(); 23 | info.dwFlags = 0; 24 | 25 | __try { 26 | RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); 27 | } 28 | __except (EXCEPTION_EXECUTE_HANDLER) { 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/sm/tvenc.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/sm/tvenc.h" 2 | 3 | namespace strikebox { 4 | 5 | TVEncoder TVEncoderFromHardwareModel(HardwareModel hardwareModel) { 6 | switch (hardwareModel) { 7 | case Revision1_0: 8 | case Revision1_1: 9 | case Revision1_2: 10 | case Revision1_3: 11 | return TVEncoder::Conexant; 12 | case Revision1_4: 13 | return TVEncoder::Focus; 14 | case Revision1_5: 15 | return TVEncoder::Focus; // Assumption 16 | case Revision1_6: 17 | return TVEncoder::XCalibur; 18 | case DebugKit: 19 | // LukeUsher : My debug kit and at least most of them (maybe all?) 20 | // are equivalent to v1.0 and have Conexant encoders. 21 | return TVEncoder::Conexant; 22 | default: 23 | // UNREACHABLE(hardwareModel); 24 | return TVEncoder::Focus; 25 | } 26 | } 27 | 28 | TVEncoderDevice::~TVEncoderDevice() { 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/sm/eeprom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sm.h" 4 | 5 | namespace strikebox { 6 | 7 | #define EEPROM_SIZE 256 8 | 9 | class EEPROMDevice : public SMDevice { 10 | public: 11 | virtual ~EEPROMDevice(); 12 | 13 | // SMDevice functions 14 | void Init(); 15 | void Reset(); 16 | 17 | void QuickCommand(bool read); 18 | uint8_t ReceiveByte(); 19 | uint8_t ReadByte(uint8_t command); 20 | uint16_t ReadWord(uint8_t command); 21 | int ReadBlock(uint8_t command, uint8_t *data); 22 | 23 | void SendByte(uint8_t data); 24 | void WriteByte(uint8_t command, uint8_t value); 25 | void WriteWord(uint8_t command, uint16_t value); 26 | void WriteBlock(uint8_t command, uint8_t* data, int length); 27 | 28 | // EEPROMDevice function 29 | void SetEEPROM(const uint8_t* pEEPROM) { memcpy(m_pEEPROM, pEEPROM, EEPROM_SIZE); }; 30 | private: 31 | uint8_t m_pEEPROM[EEPROM_SIZE]; 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pramin.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRAMIN (RAMIN access) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pramin.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PRAMIN::Reset() { 17 | std::fill(m_mem, m_mem + m_length, 0); 18 | } 19 | 20 | uint32_t PRAMIN::Read(const uint32_t addr) { 21 | return *reinterpret_cast(&m_mem[addr]); 22 | } 23 | 24 | void PRAMIN::Write(const uint32_t addr, const uint32_t value) { 25 | *reinterpret_cast(&m_mem[addr]) = value; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | /*! 8 | * Get last byte of a range from offset + length. 9 | * Undefined for ranges that wrap around 0. 10 | */ 11 | static inline uint64_t RangeGetLast(uint64_t offset, uint64_t len) { 12 | return offset + len - 1; 13 | } 14 | 15 | /*! 16 | * Check whether a given range covers a given byte. 17 | */ 18 | static inline int RangeCoversByte(uint64_t offset, uint64_t len, uint64_t byte) { 19 | return offset <= byte && byte <= RangeGetLast(offset, len); 20 | } 21 | 22 | /*! 23 | * Check whether 2 given ranges overlap. 24 | * Undefined if ranges that wrap around 0. 25 | */ 26 | static inline int RangesOverlap(uint64_t first1, uint64_t len1, uint64_t first2, uint64_t len2) { 27 | uint64_t last1 = RangeGetLast(first1, len1); 28 | uint64_t last2 = RangeGetLast(first2, len2); 29 | 30 | return !(last2 < first1 || last1 < first2); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/nv2a.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "pci.h" 6 | #include "../basic/irq.h" 7 | #include "../gpu/nv2a.h" 8 | 9 | namespace strikebox { 10 | 11 | class NV2ADevice : public PCIDevice { 12 | public: 13 | NV2ADevice(uint8_t *pSystemRAM, uint32_t systemRAMSize, IRQHandler& irqHandler); 14 | virtual ~NV2ADevice(); 15 | 16 | // PCI Device functions 17 | void Init(); 18 | void Reset(); 19 | 20 | void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override; 21 | void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override; 22 | void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override; 23 | void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override; 24 | 25 | private: 26 | IRQHandler& m_irqHandler; 27 | 28 | // NV2A state 29 | std::unique_ptr m_nv2a; 30 | }; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /modules/core/src/windows/strikebox/hw/basic/win32/char_serial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strikebox/hw/basic/char.h" 4 | #include "strikebox/thread.h" 5 | #include "mt_serial.h" 6 | 7 | #include 8 | 9 | namespace strikebox { 10 | 11 | class Win32SerialDriver : public CharDriver { 12 | public: 13 | Win32SerialDriver(uint8_t portNum); 14 | virtual ~Win32SerialDriver(); 15 | 16 | bool Init() override; 17 | int Write(const uint8_t *buf, int len) override; 18 | void AcceptInput() override; 19 | void Stop() override; 20 | 21 | // IOCTLs 22 | void SetBreakEnable(bool breakEnable) override; 23 | void SetSerialParameters(SerialParams *params) override; 24 | 25 | private: 26 | SerialComm *m_comm; 27 | 28 | void Close(); 29 | 30 | static void ReaderFunc(void *userData, uint8_t *buf, uint32_t len); 31 | static void EventFunc(void *userData, SerialCommEvent evt); 32 | 33 | void CommEvent(SerialCommEvent evt); 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/prom.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PROM (ROM access window) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PROM engine registers occupy the range 0x300000..0x31FFFF. 12 | #pragma once 13 | 14 | #include "../engine.h" 15 | 16 | namespace strikebox::nv2a { 17 | 18 | // NV2A ROM access window engine (PROM) 19 | class PROM : public NV2AEngine { 20 | public: 21 | PROM(NV2A& nv2a) : NV2AEngine("PROM", 0x300000, 0x20000, nv2a) {} 22 | 23 | void Reset() override; 24 | uint32_t Read(const uint32_t addr) override; 25 | void Write(const uint32_t addr, const uint32_t value) override; 26 | }; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/prma.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRMA (Real mode BAR access) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/prma.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PRMA::Reset() { 17 | } 18 | 19 | uint32_t PRMA::Read(const uint32_t addr) { 20 | log_spew("[NV2A] PRMA::Read: Unimplemented read! address = 0x%x\n", addr); 21 | return 0; 22 | } 23 | 24 | void PRMA::Write(const uint32_t addr, const uint32_t value) { 25 | log_spew("[NV2A] PRMA::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/prom.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PROM (ROM access window) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/prom.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PROM::Reset() { 17 | } 18 | 19 | uint32_t PROM::Read(const uint32_t addr) { 20 | log_spew("[NV2A] PROM::Read: Unimplemented read! address = 0x%x\n", addr); 21 | return 0; 22 | } 23 | 24 | void PROM::Write(const uint32_t addr, const uint32_t value) { 25 | log_spew("[NV2A] PROM::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/i8254.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "irq.h" 7 | #include "strikebox/io.h" 8 | 9 | namespace strikebox { 10 | 11 | #define PORT_PIT_DATA_0 0x40 12 | #define PORT_PIT_DATA_1 0x41 13 | #define PORT_PIT_DATA_2 0x42 14 | #define PORT_PIT_COMMAND 0x43 15 | 16 | #define PORT_PIT_BASE PORT_PIT_DATA_0 17 | #define PORT_PIT_COUNT (PORT_PIT_COMMAND - PORT_PIT_DATA_0 + 1) 18 | 19 | class i8254 : public IODevice { 20 | public: 21 | i8254(IRQHandler& irqHandler, float tickRate = 1000.0f); 22 | virtual ~i8254(); 23 | void Reset(); 24 | 25 | bool MapIO(IOMapper *mapper); 26 | 27 | bool IORead(uint32_t port, uint32_t *value, uint8_t size) override; 28 | bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override; 29 | 30 | void Run(); 31 | private: 32 | IRQHandler& m_irqHandler; 33 | float m_tickRate; 34 | bool m_running; 35 | 36 | std::thread m_timerThread; 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/defs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | // Constants for SMBus device addresses. 8 | // The constants point to the write address. 9 | // Reads are done on write address + 1. 10 | const uint8_t kSMBusAddress_MCPX = 0x10; 11 | const uint8_t kSMBusAddress_TVEncoder = 0x88; 12 | const uint8_t kSMBusAddress_SystemMicroController = 0x20; 13 | const uint8_t kSMBusAddress_TemperatureMeasurement = 0x98; 14 | const uint8_t kSMBusAddress_EEPROM = 0xA8; 15 | const uint8_t kSMBusAddress_TVEncoder_ID_Conexant = 0x8A; 16 | const uint8_t kSMBusAddress_TVEncoder_ID_Focus = 0xD4; 17 | const uint8_t kSMBusAddress_TVEncoder_ID_XCalibur = 0xE0; 18 | 19 | // Xbox hardware models. 20 | // These affect the configuration of various hardware components. 21 | typedef enum { 22 | Revision1_0, 23 | Revision1_1, 24 | Revision1_2, 25 | Revision1_3, 26 | Revision1_4, 27 | Revision1_5, 28 | Revision1_6, 29 | DebugKit 30 | } HardwareModel; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pstraps.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PSTRAPS (Straps readout) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pstraps.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PSTRAPS::Reset() { 17 | } 18 | 19 | uint32_t PSTRAPS::Read(const uint32_t addr) { 20 | log_spew("[NV2A] PSTRAPS::Read: Unimplemented read! address = 0x%x\n", addr); 21 | return 0; 22 | } 23 | 24 | void PSTRAPS::Write(const uint32_t addr, const uint32_t value) { 25 | log_spew("[NV2A] PSTRAPS::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | #define LOG_LEVEL_FATAL (1) 8 | #define LOG_LEVEL_ERROR (2) 9 | #define LOG_LEVEL_WARNING (3) 10 | #define LOG_LEVEL_INFO (4) 11 | #define LOG_LEVEL_DEBUG (5) 12 | #define LOG_LEVEL_SPEW (6) 13 | 14 | #define LOG_LEVEL LOG_LEVEL_SPEW 15 | 16 | #if 1 17 | #define log_fatal(...) log_print(LOG_LEVEL_FATAL, __VA_ARGS__) 18 | #define log_error(...) log_print(LOG_LEVEL_ERROR, __VA_ARGS__) 19 | #define log_warning(...) log_print(LOG_LEVEL_WARNING, __VA_ARGS__) 20 | #define log_info(...) log_print(LOG_LEVEL_INFO, __VA_ARGS__) 21 | #define log_debug(...) log_print(LOG_LEVEL_DEBUG, __VA_ARGS__) 22 | #define log_spew(...) log_print(LOG_LEVEL_SPEW, __VA_ARGS__) 23 | #else 24 | #define log_fatal(...) 25 | #define log_error(...) 26 | #define log_warning(...) 27 | #define log_info(...) 28 | #define log_debug(...) 29 | #define log_spew(...) 30 | #endif 31 | 32 | int log_print(int level, const char *fmt, ...); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pcounter.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PCOUNTER (Performance monitoring counters) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pcounter.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PCOUNTER::Reset() { 17 | } 18 | 19 | uint32_t PCOUNTER::Read(const uint32_t addr) { 20 | log_spew("[NV2A] PCOUNTER::Read: Unimplemented read! address = 0x%x\n", addr); 21 | return 0; 22 | } 23 | 24 | void PCOUNTER::Write(const uint32_t addr, const uint32_t value) { 25 | log_spew("[NV2A] PCOUNTER::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/prma.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRMA (Real mode BAR access) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PRMA provides access to BAR registers through real mode. 12 | // 13 | // PRMA engine registers occupy the range 0x007000..0x007FFF. 14 | #pragma once 15 | 16 | #include "../engine.h" 17 | 18 | namespace strikebox::nv2a { 19 | 20 | // NV2A real mode BAR access (PRMA) 21 | class PRMA : public NV2AEngine { 22 | public: 23 | PRMA(NV2A& nv2a) : NV2AEngine("PRMA", 0x007000, 0x1000, nv2a) {} 24 | 25 | void Reset() override; 26 | uint32_t Read(const uint32_t addr) override; 27 | void Write(const uint32_t addr, const uint32_t value) override; 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/drvs/drv_null.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/drvs/drv_null.h" 13 | 14 | #include "strikebox/log.h" 15 | #include "strikebox/io.h" 16 | 17 | namespace strikebox { 18 | namespace hw { 19 | namespace ata { 20 | 21 | NullATADeviceDriver g_nullATADeviceDriver; 22 | 23 | NullATADeviceDriver::~NullATADeviceDriver() { 24 | } 25 | 26 | void NullATADeviceDriver::IdentifyDevice(IdentifyDeviceData *data) { 27 | // Fill in with zeros 28 | memset(data, 0, sizeof(IdentifyDeviceData)); 29 | } 30 | 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/ata_device.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/ata_device.h" 13 | 14 | #include "strikebox/log.h" 15 | #include "strikebox/io.h" 16 | 17 | namespace strikebox { 18 | namespace hw { 19 | namespace ata { 20 | 21 | ATADevice::ATADevice(Channel channel, uint8_t devIndex, ATARegisters& regs, InterruptTrigger& interrupt) 22 | : m_channel(channel) 23 | , m_devIndex(devIndex) 24 | , m_driver(&g_nullATADeviceDriver) 25 | , m_regs(regs) 26 | , m_interrupt(interrupt) 27 | { 28 | } 29 | 30 | ATADevice::~ATADevice() { 31 | } 32 | 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_packet.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_packet.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Packet command (0xA0) [8.45]. 25 | */ 26 | class Packet : public PacketProtocolCommand { 27 | public: 28 | Packet(ATADevice& device); 29 | virtual ~Packet() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | }; 33 | 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_read_dma.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_dma.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Read DMA command (0xC8) [8.23]. 25 | */ 26 | class ReadDMA : public DMAProtocolCommand { 27 | public: 28 | ReadDMA(ATADevice& device); 29 | virtual ~ReadDMA() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | }; 33 | 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_write_dma.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_dma.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Write DMA command (0xCA) [8.45]. 25 | */ 26 | class WriteDMA : public DMAProtocolCommand { 27 | public: 28 | WriteDMA(ATADevice& device); 29 | virtual ~WriteDMA() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | }; 33 | 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/user.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A USER (PFIFO MMIO/DMA submission area) emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // The USER area is a portion of shared system memory where FIFO commands are submitted 12 | // for processing by the GPU. 13 | // 14 | // USER engine registers occupy the range 0x800000..0x9FFFFF. 15 | #pragma once 16 | 17 | #include "../engine.h" 18 | 19 | namespace strikebox::nv2a { 20 | 21 | // NV2A PFIFO MMIO/DMA submission area (USER) 22 | class USER : public NV2AEngine { 23 | public: 24 | USER(NV2A& nv2a) : NV2AEngine("USER", 0x800000, 0x200000, nv2a) {} 25 | 26 | void Reset() override; 27 | uint32_t Read(const uint32_t addr) override; 28 | void Write(const uint32_t addr, const uint32_t value) override; 29 | }; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/cmds/ata_command.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/cmds/ata_command.h" 13 | 14 | #include "strikebox/log.h" 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace ata { 19 | namespace cmd { 20 | 21 | IATACommand::IATACommand(ATADevice& device) 22 | : m_device(device) 23 | , m_regs(device.GetRegisters()) 24 | , m_driver(device.GetDriver()) 25 | , m_channel(device.GetChannel()) 26 | , m_devIndex(device.GetIndex()) 27 | , m_interrupt(device.GetInterrupt()) 28 | , m_finished(false) 29 | { 30 | } 31 | 32 | IATACommand::~IATACommand() { 33 | } 34 | 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/atapi/atapi_xbox.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Reverse-engineered Xbox-specific data structures and definitions. 5 | // 6 | // Sources: 7 | // [c] Cxbx-Reloaded 8 | // https://github.com/Cxbx-Reloaded/Cxbx-Reloaded 9 | // 10 | // [w] XboxDevWiki 11 | // https://xboxdevwiki.net 12 | #pragma once 13 | 14 | #include 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace atapi { 19 | 20 | // SCSI MODE SENSE and MODE SELECT page code for the security data. 21 | // Contains the XboxDVDAuthentication struct. 22 | // [w] http://xboxdevwiki.net/DVD_Drive 23 | const uint8_t kPageCodeAuthentication = 0x3E; 24 | 25 | // The Xbox DVD authentication page data. 26 | // [c] https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/e452d56991c7dce655511c5529f4cf1a6fe98e42/import/OpenXDK/include/xboxkrnl/xboxkrnl.h#L2494 27 | struct XboxDVDAuthentication { 28 | uint8_t Unknown[2]; 29 | uint8_t PartitionArea; 30 | uint8_t CDFValid; 31 | uint8_t Authentication; 32 | uint8_t Unknown2[3]; 33 | uint8_t Unknown3[3]; 34 | }; 35 | 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/drvs/ata_device_driver.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/drvs/ata_device_driver.h" 13 | 14 | #include "strikebox/log.h" 15 | #include "strikebox/io.h" 16 | 17 | namespace strikebox { 18 | namespace hw { 19 | namespace ata { 20 | 21 | IATADeviceDriver::~IATADeviceDriver() { 22 | } 23 | 24 | void IATADeviceDriver::SetPIOTransferMode(PIOTransferType type, uint8_t mode) { 25 | m_pioTransferType = type; 26 | m_pioTransferMode = mode; 27 | } 28 | 29 | void IATADeviceDriver::SetDMATransferMode(DMATransferType type, uint8_t mode) { 30 | m_dmaTransferType = type; 31 | m_dmaTransferMode = mode; 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/sm/led.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace strikebox { 4 | namespace LED { 5 | 6 | // See http://xboxdevwiki.net/PIC#The_LED 7 | 8 | union Sequence { 9 | struct { 10 | uint8_t greenPhases : 4; 11 | uint8_t redPhases : 4; 12 | }; 13 | uint8_t asUint8; 14 | 15 | Sequence(const uint8_t greenPhases, const uint8_t redPhases) { 16 | this->greenPhases = greenPhases; 17 | this->redPhases = redPhases; 18 | } 19 | 20 | Sequence(const uint8_t& val) { 21 | asUint8 = val; 22 | } 23 | 24 | operator uint8_t() { 25 | return asUint8; 26 | } 27 | 28 | const char *Name(uint8_t phase) { 29 | if (phase > 3) { 30 | return ""; 31 | } 32 | 33 | uint8_t mask = (1 << phase); 34 | bool green = (greenPhases & mask); 35 | bool red = (redPhases & mask); 36 | if (green && red) { 37 | return "Orange"; 38 | } 39 | if (green) { 40 | return "Green"; 41 | } 42 | if (red) { 43 | return "Red"; 44 | } 45 | return "Off"; 46 | } 47 | }; 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/prmdio.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRMDIO (VGA DAC registers) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PRMDIO engine registers occupy the range 0x681000..0x681FFF. 12 | #pragma once 13 | 14 | #include "../engine.h" 15 | 16 | namespace strikebox::nv2a { 17 | 18 | // NV2A VGA DAC registers engine (PRMDIO) 19 | class PRMDIO : public NV2AEngine { 20 | public: 21 | PRMDIO(NV2A& nv2a) : NV2AEngine("PRMDIO", 0x681000, 0x1000, nv2a) {} 22 | 23 | void Reset() override; 24 | uint32_t Read(const uint32_t addr) override; 25 | void Write(const uint32_t addr, const uint32_t value) override; 26 | uint32_t ReadUnaligned(const uint32_t addr, const uint8_t size) override; 27 | void WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) override; 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/ata_common.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/ata_common.h" 13 | 14 | namespace strikebox { 15 | namespace hw { 16 | namespace ata { 17 | 18 | void ATARegisters::WriteSignature(bool packetFeatureSet) { 19 | // Write signature according to Signature and Persistence protocol [9.1] 20 | if (packetFeatureSet) { 21 | sectorCount = 0x01; 22 | sectorNumber = 0x01; 23 | cylinder = 0xEB14; 24 | deviceHead = 0x10; 25 | } 26 | else { 27 | sectorCount = 0x01; 28 | sectorNumber = 0x01; 29 | cylinder = 0x0000; 30 | deviceHead = 0x00; 31 | } 32 | } 33 | 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pnvio.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PNVIO (VGA sequencer and graph controller registers) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PNVIO engine registers occupy the range 0x0C0000..0x0C0FFF. 12 | #pragma once 13 | 14 | #include "../engine.h" 15 | 16 | namespace strikebox::nv2a { 17 | 18 | // NV2A VGA sequencer and graph controller registers (PNVIO) 19 | class PNVIO : public NV2AEngine { 20 | public: 21 | PNVIO(NV2A& nv2a) : NV2AEngine("PNVIO", 0x0C0000, 0x1000, nv2a) {} 22 | 23 | void Reset() override; 24 | uint32_t Read(const uint32_t addr) override; 25 | void Write(const uint32_t addr, const uint32_t value) override; 26 | uint32_t ReadUnaligned(const uint32_t addr, const uint8_t size) override; 27 | void WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) override; 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/prmcio.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRMCIO (VGA CRTC and attribute controller registers) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PRMCIO engine registers occupy the range 0x601000..0x601FFF. 12 | #pragma once 13 | 14 | #include "../engine.h" 15 | 16 | namespace strikebox::nv2a { 17 | 18 | // NV2A VGA CRTC and attribute controller registers engine (PRMCIO) 19 | class PRMCIO : public NV2AEngine { 20 | public: 21 | PRMCIO(NV2A& nv2a) : NV2AEngine("PRMCIO", 0x601000, 0x1000, nv2a) {} 22 | 23 | void Reset() override; 24 | uint32_t Read(const uint32_t addr) override; 25 | void Write(const uint32_t addr, const uint32_t value) override; 26 | uint32_t ReadUnaligned(const uint32_t addr, const uint8_t size) override; 27 | void WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) override; 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/sm/adm1032.h: -------------------------------------------------------------------------------- 1 | // ADM1032 emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Datasheet: https://www.onsemi.com/pub/Collateral/ADM1032-D.PDF 5 | #pragma once 6 | 7 | #include "sm.h" 8 | 9 | namespace strikebox { 10 | 11 | enum ADM1032Register { 12 | ADM1032RegLocalTemp = 0x00, // (Read-only) Local Temperature Value 13 | ADM1032RegExtTempHigh = 0x01, // (Read-only) External Temperature Value high byte 14 | ADM1032RegExtTempLow = 0x10, // (Read-only) External Temperature Value low byte (only 3 most significant bits used, 0.125 C increments) 15 | }; 16 | 17 | class ADM1032Device : public SMDevice { 18 | public: 19 | virtual ~ADM1032Device(); 20 | 21 | // SMDevice functions 22 | void Init(); 23 | void Reset(); 24 | 25 | void QuickCommand(bool read); 26 | uint8_t ReceiveByte(); 27 | uint8_t ReadByte(uint8_t command); 28 | uint16_t ReadWord(uint8_t command); 29 | int ReadBlock(uint8_t command, uint8_t *data); 30 | 31 | void SendByte(uint8_t data); 32 | void WriteByte(uint8_t command, uint8_t value); 33 | void WriteWord(uint8_t command, uint16_t value); 34 | void WriteBlock(uint8_t command, uint8_t* data, int length); 35 | }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/bmide.h: -------------------------------------------------------------------------------- 1 | // Bus Master PCI IDE Controller emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on the Programming Interface for Bus Master IDE Controller 5 | // Revision 1.0 available at http://www.bswd.com/idems100.pdf 6 | // and complemented with information from PC87415 at 7 | // https://parisc.wiki.kernel.org/images-parisc/0/0a/PC87415.pdf 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | #include "../defs.h" 14 | #include "pci.h" 15 | #include "bmide_defs.h" 16 | #include "bmide_channel.h" 17 | #include "strikebox/hw/ata/ata.h" 18 | 19 | namespace strikebox { 20 | namespace hw { 21 | namespace bmide { 22 | 23 | class BMIDEDevice : public PCIDevice { 24 | public: 25 | // constructor 26 | BMIDEDevice(uint8_t *ram, uint32_t ramSize, hw::ata::ATA& ata); 27 | virtual ~BMIDEDevice(); 28 | 29 | // PCI Device functions 30 | void Init(); 31 | void Reset(); 32 | 33 | void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override; 34 | void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override; 35 | private: 36 | BMIDEChannel *m_channels[2]; 37 | }; 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/drvs/drv_vdvd_dummy.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/drvs/drv_vdvd_dummy.h" 13 | 14 | #include "strikebox/log.h" 15 | #include "strikebox/io.h" 16 | 17 | namespace strikebox { 18 | namespace hw { 19 | namespace ata { 20 | 21 | DummyDVDDriveATADeviceDriver::DummyDVDDriveATADeviceDriver() { 22 | strcpy(m_serialNumber, "0123456789"); 23 | strcpy(m_firmwareRevision, "1.0.0"); 24 | strcpy(m_modelNumber, "SBx DDVDD0010000"); 25 | } 26 | 27 | DummyDVDDriveATADeviceDriver::~DummyDVDDriveATADeviceDriver() { 28 | } 29 | 30 | bool DummyDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) { 31 | // Always fail; no media in drive 32 | return false; 33 | } 34 | 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/sm/eeprom.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/sm/eeprom.h" 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | EEPROMDevice::~EEPROMDevice() { 8 | } 9 | 10 | void EEPROMDevice::Init() { 11 | // TODO 12 | } 13 | 14 | void EEPROMDevice::Reset() { 15 | // TODO 16 | } 17 | 18 | void EEPROMDevice::QuickCommand(bool read) { 19 | // TODO 20 | } 21 | 22 | uint8_t EEPROMDevice::ReceiveByte() { 23 | return 0; // TODO 24 | } 25 | 26 | uint8_t EEPROMDevice::ReadByte(uint8_t command) { 27 | return *(m_pEEPROM + command); 28 | } 29 | 30 | uint16_t EEPROMDevice::ReadWord(uint8_t command) { 31 | return *((uint16_t*)(m_pEEPROM + command)); 32 | } 33 | 34 | int EEPROMDevice::ReadBlock(uint8_t command, uint8_t *data) { 35 | return 0; // TODO 36 | } 37 | 38 | void EEPROMDevice::SendByte(uint8_t data) { 39 | // TODO 40 | } 41 | 42 | void EEPROMDevice::WriteByte(uint8_t command, uint8_t value) { 43 | *((uint8_t*)(m_pEEPROM + command)) = value; 44 | } 45 | 46 | void EEPROMDevice::WriteWord(uint8_t command, uint16_t value) { 47 | *((uint16_t*)(m_pEEPROM + command)) = value; 48 | } 49 | 50 | void EEPROMDevice::WriteBlock(uint8_t command, uint8_t* data, int length) { 51 | memcpy(m_pEEPROM + command, data, length); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_init_dev_params.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_nondata.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Initialize Device Parameters command (0x91) [8.16]. 25 | */ 26 | class InitializeDeviceParameters : public NonDataProtocolCommand { 27 | public: 28 | InitializeDeviceParameters(ATADevice& device); 29 | virtual ~InitializeDeviceParameters() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | 33 | protected: 34 | bool ExecuteImpl() override; 35 | }; 36 | 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/ata.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "../basic/irq.h" 17 | #include "strikebox/io.h" 18 | #include "ata_defs.h" 19 | #include "ata_channel.h" 20 | 21 | namespace strikebox { 22 | namespace hw { 23 | namespace ata { 24 | 25 | class ATA : public IODevice { 26 | public: 27 | ATA(IRQHandler& irqHandler); 28 | virtual ~ATA(); 29 | void Reset(); 30 | 31 | bool MapIO(IOMapper *mapper); 32 | 33 | bool IORead(uint32_t port, uint32_t *value, uint8_t size) override; 34 | bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override; 35 | 36 | ATAChannel& GetChannel(Channel channel) { return *m_channels[channel]; } 37 | 38 | private: 39 | ATAChannel *m_channels[2]; 40 | }; 41 | 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_identify_device.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_pio_data_in.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Identify Device command (0xEC) [8.12]. 25 | */ 26 | class IdentifyDevice : public PIODataInProtocolCommand { 27 | public: 28 | IdentifyDevice(ATADevice& device); 29 | virtual ~IdentifyDevice() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | 33 | protected: 34 | bool HasMoreData() override; 35 | BlockReadResult ReadBlock(uint8_t data[kSectorSize]) override; 36 | }; 37 | 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/drvs/drv_vhd_dummy.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "drv_vhd_base.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | 22 | /*! 23 | * The dummy ATA device driver represents a basic hard drive that is filled with zeros. 24 | */ 25 | class DummyHardDriveATADeviceDriver : public BaseHardDriveATADeviceDriver { 26 | public: 27 | DummyHardDriveATADeviceDriver(); 28 | ~DummyHardDriveATADeviceDriver() override; 29 | 30 | // ----- Data access ------------------------------------------------------ 31 | 32 | bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override; 33 | bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override; 34 | }; 35 | 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_security_unlock.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_pio_data_out.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Security Unlock command (0xF2) [8.34]. 25 | */ 26 | class SecurityUnlock : public PIODataOutProtocolCommand { 27 | public: 28 | SecurityUnlock(ATADevice& device); 29 | virtual ~SecurityUnlock() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | 33 | protected: 34 | bool Initialize() override; 35 | BlockWriteResult ProcessBlock(uint8_t block[kSectorSize]) override; 36 | }; 37 | 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_identify_packet_device.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_pio_data_in.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Identify Packet Device command (0xA1) [8.13]. 25 | */ 26 | class IdentifyPacketDevice : public PIODataInProtocolCommand { 27 | public: 28 | IdentifyPacketDevice(ATADevice& device); 29 | virtual ~IdentifyPacketDevice() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | 33 | protected: 34 | bool HasMoreData() override; 35 | BlockReadResult ReadBlock(uint8_t data[kSectorSize]) override; 36 | }; 37 | 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/sm/adm1032.cpp: -------------------------------------------------------------------------------- 1 | // (C) Ivan "StrikerX3" Oliveira 2 | // 3 | // Datasheet: https://www.onsemi.com/pub/Collateral/ADM1032-D.PDF 4 | #include "strikebox/hw/sm/adm1032.h" 5 | 6 | namespace strikebox { 7 | 8 | ADM1032Device::~ADM1032Device() { 9 | } 10 | 11 | void ADM1032Device::Init() { 12 | } 13 | 14 | void ADM1032Device::Reset() { 15 | } 16 | 17 | void ADM1032Device::QuickCommand(bool read) { 18 | } 19 | 20 | uint8_t ADM1032Device::ReceiveByte() { 21 | return 0; 22 | } 23 | 24 | uint8_t ADM1032Device::ReadByte(uint8_t command) { 25 | switch (command) { 26 | case ADM1032RegLocalTemp: 27 | return 40; 28 | case ADM1032RegExtTempHigh: 29 | return 30; 30 | case ADM1032RegExtTempLow: 31 | return 0; 32 | default: 33 | return 0; 34 | } 35 | } 36 | 37 | uint16_t ADM1032Device::ReadWord(uint8_t command) { 38 | return ReadByte(command); 39 | } 40 | 41 | int ADM1032Device::ReadBlock(uint8_t command, uint8_t *data) { 42 | return 0; 43 | } 44 | 45 | void ADM1032Device::SendByte(uint8_t data) { 46 | } 47 | 48 | void ADM1032Device::WriteByte(uint8_t command, uint8_t value) { 49 | } 50 | 51 | void ADM1032Device::WriteWord(uint8_t command, uint16_t value) { 52 | } 53 | 54 | void ADM1032Device::WriteBlock(uint8_t command, uint8_t* data, int length) { 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /apps/cli/src/pch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is required by Visual Studio in order to compile pch.hpp. 3 | ------------------------------------------------------------------------------- 4 | MIT License 5 | 6 | Copyright (c) 2019 Ivan Roberto de Oliveira 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | #include "pch.hpp" 27 | -------------------------------------------------------------------------------- /apps/cli/src/pch.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Precompiled header for StrikeBox CLI. 3 | ------------------------------------------------------------------------------- 4 | MIT License 5 | 6 | Copyright (c) 2019 Ivan Roberto de Oliveira 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | #include 27 | #include 28 | 29 | #include "virt86/virt86.hpp" 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Ivan Roberto de Oliveira 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/drvs/drv_vdvd_dummy.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "drv_vdvd_base.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | 22 | /*! 23 | * This dummy ATA device driver represents a basic DVD drive that does not contain media. 24 | */ 25 | class DummyDVDDriveATADeviceDriver : public BaseDVDDriveATADeviceDriver { 26 | public: 27 | DummyDVDDriveATADeviceDriver(); 28 | ~DummyDVDDriveATADeviceDriver() override; 29 | 30 | // ----- Data access ------------------------------------------------------ 31 | 32 | bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override; 33 | 34 | // ----- Medium ----------------------------------------------------------- 35 | 36 | bool HasMedium() override { return false; } 37 | uint32_t GetMediumCapacitySectors() override { return 0; } 38 | }; 39 | 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/cmds/cmd_security_unlock.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/cmds/cmd_security_unlock.h" 13 | 14 | #include "strikebox/log.h" 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace ata { 19 | namespace cmd { 20 | 21 | SecurityUnlock::SecurityUnlock(ATADevice& device) 22 | : PIODataOutProtocolCommand(device) { 23 | } 24 | 25 | SecurityUnlock::~SecurityUnlock() { 26 | } 27 | 28 | bool SecurityUnlock::Initialize() { 29 | // [8.34.7] As a prerequisite, DRDY must be set equal to one 30 | if ((m_regs.status & StReady) == 0) { 31 | return false; 32 | } 33 | 34 | return true; 35 | } 36 | 37 | BlockWriteResult SecurityUnlock::ProcessBlock(uint8_t block[kSectorSize]) { 38 | Finish(); 39 | 40 | if (!m_driver->SecurityUnlock(block)) { 41 | return BlockWriteError; 42 | } 43 | 44 | return BlockWriteOK; 45 | } 46 | 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pramin.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRAMIN (RAMIN access) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PRAMIN contains a memory area reserved by the kernel used to describe GPU objects. 12 | // 13 | // PRAMIN engine registers occupy the range 0x700000..0x7FFFFF. 14 | #pragma once 15 | 16 | #include "../engine.h" 17 | 18 | namespace strikebox::nv2a { 19 | 20 | // NV2A RAMIN access engine (PRAMIN) 21 | class PRAMIN : public NV2AEngine { 22 | public: 23 | PRAMIN(NV2A& nv2a) : NV2AEngine("PRAMIN", 0x700000, 0x100000, nv2a) { 24 | m_mem = new uint8_t[m_length]; 25 | } 26 | 27 | ~PRAMIN() { 28 | delete[] m_mem; 29 | } 30 | 31 | void Reset() override; 32 | uint32_t Read(const uint32_t addr) override; 33 | void Write(const uint32_t addr, const uint32_t value) override; 34 | 35 | inline uint8_t* GetMemoryPointer(uint32_t address = 0) { 36 | if (address < m_length) { 37 | return &m_mem[address]; 38 | } 39 | return nullptr; 40 | } 41 | 42 | private: 43 | uint8_t* m_mem; 44 | }; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/bus/isabus.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Portions of the code are based on QEMU's ISA bus support. 3 | * The original copyright header is included below. 4 | */ 5 | /* 6 | * isa bus support for qdev. 7 | * 8 | * Copyright (c) 2009 Gerd Hoffmann 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 2 of the License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, see . 22 | */ 23 | #include "strikebox/hw/bus/isabus.h" 24 | 25 | #include "strikebox/log.h" 26 | 27 | namespace strikebox { 28 | 29 | ISABus::ISABus(IRQ *irqs) 30 | : m_irqs(irqs) 31 | { 32 | } 33 | 34 | ISABus::~ISABus() { 35 | } 36 | 37 | IRQ *ISABus::GetIRQ(uint8_t isaIRQ) { 38 | if (isaIRQ > 15) { 39 | log_warning("ISABus::GetIRQ: Invalid ISA IRQ %u\n", isaIRQ); 40 | return nullptr; 41 | } 42 | return &m_irqs[isaIRQ]; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pfb.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PFB (Memory interface) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PFB engine registers occupy the range 0x100000..0x100FFF. 12 | #pragma once 13 | 14 | #include "../engine.h" 15 | 16 | namespace strikebox::nv2a { 17 | 18 | // PFB registers 19 | const uint32_t Reg_PFB_CFG0 = 0x200; // [RW] Configuration register 0 20 | const uint32_t Reg_PFB_CSTATUS = 0x20C; // [R ] Framebuffer size 21 | const uint32_t Reg_PFB_WBC = 0x410; // [RW] Write-back cache? 22 | 23 | // ---------------------------------------------------------------------------- 24 | 25 | // NV2A memory interface engine (PFB) 26 | class PFB : public NV2AEngine { 27 | public: 28 | PFB(NV2A& nv2a) : NV2AEngine("PFB", 0x100000, 0x1000, nv2a) {} 29 | 30 | void SetEnabled(bool enabled); 31 | 32 | void Reset() override; 33 | uint32_t Read(const uint32_t addr) override; 34 | void Write(const uint32_t addr, const uint32_t value) override; 35 | 36 | private: 37 | bool m_enabled = false; 38 | uint32_t m_mem[0x1000 >> 2]; // for all other reads/writes 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /modules/core/cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | # Template for CMake Config module. 2 | # ------------------------------------------------------------------------------- 3 | # MIT License 4 | # 5 | # Copyright (c) 2019 Ivan Roberto de Oliveira 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | @PACKAGE_INIT@ 25 | 26 | include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") 27 | check_required_components("@PROJECT_NAME@") 28 | -------------------------------------------------------------------------------- /cmake/VSHelpers.cmake: -------------------------------------------------------------------------------- 1 | # Add Visual Studio filters to better organize the code 2 | function(vs_set_filters) 3 | cmake_parse_arguments(VS_SET_FILTERS "" "FILTER_ROOT;BASE_DIR" "SOURCES" ${ARGN}) 4 | if(MSVC) 5 | foreach(FILE IN ITEMS ${VS_SET_FILTERS_SOURCES}) 6 | # Get the directory of the source file 7 | get_filename_component(PARENT_DIR "${FILE}" DIRECTORY) 8 | 9 | # Remove common directory prefix to make the group 10 | if(BASE_DIR STREQUAL "") 11 | string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" GROUP "${PARENT_DIR}") 12 | else() 13 | string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/${VS_SET_FILTERS_BASE_DIR}" "" GROUP "${PARENT_DIR}") 14 | endif() 15 | 16 | # Use Windows path separators 17 | string(REPLACE "/" "\\" GROUP "${GROUP}") 18 | 19 | # Add to filter 20 | source_group("${VS_SET_FILTERS_FILTER_ROOT}${GROUP}" FILES "${FILE}") 21 | endforeach() 22 | endif() 23 | endfunction() 24 | 25 | # Make the Debug and RelWithDebInfo targets use Program Database for Edit and Continue for easier debugging 26 | function(vs_use_edit_and_continue) 27 | if(MSVC) 28 | string(REPLACE "/Zi" "/ZI" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") 29 | string(REPLACE "/Zi" "/ZI" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 30 | set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} PARENT_SCOPE) 31 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} PARENT_SCOPE) 32 | endif() 33 | endfunction() 34 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/cmd_set_features.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "proto_nondata.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Implements the Set Features command (0xEF) [8.37]. 25 | */ 26 | class SetFeatures : public NonDataProtocolCommand { 27 | public: 28 | SetFeatures(ATADevice& device); 29 | virtual ~SetFeatures() override; 30 | 31 | static IATACommand *Factory(DynamicVariant& sharedMemory, ATADevice& device) { return sharedMemory.Allocate(device); } 32 | 33 | protected: 34 | bool ExecuteImpl() override; 35 | 36 | private: 37 | // ----- Subcommands ------------------------------------------------------ 38 | 39 | bool SetTransferMode(); 40 | bool SetPIOTransferMode(PIOTransferType type, uint8_t mode); 41 | bool SetDMATransferMode(DMATransferType type, uint8_t mode); 42 | }; 43 | 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/prmdio.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRMDIO (VGA DAC registers) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/prmdio.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PRMDIO::Reset() { 17 | } 18 | 19 | uint32_t PRMDIO::Read(const uint32_t addr) { 20 | log_spew("[NV2A] PRMDIO::Read: Unimplemented read! address = 0x%x\n", addr); 21 | return 0; 22 | } 23 | 24 | void PRMDIO::Write(const uint32_t addr, const uint32_t value) { 25 | log_spew("[NV2A] PRMDIO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 26 | } 27 | 28 | uint32_t PRMDIO::ReadUnaligned(const uint32_t addr, const uint8_t size) { 29 | log_spew("[NV2A] PRMDIO::ReadUnaligned: Unimplemented unaligned read! address = 0x%x, size = %u\n", addr, size); 30 | return 0; 31 | } 32 | 33 | void PRMDIO::WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) { 34 | log_spew("[NV2A] PRMDIO::WriteUnaligned: Unimplemented unaligned write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pnvio.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PNVIO (VGA sequencer and graph controller registers) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pnvio.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PNVIO::Reset() { 17 | } 18 | 19 | uint32_t PNVIO::Read(const uint32_t addr) { 20 | log_spew("[NV2A] PNVIO::Read: Unimplemented read! address = 0x%x\n", addr); 21 | return 0; 22 | } 23 | 24 | void PNVIO::Write(const uint32_t addr, const uint32_t value) { 25 | log_spew("[NV2A] PNVIO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 26 | } 27 | 28 | uint32_t PNVIO::ReadUnaligned(const uint32_t addr, const uint8_t size) { 29 | log_spew("[NV2A] PNVIO::ReadUnaligned: Unimplemented unaligned read! address = 0x%x, size = %u\n", addr, size); 30 | return 0; 31 | } 32 | 33 | void PNVIO::WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) { 34 | log_spew("[NV2A] PNVIO::WriteUnaligned: Unimplemented unaligned write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/util/invoke_later.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace strikebox { 8 | 9 | /*! 10 | * Function to be fired when scheduled. 11 | */ 12 | typedef void (*InvokeLaterFunc)(void *userData); 13 | 14 | /*! 15 | * An object that invokes a function at a later point in time. 16 | * The object can be reused multiple times. 17 | */ 18 | class InvokeLater { 19 | public: 20 | InvokeLater(InvokeLaterFunc callback, void *userData); 21 | ~InvokeLater(); 22 | 23 | /*! 24 | * Starts the timer thread. 25 | */ 26 | void Start(); 27 | 28 | /*! 29 | * Stops the timer thread. 30 | */ 31 | void Stop(); 32 | 33 | /*! 34 | * Sets the timer to invoke at the specified expiration time. 35 | */ 36 | void Set(std::chrono::time_point& expiration); 37 | 38 | /*! 39 | * Cancels a pending invocation. 40 | */ 41 | void Cancel(); 42 | 43 | private: 44 | void Run(); 45 | 46 | bool m_primed; 47 | InvokeLaterFunc m_func; 48 | void *m_userData; 49 | 50 | std::thread *m_thread; 51 | std::mutex m_setupMutex; 52 | std::condition_variable m_setupCond; 53 | std::mutex m_mutex; 54 | std::condition_variable m_cond; 55 | std::chrono::time_point m_targetExpiration; 56 | 57 | bool m_running; 58 | 59 | friend void InvokeLaterThreadFunc(void *data); 60 | }; 61 | 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/prmcio.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRMCIO (VGA CRTC and attribute controller registers) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/prmcio.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PRMCIO::Reset() { 17 | } 18 | 19 | uint32_t PRMCIO::Read(const uint32_t addr) { 20 | log_spew("[NV2A] PRMCIO::Read: Unimplemented read! address = 0x%x\n", addr); 21 | return 0; 22 | } 23 | 24 | void PRMCIO::Write(const uint32_t addr, const uint32_t value) { 25 | log_spew("[NV2A] PRMCIO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 26 | } 27 | 28 | uint32_t PRMCIO::ReadUnaligned(const uint32_t addr, const uint8_t size) { 29 | log_spew("[NV2A] PRMCIO::ReadUnaligned: Unimplemented unaligned read! address = 0x%x, size = %u\n", addr, size); 30 | return 0; 31 | } 32 | 33 | void PRMCIO::WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) { 34 | log_spew("[NV2A] PRMCIO::WriteUnaligned: Unimplemented unaligned write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/sm/tvenc_conexant.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/sm/tvenc_conexant.h" 2 | 3 | namespace strikebox { 4 | 5 | // This is just a completely fake device that doesn't respond to anything. 6 | // Its mere presence is enough to satisfy the X-codes initialization process. 7 | 8 | TVEncConexantDevice::~TVEncConexantDevice() { 9 | } 10 | 11 | void TVEncConexantDevice::Init() { 12 | // TODO 13 | } 14 | 15 | void TVEncConexantDevice::Reset() { 16 | // TODO 17 | } 18 | 19 | void TVEncConexantDevice::QuickCommand(bool read) { 20 | // TODO 21 | } 22 | 23 | uint8_t TVEncConexantDevice::ReceiveByte() { 24 | return 0; // TODO 25 | } 26 | 27 | uint8_t TVEncConexantDevice::ReadByte(uint8_t command) { 28 | return *(m_registers + command); 29 | } 30 | 31 | uint16_t TVEncConexantDevice::ReadWord(uint8_t command) { 32 | return *((uint16_t*)(m_registers + command)); 33 | } 34 | 35 | int TVEncConexantDevice::ReadBlock(uint8_t command, uint8_t *data) { 36 | return 0; // TODO 37 | } 38 | 39 | void TVEncConexantDevice::SendByte(uint8_t data) { 40 | // TODO 41 | } 42 | 43 | void TVEncConexantDevice::WriteByte(uint8_t command, uint8_t value) { 44 | *((uint8_t*)(m_registers + command)) = value; 45 | } 46 | 47 | void TVEncConexantDevice::WriteWord(uint8_t command, uint16_t value) { 48 | *((uint16_t*)(m_registers + command)) = value; 49 | } 50 | 51 | void TVEncConexantDevice::WriteBlock(uint8_t command, uint8_t* data, int length) { 52 | memcpy(m_registers + command, data, length); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace strikebox { 8 | 9 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 10 | 11 | #define ALIGN_DOWN_SIZE(length, size) \ 12 | ((uint32_t)(length) & ~(size - 1)) 13 | 14 | #define ALIGN_UP_SIZE(length, size) \ 15 | (ALIGN_DOWN_SIZE(((uint32_t)(length) + size - 1), size)) 16 | 17 | 18 | struct ci_wchar_traits : public ::std::char_traits { 19 | static bool eq(wchar_t c1, wchar_t c2) { return ::std::toupper(c1) == ::std::toupper(c2); } 20 | static bool ne(wchar_t c1, wchar_t c2) { return ::std::toupper(c1) != ::std::toupper(c2); } 21 | static bool lt(wchar_t c1, wchar_t c2) { return ::std::toupper(c1) < ::std::toupper(c2); } 22 | static int compare(const wchar_t* s1, const wchar_t* s2, size_t n) { 23 | while (n-- != 0) { 24 | if (::std::toupper(*s1) < ::std::toupper(*s2)) return -1; 25 | if (::std::toupper(*s1) > ::std::toupper(*s2)) return 1; 26 | ++s1; ++s2; 27 | } 28 | return 0; 29 | } 30 | static const wchar_t* find(const wchar_t* s, int n, wchar_t a) { 31 | while (n-- > 0 && std::toupper(*s) != std::toupper(a)) { 32 | ++s; 33 | } 34 | return s; 35 | } 36 | }; 37 | 38 | typedef ::std::basic_string ci_wstring; 39 | 40 | inline bool ends_with(ci_wstring const &value, ci_wstring const &ending) { 41 | if (ending.size() > value.size()) return false; 42 | return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); 43 | } 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/proto_nondata.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "ata_command.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Base class for all commands based on the non-data protocol [9.9]. 25 | */ 26 | class NonDataProtocolCommand : public IATACommand { 27 | public: 28 | NonDataProtocolCommand(ATADevice& device); 29 | virtual ~NonDataProtocolCommand() override; 30 | 31 | // ----- Low-level operations --------------------------------------------- 32 | 33 | void Execute() override; 34 | void ReadData(uint8_t *value, uint32_t size) override; 35 | void WriteData(uint8_t *value, uint32_t size) override; 36 | 37 | protected: 38 | // ----- Protocol operations ---------------------------------------------- 39 | 40 | // Executes the command. 41 | // Return value indicates success (true) or failure (false). 42 | virtual bool ExecuteImpl() = 0; 43 | }; 44 | 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/status.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace strikebox { 4 | 5 | enum EmulatorStatus { 6 | EMUS_OK = 0, // Operation completed successfully 7 | 8 | EMUS_INIT_INVALID_REVISION, // An invalid hardware revision was specified 9 | 10 | EMUS_INIT_VM_INIT_FAILED, // Could not initialize virtual machine 11 | 12 | EMUS_INIT_ALLOC_RAM_FAILED, // Could not allocate memory for the guest RAM 13 | EMUS_INIT_ALLOC_RAM_RGN_FAILED, // Could not allocate memory for the RAM region 14 | 15 | EMUS_INIT_ALLOC_ROM_FAILED, // Could not allocate memory for the guest ROM 16 | EMUS_INIT_ALLOC_ROM_RGN_FAILED, // Could not allocate memory for the ROM region 17 | EMUS_INIT_MCPX_ROM_NOT_FOUND, // MCPX ROM file not found 18 | EMUS_INIT_MCPX_ROM_INVALID_SIZE, // MCPX ROM provided has incorrect size (must be 512 bytes) 19 | EMUS_INIT_BIOS_ROM_NOT_FOUND, // BIOS ROM file not found 20 | EMUS_INIT_BIOS_ROM_INVALID_SIZE, // BIOS ROM provided has incorrect size (must be 256 KiB or 1 MiB) 21 | 22 | EMUS_INIT_INVALID_HARD_DRIVE_TYPE, // An invalid hard drive type was specified 23 | EMUS_INIT_HARD_DRIVE_INIT_FAILED, // Virtual hard drive initialization failed 24 | EMUS_INIT_INVALID_DVD_DRIVE_TYPE, // An invalid DVD drive type was specified 25 | EMUS_INIT_DVD_DRIVE_INIT_FAILED, // Virtual DVD drive initialization failed 26 | 27 | EMUS_INIT_DEBUGGER_FAILED, // Debugger initialization failed 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pcounter.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PCOUNTER (Performance monitoring counters) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // [https://envytools.readthedocs.io/en/latest/hw/pcounter/intro.html] 12 | // "PCOUNTER is the card units that contains performance monitoring counters. 13 | // [...] 14 | // PCOUNTER is actually made of several identical hardware counter units, one for each so-called domain. 15 | // Each PCOUNTER domain can potentially run on a different source clock, allowing one to monitor events in various clock domains. 16 | // The PCOUNTER domains are mostly independent, but there's some limitted communication and shared circuitry among them." 17 | // 18 | // PCOUNTER engine registers occupy the range 0x00A000..0x00AFFF. 19 | #pragma once 20 | 21 | #include "../engine.h" 22 | 23 | namespace strikebox::nv2a { 24 | 25 | // NV2A performance monitoring counters engine (PCOUNTER) 26 | class PCOUNTER : public NV2AEngine { 27 | public: 28 | PCOUNTER(NV2A& nv2a) : NV2AEngine("PCOUNTER", 0x00A000, 0x1000, nv2a) {} 29 | 30 | void Reset() override; 31 | uint32_t Read(const uint32_t addr) override; 32 | void Write(const uint32_t addr, const uint32_t value) override; 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pvideo.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PVIDEO (Video overlay) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PVIDEO engine registers occupy the range 0x008000..0x008FFF. 12 | #pragma once 13 | 14 | #include "../engine.h" 15 | 16 | namespace strikebox::nv2a { 17 | 18 | // PVIDEO registers 19 | // [https://envytools.readthedocs.io/en/latest/hw/display/nv3/pvideo.html#mmio-registers] 20 | const uint32_t Reg_PVIDEO_INTR = 0x100; // [RW] Interrupt status 21 | const uint32_t Reg_PVIDEO_INTR_ENABLE = 0x140; // [RW] Interrupt enable 22 | 23 | // ---------------------------------------------------------------------------- 24 | 25 | // NV2A video overlay engine (PVIDEO) 26 | class PVIDEO : public NV2AEngine { 27 | public: 28 | PVIDEO(NV2A& nv2a) : NV2AEngine("PVIDEO", 0x008000, 0x1000, nv2a) {} 29 | 30 | void SetEnabled(bool enabled); 31 | 32 | void Reset() override; 33 | uint32_t Read(const uint32_t addr) override; 34 | void Write(const uint32_t addr, const uint32_t value) override; 35 | 36 | bool GetInterruptState() { return m_interruptLevels & m_enabledInterrupts; } 37 | 38 | private: 39 | bool m_enabled = false; 40 | 41 | uint32_t m_interruptLevels; 42 | uint32_t m_enabledInterrupts; 43 | }; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/cmds/proto_nondata.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/cmds/proto_nondata.h" 13 | 14 | #include "strikebox/log.h" 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace ata { 19 | namespace cmd { 20 | 21 | NonDataProtocolCommand::NonDataProtocolCommand(ATADevice& device) 22 | : IATACommand(device) { 23 | } 24 | 25 | NonDataProtocolCommand::~NonDataProtocolCommand() { 26 | } 27 | 28 | void NonDataProtocolCommand::Execute() { 29 | bool successful = ExecuteImpl(); 30 | 31 | if (!successful) { 32 | m_regs.status |= StError; 33 | } 34 | 35 | m_regs.status &= ~StBusy; 36 | m_interrupt.Assert(); 37 | 38 | Finish(); 39 | } 40 | 41 | void NonDataProtocolCommand::ReadData(uint8_t *value, uint32_t size) { 42 | // Should never happen 43 | log_warning("NonDataProtocolCommand::ReadData: Unexpected read!\n"); 44 | } 45 | 46 | void NonDataProtocolCommand::WriteData(uint8_t *value, uint32_t size) { 47 | // Should never happen 48 | log_warning("NonDataProtocolCommand::WriteData: Unexpected write!\n"); 49 | } 50 | 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /apps/cli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(strikebox-cli VERSION 1.0.0 LANGUAGES CXX) 2 | 3 | ############################## 4 | # Source files 5 | # 6 | file(GLOB_RECURSE sources 7 | src/*.cpp 8 | ) 9 | 10 | file(GLOB_RECURSE private_headers 11 | src/*.hpp 12 | src/*.h 13 | ) 14 | 15 | file(GLOB_RECURSE public_headers 16 | include/*.hpp 17 | include/*.h 18 | ) 19 | 20 | ############################## 21 | # Project structure 22 | # 23 | add_executable(strikebox-cli ${sources} ${private_headers} ${public_headers}) 24 | 25 | target_include_directories(strikebox-cli 26 | PUBLIC 27 | $ 28 | $ 29 | PRIVATE 30 | ${CMAKE_CURRENT_SOURCE_DIR}/src 31 | ) 32 | target_link_libraries(strikebox-cli strikebox-core) 33 | 34 | if(MSVC) 35 | add_precompiled_header(strikebox-cli pch.hpp SOURCE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/src/pch.cpp" FORCEINCLUDE) 36 | 37 | vs_set_filters(BASE_DIR src FILTER_ROOT "Sources" SOURCES ${sources}) 38 | vs_set_filters(BASE_DIR src FILTER_ROOT "Private Headers" SOURCES ${private_headers}) 39 | vs_set_filters(BASE_DIR include FILTER_ROOT "Public Headers" SOURCES ${public_headers}) 40 | 41 | vs_use_edit_and_continue() 42 | 43 | set_target_properties(strikebox-cli PROPERTIES FOLDER Applications) 44 | else() 45 | add_precompiled_header(strikebox-cli src/pch.hpp PCH_PATH pch.hpp SOURCE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/src/pch.cpp" FORCEINCLUDE) 46 | endif() 47 | 48 | ############################## 49 | # Installation 50 | # 51 | install(TARGETS strikebox-cli 52 | EXPORT platform-check 53 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 54 | ) 55 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pfb.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PFB (Memory interface) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pfb.h" 11 | #include "strikebox/hw/gpu/state.h" 12 | 13 | #include "strikebox/log.h" 14 | 15 | namespace strikebox::nv2a { 16 | 17 | void PFB::SetEnabled(bool enabled) { 18 | if (m_enabled != enabled) { 19 | m_enabled = enabled; 20 | if (enabled) { 21 | // TODO: start 22 | } 23 | else { 24 | Reset(); 25 | } 26 | } 27 | } 28 | 29 | void PFB::Reset() { 30 | std::fill(std::begin(m_mem), std::end(m_mem), 0); 31 | m_enabled = false; 32 | } 33 | 34 | uint32_t PFB::Read(const uint32_t addr) { 35 | switch (addr) { 36 | case Reg_PFB_CFG0: return 3; // The kernel asserts this value to be 3 early during initialization 37 | case Reg_PFB_CSTATUS: return m_nv2a.systemRAMSize; 38 | case Reg_PFB_WBC: return 0; 39 | default: 40 | //log_spew("[NV2A] PFB::Read: Unimplemented read! address = 0x%x\n", addr); 41 | return m_mem[addr >> 2]; 42 | } 43 | } 44 | 45 | void PFB::Write(const uint32_t addr, const uint32_t value) { 46 | //log_spew("[NV2A] PFB::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 47 | m_mem[addr >> 2] = value; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/ata_common.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "../ata/ata_defs.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | 22 | enum Channel { 23 | ChanPrimary, 24 | ChanSecondary, 25 | }; 26 | 27 | struct ATARegisters { 28 | uint8_t status = StReady; 29 | uint8_t error = 0; 30 | uint8_t features = 0; 31 | uint8_t sectorCount = 0; 32 | uint8_t sectorNumber = 0; 33 | uint16_t cylinder = 0; 34 | uint8_t deviceHead = 0; 35 | uint8_t control = 0; 36 | 37 | // ----- Utility functions ------------------------------------------------ 38 | 39 | // Retrieves the index of the currently selected device from bit 4 40 | // (DEV - Device select) of the Device/Head register [7.10.6] 41 | inline uint8_t GetSelectedDeviceIndex() const { return (deviceHead >> kDevSelectorBit) & 1; } 42 | 43 | inline bool AreInterruptsEnabled() const { return (control & DevCtlNegateInterruptEnable) == 0; } 44 | 45 | // ----- Signature and Persistence [9.1] ---------------------------------- 46 | 47 | void WriteSignature(bool packetFeatureSet); 48 | }; 49 | 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pcrtc.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PCRTC (CRTC controls) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // PCRTC engine registers occupy the range 0x600000..0x600FFF. 12 | #pragma once 13 | 14 | #include "../engine.h" 15 | 16 | namespace strikebox::nv2a { 17 | 18 | // PCRTC registers 19 | // [https://envytools.readthedocs.io/en/latest/hw/display/nv3/pcrtc.html#mmio-registers] 20 | const uint32_t Reg_PCRTC_INTR = 0x100; // [RW] Interrupt status 21 | const uint32_t Reg_PCRTC_INTR_ENABLE = 0x140; // [RW] Interrupt enable 22 | /**/const uint32_t Val_PCRTC_INTR_VBLANK = (1 << 0); // bit 0: Vertical blank 23 | 24 | // ---------------------------------------------------------------------------- 25 | 26 | // NV2A CRTC controls engine (PCRTC) 27 | class PCRTC : public NV2AEngine { 28 | public: 29 | PCRTC(NV2A& nv2a) : NV2AEngine("PCRTC", 0x600000, 0x1000, nv2a) {} 30 | 31 | void SetEnabled(bool enabled); 32 | 33 | void Reset() override; 34 | uint32_t Read(const uint32_t addr) override; 35 | void Write(const uint32_t addr, const uint32_t value) override; 36 | 37 | bool GetInterruptState() { return m_interruptLevels & m_enabledInterrupts; } 38 | 39 | private: 40 | bool m_enabled = false; 41 | 42 | uint32_t m_interruptLevels; 43 | uint32_t m_enabledInterrupts; 44 | }; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/drvs/drv_vhd_image.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "drv_vhd_base.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | 22 | /*! 23 | * A virtual hard disk ATA device driver based on an image file. 24 | * 25 | * It can read/write directly to the image file or use write-on-copy, in which 26 | * case all writes done on a temporary file and subsequent reads to overwritten 27 | * sectors are redirected to the temporary file. 28 | */ 29 | class ImageHardDriveATADeviceDriver : public BaseHardDriveATADeviceDriver { 30 | public: 31 | ImageHardDriveATADeviceDriver(); 32 | ~ImageHardDriveATADeviceDriver() override; 33 | 34 | // ----- Virtual hard disk image initialization --------------------------- 35 | 36 | bool LoadImageFile(const char *imagePath, bool copyOnWrite); 37 | 38 | // ----- Data access ------------------------------------------------------ 39 | 40 | bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override; 41 | bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override; 42 | 43 | private: 44 | FILE *m_fpImage = NULL; 45 | bool m_copyOnWrite; 46 | }; 47 | 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/pci/lpc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../defs.h" 6 | #include "pci.h" 7 | #include "pci_irq.h" 8 | #include "../basic/irq.h" 9 | #include "../bus/isabus.h" 10 | 11 | namespace strikebox { 12 | 13 | #define XBOX_NUM_INT_IRQS 8 14 | #define XBOX_NUM_PIRQS 4 15 | 16 | #define XBOX_NUM_PIC_IRQS 16 17 | 18 | #define XBOX_LPC_ACPI_IRQ_ROUT 0x64 19 | #define XBOX_LPC_PIRQ_ROUT 0x68 20 | #define XBOX_LPC_INT_IRQ_ROUT 0x6C 21 | 22 | class LPCDevice : public PCIDevice, public IRQHandler { 23 | public: 24 | // constructor 25 | LPCDevice(IRQ *irqs, uint8_t *rom, uint8_t *bios, uint32_t biosSize, uint8_t *mcpxROM, bool initMcpxROM); 26 | virtual ~LPCDevice(); 27 | 28 | void HandleIRQ(uint8_t irqNum, bool level) override; 29 | inline ISABus *GetISABus() { return m_isaBus; } 30 | 31 | // PCI Device functions 32 | void Init(); 33 | void Reset(); 34 | 35 | void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override; 36 | void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override; 37 | 38 | void WriteConfig(uint32_t reg, uint32_t value, uint8_t size) override; 39 | 40 | private: 41 | int m_field_pin = 0; 42 | IRQ *m_irqs; 43 | ISABus *m_isaBus; 44 | 45 | uint8_t *m_rom; 46 | uint8_t *m_bios; 47 | uint32_t m_biosSize; 48 | uint8_t *m_mcpxROM; 49 | bool m_initMcpxROM; 50 | 51 | friend class LPCIRQMapper; 52 | }; 53 | 54 | class LPCIRQMapper : public IRQMapper { 55 | public: 56 | LPCIRQMapper(LPCDevice *lpc); 57 | 58 | uint8_t MapIRQ(PCIDevice *dev, uint8_t irqNum) override; 59 | bool CanSetIRQ() override; 60 | void SetIRQ(uint8_t irqNum, int level) override; 61 | private: 62 | LPCDevice *m_lpc; 63 | }; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pbus.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PBUS (Bus control) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // [https://envytools.readthedocs.io/en/latest/hw/bus/pbus.html] 12 | // "PBUS is present on all nvidia cards. 13 | // In theory, it deals with "bus control". In practice, it accumulates all sort of junk nobody bothered to create a special area for. 14 | // It is unaffected by any PMC.ENABLE bits." 15 | // 16 | // PBUS engine registers occupy the range 0x001000..0x001FFF. 17 | #pragma once 18 | 19 | #include "../engine.h" 20 | 21 | namespace strikebox::nv2a { 22 | 23 | // PBUS registers 24 | // [https://envytools.readthedocs.io/en/latest/hw/bus/pbus.html#mmio-registers] 25 | const uint32_t Reg_PBUS_INTR = 0x100; // [RW] Interrupt status 26 | const uint32_t Reg_PBUS_INTR_ENABLE = 0x140; // [RW] Interrupt enable 27 | 28 | // ---------------------------------------------------------------------------- 29 | 30 | // NV2A bus control engine (PBUS) 31 | class PBUS : public NV2AEngine { 32 | public: 33 | PBUS(NV2A& nv2a) : NV2AEngine("PBUS", 0x001000, 0x1000, nv2a) {} 34 | 35 | void Reset() override; 36 | uint32_t Read(const uint32_t addr) override; 37 | void Write(const uint32_t addr, const uint32_t value) override; 38 | 39 | bool GetInterruptState() { return m_interruptLevels & m_enabledInterrupts; } 40 | 41 | private: 42 | uint32_t m_interruptLevels; 43 | uint32_t m_enabledInterrupts; 44 | }; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/util/fifo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "strikebox/log.h" 6 | 7 | namespace strikebox { 8 | 9 | template 10 | class Fifo { 11 | public: 12 | Fifo(uint32_t capacity); 13 | ~Fifo(); 14 | 15 | bool Push(T data); 16 | bool Pop(T *data); 17 | bool Discard(); 18 | 19 | inline void Clear() { m_num = 0; } 20 | inline uint32_t Count() const { return m_num; } 21 | 22 | inline bool IsEmpty() const { return m_num == 0; } 23 | inline bool IsFull() const { return m_num == m_capacity; } 24 | private: 25 | T *m_data; 26 | uint32_t m_capacity; 27 | uint32_t m_head; 28 | uint32_t m_num; 29 | }; 30 | 31 | template 32 | Fifo::Fifo(uint32_t capacity) { 33 | m_data = new T[capacity]; 34 | m_capacity = capacity; 35 | m_head = 0; 36 | m_num = 0; 37 | } 38 | 39 | template 40 | Fifo::~Fifo() { 41 | delete[] m_data; 42 | } 43 | 44 | template 45 | bool Fifo::Push(T data) { 46 | if (m_num == m_capacity) { 47 | log_debug("Fifo::Push: Queue full!\n"); 48 | return false; 49 | } 50 | m_data[(m_head + m_num) % m_capacity] = data; 51 | m_num++; 52 | return true; 53 | } 54 | 55 | template 56 | bool Fifo::Pop(T *data) { 57 | if (m_num == 0) { 58 | log_debug("Fifo::Pop: Queue empty!\n"); 59 | return false; 60 | } 61 | *data = m_data[m_head++]; 62 | m_head %= m_capacity; 63 | m_num--; 64 | return true; 65 | } 66 | 67 | template 68 | bool Fifo::Discard() { 69 | if (m_num == 0) { 70 | log_debug("Fifo::Discard: Queue empty!\n"); 71 | return false; 72 | } 73 | m_head = (m_head + 1) % m_capacity; 74 | m_num--; 75 | return true; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/atapi/cmds/atapi_command.cpp: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #include "strikebox/hw/atapi/cmds/atapi_command.h" 30 | 31 | #include "strikebox/log.h" 32 | 33 | namespace strikebox { 34 | namespace hw { 35 | namespace atapi { 36 | namespace cmd { 37 | 38 | IATAPICommand::IATAPICommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) 39 | : m_packetCmdState(packetCmdState) 40 | , m_driver(driver) 41 | { 42 | } 43 | 44 | IATAPICommand::~IATAPICommand() { 45 | } 46 | 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/atapi/cmds/proto_nondata.cpp: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #include "strikebox/hw/atapi/cmds/proto_nondata.h" 30 | 31 | #include "strikebox/log.h" 32 | 33 | namespace strikebox { 34 | namespace hw { 35 | namespace atapi { 36 | namespace cmd { 37 | 38 | ATAPINonDataCommand::ATAPINonDataCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) 39 | : IATAPICommand(packetCmdState, driver) 40 | { 41 | } 42 | 43 | ATAPINonDataCommand::~ATAPINonDataCommand() { 44 | } 45 | 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/bus/pcibus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../pci/pci_irq.h" 4 | #include "../pci/pci.h" 5 | #include "strikebox/io.h" 6 | 7 | #include 8 | 9 | namespace strikebox { 10 | 11 | #define PORT_PCI_CONFIG_ADDRESS 0xCF8 12 | #define PORT_PCI_CONFIG_DATA 0xCFC 13 | #define PCI_CONFIG_REGISTER_MASK 0xFC 14 | 15 | class PCIBus : public IODevice { 16 | public: 17 | PCIBus(); 18 | virtual ~PCIBus(); 19 | bool MapIO(IOMapper *mapper); 20 | 21 | void ConnectDevice(uint32_t deviceId, PCIDevice *pDevice); 22 | 23 | bool IORead(uint32_t port, uint32_t *value, uint8_t size) override; 24 | bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override; 25 | 26 | bool MMIORead(uint32_t addr, uint32_t *value, uint8_t size) override; 27 | bool MMIOWrite(uint32_t addr, uint32_t value, uint8_t size) override; 28 | 29 | void Reset(); 30 | 31 | void ConfigureIRQs(IRQMapper *irqMapper, uint8_t numIRQs); 32 | 33 | inline uint8_t MapIRQ(PCIDevice *dev, uint8_t irqNum) { return m_irqMapper->MapIRQ(dev, irqNum); } 34 | inline bool CanSetIRQ() { return m_irqMapper->CanSetIRQ(); } 35 | inline void SetIRQ(uint8_t irqNum, int level) { return m_irqMapper->SetIRQ(irqNum, level); } 36 | 37 | private: 38 | friend class PCIDevice; 39 | friend class PCIBridgeDevice; 40 | 41 | PCIDevice *m_owner; // The bridge that owns this bus 42 | std::map m_Devices; 43 | PCIConfigAddressRegister m_configAddressRegister; 44 | 45 | uint8_t m_numIRQs; 46 | uint32_t *m_irqCount; 47 | IRQMapper *m_irqMapper; 48 | 49 | void IOWriteConfigAddress(uint32_t pData); 50 | void IOWriteConfigData(uint32_t pData, uint8_t size, uint8_t regOffset); 51 | uint32_t IOReadConfigData(uint8_t size, uint8_t regOffset); 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engine.h: -------------------------------------------------------------------------------- 1 | // Abstract base class for NV2A engines 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #pragma once 11 | 12 | #include 13 | #include 14 | 15 | #include "defs.h" 16 | 17 | namespace strikebox::nv2a { 18 | 19 | class NV2A; 20 | 21 | // Abstract base class of all NV2A engines. 22 | class NV2AEngine { 23 | public: 24 | NV2AEngine(const std::string name, const uint32_t offset, const uint32_t length, NV2A& nv2a) 25 | : m_name(name) 26 | , m_offset(offset) 27 | , m_length(length) 28 | , m_offsetEnd(offset + length) 29 | , m_nv2a(nv2a) 30 | {} 31 | 32 | virtual void Reset() = 0; 33 | virtual uint32_t Read(const uint32_t addr) = 0; 34 | virtual void Write(const uint32_t addr, const uint32_t value) = 0; 35 | 36 | virtual uint32_t ReadUnaligned(const uint32_t addr, const uint8_t size); 37 | virtual void WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size); 38 | 39 | const std::string GetName() const noexcept { return m_name; } 40 | const uint32_t GetOffset() const noexcept { return m_offset; } 41 | const uint32_t GetLength() const noexcept { return m_length; } 42 | 43 | const bool Contains(uint32_t address) const noexcept { return address >= m_offset && address < m_offsetEnd; } 44 | 45 | protected: 46 | NV2A& m_nv2a; 47 | 48 | const std::string m_name; 49 | const uint32_t m_offset; 50 | const uint32_t m_length; 51 | const uint32_t m_offsetEnd; // m_offset + m_length, precomputed for speed 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/engines/pstraps.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PSTRAPS (Straps readout) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // [https://envytools.readthedocs.io/en/latest/hw/io/pstraps.html] 12 | // "The nvidia GPU chips are used in multiple cards from multiple manufacturers. 13 | // Thus, the a single GPU can end up in many different configurations, with varying memory amount, memory type, bus type, 14 | // TV norm, crystal frequency, and many other parameters. Since the GPU often needs to know what configuration it is used in, 15 | // a "straps" mechanism was invented to tell it this information. 16 | // On the first few cycles after reset, the memory bus pins are sampled. Since nothing else is driving them at that point, 17 | // their logic state is decided by the pull-up or pull-down resistors placed by board manufacturer. 18 | // The value this read is used as the "straps" value and is used to configure many aspects of GPU operation. 19 | // Some of the straps are not used by the GPU itself, but are intended for use by the BIOS or the driver." 20 | // 21 | // PSTRAPS engine registers occupy the range 0x101000..0x101FFF. 22 | #pragma once 23 | 24 | #include "../engine.h" 25 | 26 | namespace strikebox::nv2a { 27 | 28 | // NV2A straps readout engine (PSTRAPS) 29 | class PSTRAPS : public NV2AEngine { 30 | public: 31 | PSTRAPS(NV2A& nv2a) : NV2AEngine("PSTRAPS", 0x101000, 0x1000, nv2a) {} 32 | 33 | void Reset() override; 34 | uint32_t Read(const uint32_t addr) override; 35 | void Write(const uint32_t addr, const uint32_t value) override; 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pcrtc.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PCRTC (CRTC controls) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pcrtc.h" 11 | #include "strikebox/hw/gpu/state.h" 12 | 13 | #include "strikebox/log.h" 14 | 15 | namespace strikebox::nv2a { 16 | 17 | void PCRTC::SetEnabled(bool enabled) { 18 | if (m_enabled != enabled) { 19 | m_enabled = enabled; 20 | if (enabled) { 21 | // TODO: start 22 | } 23 | else { 24 | Reset(); 25 | } 26 | } 27 | } 28 | 29 | void PCRTC::Reset() { 30 | m_enabled = false; 31 | m_interruptLevels = 0; 32 | m_enabledInterrupts = 0; 33 | } 34 | 35 | uint32_t PCRTC::Read(const uint32_t addr) { 36 | switch (addr) { 37 | case Reg_PCRTC_INTR: return m_interruptLevels; 38 | case Reg_PCRTC_INTR_ENABLE: return m_enabledInterrupts; 39 | default: 40 | log_spew("[NV2A] PCRTC::Read: Unimplemented read! address = 0x%x\n", addr); 41 | return 0; 42 | } 43 | } 44 | 45 | void PCRTC::Write(const uint32_t addr, const uint32_t value) { 46 | switch (addr) { 47 | case Reg_PCRTC_INTR: 48 | // Clear specified interrupts 49 | m_interruptLevels &= ~value; 50 | m_nv2a.UpdateIRQ(); 51 | break; 52 | case Reg_PCRTC_INTR_ENABLE: 53 | m_enabledInterrupts = value; 54 | m_nv2a.UpdateIRQ(); 55 | break; 56 | default: 57 | log_spew("[NV2A] PCRTC::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 58 | break; 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pvideo.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PVIDEO (Video overlay) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pvideo.h" 11 | #include "strikebox/hw/gpu/state.h" 12 | 13 | #include "strikebox/log.h" 14 | 15 | namespace strikebox::nv2a { 16 | 17 | void PVIDEO::SetEnabled(bool enabled) { 18 | if (m_enabled != enabled) { 19 | m_enabled = enabled; 20 | if (enabled) { 21 | // TODO: start 22 | } 23 | else { 24 | Reset(); 25 | } 26 | } 27 | } 28 | 29 | void PVIDEO::Reset() { 30 | m_enabled = false; 31 | m_interruptLevels = 0; 32 | m_enabledInterrupts = 0; 33 | } 34 | 35 | uint32_t PVIDEO::Read(const uint32_t addr) { 36 | switch (addr) { 37 | case Reg_PVIDEO_INTR: return m_interruptLevels; 38 | case Reg_PVIDEO_INTR_ENABLE: return m_enabledInterrupts; 39 | default: 40 | log_spew("[NV2A] PVIDEO::Read: Unimplemented read! address = 0x%x\n", addr); 41 | return 0; 42 | } 43 | } 44 | 45 | void PVIDEO::Write(const uint32_t addr, const uint32_t value) { 46 | switch (addr) { 47 | case Reg_PVIDEO_INTR: 48 | // Clear specified interrupts 49 | m_interruptLevels &= ~value; 50 | m_nv2a.UpdateIRQ(); 51 | break; 52 | case Reg_PVIDEO_INTR_ENABLE: 53 | m_enabledInterrupts = value; 54 | m_nv2a.UpdateIRQ(); 55 | break; 56 | default: 57 | log_spew("[NV2A] PVIDEO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 58 | break; 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/drvs/drv_vdvd_image.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "drv_vdvd_base.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | 22 | /*! 23 | * A virtual DVD ATA device driver based on an image file. 24 | * 25 | * It can read/write directly to the image file or use write-on-copy, in which 26 | * case all writes done on a temporary file and subsequent reads to overwritten 27 | * sectors are redirected to the temporary file. 28 | */ 29 | class ImageDVDDriveATADeviceDriver : public BaseDVDDriveATADeviceDriver { 30 | public: 31 | ImageDVDDriveATADeviceDriver(); 32 | ~ImageDVDDriveATADeviceDriver() override; 33 | 34 | // ----- Virtual DVD image management ------------------------------------- 35 | 36 | bool LoadImageFile(const char *imagePath, bool copyOnWrite); 37 | bool EjectMedium(); 38 | 39 | // ----- Data access ------------------------------------------------------ 40 | 41 | bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override; 42 | 43 | // ----- Medium ----------------------------------------------------------- 44 | 45 | bool HasMedium() override { return m_fpImage != NULL; } 46 | uint32_t GetMediumCapacitySectors() override { return m_sectorCapacity; } 47 | 48 | private: 49 | FILE *m_fpImage = NULL; 50 | bool m_copyOnWrite; 51 | 52 | uint64_t m_sectorCapacity; 53 | }; 54 | 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/superio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "serial.h" 6 | 7 | namespace strikebox { 8 | 9 | #define PORT_SUPERIO_CONFIG 0x2E 10 | #define PORT_SUPERIO_DATA 0x2F 11 | 12 | #define PORT_SUPERIO_BASE PORT_SUPERIO_CONFIG 13 | #define PORT_SUPERIO_COUNT 2 14 | 15 | #define SUPERIO_SERIAL_PORT_COUNT 2 16 | 17 | 18 | #define DEVICE_FDD 0x0 19 | #define DEVICE_PARALLEL_PORT 0x3 20 | #define DEVICE_SERIAL_PORT_1 0x4 21 | #define DEVICE_SERIAL_PORT_2 0x5 22 | #define DEVICE_KEYBOARD 0x7 23 | #define DEVICE_GAME_PORT 0x9 24 | #define DEVICE_PME 0xA 25 | #define DEVICE_MPU_401 0xB 26 | #define MAX_DEVICE 0xC 27 | 28 | #define ENTER_CONFIG_KEY 0x55 29 | #define EXIT_CONFIG_KEY 0xAA 30 | 31 | #define MAX_CONFIG_REG 0x30 32 | #define MAX_DEVICE_REGS 0xFF 33 | 34 | #define CONFIG_DEVICE_NUMBER 0x07 35 | #define CONFIG_PORT_LOW 0x26 36 | #define CONFIG_PORT_HIGH 0x27 37 | 38 | #define CONFIG_DEVICE_ACTIVATE 0x30 39 | #define CONFIG_DEVICE_BASE_ADDRESS_HIGH 0x60 40 | #define CONFIG_DEVICE_BASE_ADDRESS_LOW 0x61 41 | #define CONFIG_DEVICE_INTERRUPT 0x70 42 | 43 | class SuperIO : public IODevice { 44 | public: 45 | SuperIO(IRQHandler& irqHandler, CharDriver *chrs[SUPERIO_SERIAL_PORT_COUNT]); 46 | virtual ~SuperIO(); 47 | 48 | void Init(); 49 | void Reset(); 50 | 51 | bool MapIO(IOMapper *mapper); 52 | 53 | bool IORead(uint32_t port, uint32_t *value, uint8_t size) override; 54 | bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override; 55 | 56 | private: 57 | void UpdateDevices(); 58 | 59 | bool m_inConfigMode; 60 | uint32_t m_selectedReg; 61 | 62 | uint8_t m_configRegs[MAX_CONFIG_REG]; 63 | uint8_t m_deviceRegs[MAX_DEVICE][MAX_DEVICE_REGS]; 64 | 65 | Serial *m_serialPorts[SUPERIO_SERIAL_PORT_COUNT]; 66 | }; 67 | 68 | } 69 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pramdac.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PRAMDAC (RAMDAC, video overlay, cursor, and PLL control) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pramdac.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | void PRAMDAC::Reset() { 17 | // Default NV2A clocks: 18 | // crystal = 16.6 MHz 19 | // core = 233 MHz 20 | // memory = 200 MHz 21 | // video = 25.160 MHz 22 | m_coreClockCoeff = ClockCoefficients{ 1, 28, 1 }; 23 | m_memoryClockCoeff = ClockCoefficients{ 1, 24, 1 }; 24 | m_videoClockCoeff = ClockCoefficients{ 3, 157, 13 }; 25 | 26 | std::fill(std::begin(m_mem), std::end(m_mem), 0); 27 | } 28 | 29 | uint32_t PRAMDAC::Read(const uint32_t addr) { 30 | switch (addr) { 31 | case Reg_RAMDAC_NVPLL: return m_coreClockCoeff.u32; 32 | case Reg_RAMDAC_MPLL: return m_memoryClockCoeff.u32; 33 | case Reg_RAMDAC_VPLL: return m_videoClockCoeff.u32; 34 | default: 35 | log_spew("[NV2A] PRAMDAC::Read: Unimplemented read! address = 0x%x\n", addr); 36 | return m_mem[addr >> 2]; 37 | } 38 | } 39 | 40 | void PRAMDAC::Write(const uint32_t addr, const uint32_t value) { 41 | switch (addr) { 42 | case Reg_RAMDAC_NVPLL: m_coreClockCoeff.u32 = value; break; 43 | case Reg_RAMDAC_MPLL: m_memoryClockCoeff.u32 = value; break; 44 | case Reg_RAMDAC_VPLL: m_videoClockCoeff.u32 = value; break; 45 | default: 46 | log_spew("[NV2A] PRAMDAC::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 47 | m_mem[addr >> 2] = value; 48 | break; 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/pci/agpbridge.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/pci/agpbridge.h" 2 | 3 | #include "strikebox/log.h" 4 | 5 | namespace strikebox { 6 | 7 | AGPBridgeDevice::AGPBridgeDevice() 8 | : PCIBridgeDevice(PCI_VENDOR_ID_NVIDIA, 0x01B7, 0xA1) 9 | { 10 | } 11 | 12 | AGPBridgeDevice::~AGPBridgeDevice() { 13 | } 14 | 15 | // PCI Device functions 16 | 17 | void AGPBridgeDevice::Init() { 18 | Write16(m_configSpace, PCI_PREF_MEMORY_BASE, PCI_PREF_RANGE_TYPE_32); 19 | Write16(m_configSpace, PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_32); 20 | PCIBridgeDevice::Init(); 21 | 22 | // Initialize configuration space 23 | Write16(m_configSpace, PCI_STATUS, PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); 24 | Write16(m_configSpace, PCI_SEC_STATUS, PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); 25 | Write8(m_configSpace, PCI_MIN_GNT, 0x80); 26 | Write8(m_configSpace, PCI_MAX_LAT, 0x00); 27 | Write8(m_configSpace, PCI_IO_BASE, 0xf0); 28 | Write8(m_configSpace, PCI_IO_LIMIT, 0x0); 29 | Write16(m_configSpace, PCI_MEMORY_BASE, 0xfd00); 30 | Write16(m_configSpace, PCI_MEMORY_LIMIT, 0xfe70); 31 | Write16(m_configSpace, PCI_PREF_MEMORY_BASE, 0xf000); 32 | Write16(m_configSpace, PCI_PREF_MEMORY_LIMIT, 0xf3f0); 33 | Write32(m_configSpace, PCI_PREF_BASE_UPPER32, 0xff3fbfff); 34 | Write32(m_configSpace, PCI_PREF_LIMIT_UPPER32, 0xafff7fff); 35 | Write16(m_configSpace, PCI_IO_BASE_UPPER16, 0xf5fd); 36 | Write16(m_configSpace, PCI_IO_LIMIT_UPPER16, 0x3eff); 37 | Write8(m_configSpace, PCI_CAPABILITY_LIST, 0x0); 38 | 39 | // Unknown registers 40 | Write16(m_configSpace, 0x44, 0x0); 41 | Write16(m_configSpace, 0x46, 0x8000); 42 | Write16(m_configSpace, 0x48, 0x14); 43 | Write16(m_configSpace, 0x4c, 0x1); 44 | Write16(m_configSpace, 0x50, 0x0); 45 | Write32(m_configSpace, 0x54, 0x10000000); 46 | for (uint8_t i = 0; i < 0x100 - 0x58; i += 4) { 47 | Write32(m_configSpace, 0x58 + i, 0xffffffff); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/drvs/drv_vhd_dummy.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/drvs/drv_vhd_dummy.h" 13 | 14 | #include "strikebox/log.h" 15 | #include "strikebox/io.h" 16 | 17 | namespace strikebox { 18 | namespace hw { 19 | namespace ata { 20 | 21 | static void padString(uint8_t *dest, const char *src, uint32_t length) { 22 | for (uint32_t i = 0; i < length; i++) { 23 | if (*src) { 24 | dest[i ^ 1] = *src++; 25 | } 26 | else { 27 | dest[i ^ 1] = ' '; 28 | } 29 | } 30 | } 31 | 32 | DummyHardDriveATADeviceDriver::DummyHardDriveATADeviceDriver() { 33 | strcpy(m_serialNumber, "0123456789"); 34 | strcpy(m_firmwareRevision, "1.0.0"); 35 | strcpy(m_modelNumber, "SBx DHDD0010000"); 36 | 37 | // Initialize with parameters for a 10 GiB hard drive 38 | m_numCylinders = 20480; 39 | m_numHeadsPerCylinder = 16; 40 | m_numSectorsPerTrack = 63; 41 | m_sectorCapacity = m_numCylinders * m_numHeadsPerCylinder * m_numSectorsPerTrack; 42 | } 43 | 44 | DummyHardDriveATADeviceDriver::~DummyHardDriveATADeviceDriver() { 45 | } 46 | 47 | bool DummyHardDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) { 48 | // Fill with zeros, as if the disk was blank 49 | memset(buffer, 0, size); 50 | 51 | // Always succeed 52 | return true; 53 | } 54 | 55 | bool DummyHardDriveATADeviceDriver::Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) { 56 | // Lie about writing, always succeed 57 | return true; 58 | } 59 | 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engine.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PBUS (Bus control) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/state.h" 11 | 12 | #include "strikebox/log.h" 13 | 14 | namespace strikebox::nv2a { 15 | 16 | uint32_t NV2AEngine::ReadUnaligned(const uint32_t addr, const uint8_t size) { 17 | // Unaligned read fits in one register 18 | if ((addr & ~3) == ((addr + size - 1) & ~3)) { 19 | log_warning("NV2AEngine::Read: Unaligned read! address = 0x%x, size = %u\n", addr + m_offset, size); 20 | uint8_t offset = (addr & 3) * 8; 21 | uint32_t mask = 0xFFFFFFFF >> (32 - size * 8); 22 | return (Read(addr & ~3) >> offset) & mask; 23 | } 24 | 25 | // Unaligned read spans two registers, corresponding to one of these cases: 26 | // - 16-bit read from offset 3 27 | // - 32-bit read from offsets 1, 2 or 3 28 | // FIXME: how does the real hardware behave in this case? 29 | log_warning("NV2AEngine::Read: Severely unaligned read! address = 0x%x, size = %u\n", addr + m_offset, size); 30 | 31 | uint32_t value1 = Read(addr & ~3); 32 | uint32_t value2 = Read((addr & ~3) + 4); 33 | 34 | uint8_t offset = (addr & 3) * 8; 35 | uint32_t mask = 0xFFFFFFFF >> (32 - size * 8); 36 | return ((value1 >> offset) | (value2 << (32 - offset))) & mask; 37 | } 38 | 39 | void NV2AEngine::WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) { 40 | log_warning("NV2AEngine::Write: Unaligned write! address = 0x%x, size = %u\n", addr + m_offset, size); 41 | // FIXME: how does the real hardware behave in this case? 42 | // This is almost certainly wrong. 43 | Write(addr & ~3, value); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/atapi/cmds/cmd_test_unit_ready.h: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #pragma once 30 | 31 | #include 32 | 33 | #include "proto_nondata.h" 34 | 35 | namespace strikebox { 36 | namespace hw { 37 | namespace atapi { 38 | namespace cmd { 39 | 40 | /*! 41 | * Implements the TEST UNIT READY command (0x00) [p 6.33]. 42 | */ 43 | class TestUnitReady : public ATAPINonDataCommand { 44 | public: 45 | TestUnitReady(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver); 46 | virtual ~TestUnitReady(); 47 | 48 | bool Prepare() override; 49 | bool Execute() override; 50 | 51 | static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new TestUnitReady(packetCmdState, driver); } 52 | }; 53 | 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/proto_dma.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "ata_command.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Base class for all commands based on the DMA protocol [9.10]. 25 | */ 26 | class DMAProtocolCommand : public IATACommand { 27 | public: 28 | DMAProtocolCommand(ATADevice& device, bool isWrite); 29 | virtual ~DMAProtocolCommand() override; 30 | 31 | // ----- Low-level operations --------------------------------------------- 32 | 33 | void Execute() override; 34 | void ReadData(uint8_t *value, uint32_t size) override; 35 | void WriteData(uint8_t *value, uint32_t size) override; 36 | 37 | protected: 38 | // ----- Protocol operations ---------------------------------------------- 39 | 40 | // Invoked when the DMA transfer finishes. Updates registers and marks the 41 | // command as finished. 42 | void FinishTransfer(); 43 | 44 | // Invoked when an unrecoverable error occurred. Updates registers and 45 | // marks the command as finished. 46 | void UnrecoverableError(); 47 | 48 | // ----- Parameters ------------------------------------------------------- 49 | 50 | // Range of operation 51 | uint64_t m_startingByte; // Inclusive 52 | uint64_t m_endingByte; // Exclusive 53 | 54 | uint64_t m_currentByte; 55 | 56 | // DMA operation type (true = write, false = read), used for sanity check. 57 | // Specified in the constructor. 58 | bool m_isWrite; 59 | }; 60 | 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/gpu/nv2a.h: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | // 11 | // NV2A is a custom GPU designed by Nvidia for the Original Xbox. Internally, 12 | // the chip is split up into different engines that are mapped to distinct 13 | // regions of the system memory allocated to the device: 14 | // 15 | // Engine Offset Length Description 16 | // ---------------------------------------------------------------------------- 17 | // PMC 0x000000 0x1000 Master control 18 | // PBUS 0x001000 0x1000 Bus control 19 | // PFIFO 0x002000 0x2000 MMIO and DMA FIFO submission to PGRAPH (there's no VPE in NV2A) 20 | // PRMA 0x007000 0x1000 Real mode BAR access 21 | // PVIDEO 0x008000 0x1000 Video overlay 22 | // PTIMER 0x009000 0x1000 Time measurement and time-based alarms 23 | // PCOUNTER 0x00A000 0x1000 Performance monitoring counters 24 | // PNVIO 0x0C0000 0x1000 VGA sequencer and graph controller registers 25 | // PFB 0x100000 0x1000 Memory interface 26 | // PSTRAPS 0x101000 0x1000 Straps readout 27 | // PROM 0x300000 0x20000 ROM access window 28 | // PGRAPH 0x400000 0x2000 2D/3D graphics engine 29 | // PCRTC 0x600000 0x1000 CRTC controls 30 | // PRMCIO 0x601000 0x1000 VGA CRTC and attribute controller registers 31 | // PRAMDAC 0x680000 0x1000 RAMDAC, video overlay, cursor, and PLL control 32 | // PRMDIO 0x681000 0x1000 VGA DAC registers 33 | // PRAMIN 0x700000 0x100000 RAMIN access 34 | // USER 0x800000 0x200000 PFIFO MMIO/DMA submission area 35 | // 36 | #pragma once 37 | 38 | #include "state.h" 39 | #include "engine.h" 40 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/util/invoke_later.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/util/invoke_later.h" 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | void InvokeLaterThreadFunc(void *data) { 8 | ((InvokeLater *)data)->Run(); 9 | } 10 | 11 | InvokeLater::InvokeLater(InvokeLaterFunc func, void *userData) 12 | : m_func(func) 13 | , m_userData(userData) 14 | { 15 | m_running = false; 16 | m_primed = false; 17 | m_thread = nullptr; 18 | } 19 | 20 | InvokeLater::~InvokeLater() { 21 | Stop(); 22 | if (m_thread != nullptr) { 23 | m_thread->join(); 24 | } 25 | delete m_thread; 26 | } 27 | 28 | void InvokeLater::Start() { 29 | if (m_running) { 30 | return; 31 | } 32 | 33 | m_running = true; 34 | m_thread = new std::thread(InvokeLaterThreadFunc, this); 35 | } 36 | 37 | void InvokeLater::Stop() { 38 | m_running = false; 39 | Cancel(); 40 | } 41 | 42 | void InvokeLater::Set(std::chrono::time_point& expiration) { 43 | if (m_func == nullptr) { 44 | return; 45 | } 46 | 47 | Cancel(); 48 | m_targetExpiration = expiration; 49 | m_primed = true; 50 | m_setupCond.notify_one(); 51 | } 52 | 53 | void InvokeLater::Cancel() { 54 | m_primed = false; 55 | { 56 | std::unique_lock lock(m_setupMutex); 57 | m_setupCond.notify_one(); 58 | } 59 | { 60 | std::unique_lock lock(m_mutex); 61 | m_cond.notify_one(); 62 | } 63 | } 64 | 65 | void InvokeLater::Run() { 66 | while (m_running) { 67 | // Wait for a timer to be set up 68 | { 69 | std::unique_lock lock(m_setupMutex); 70 | m_setupCond.wait(lock); 71 | } 72 | 73 | // Wait until the expiration time is reached 74 | { 75 | std::unique_lock lock(m_mutex); 76 | m_cond.wait_until(lock, m_targetExpiration); 77 | } 78 | 79 | if (!m_running) { 80 | break; 81 | } 82 | 83 | if (m_primed && m_func != nullptr) { 84 | m_func(m_userData); 85 | } 86 | } 87 | } 88 | 89 | } 90 | 91 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/ata_device.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "../ata/ata_defs.h" 17 | #include "../basic/interrupt.h" 18 | #include "ata_common.h" 19 | #include "drvs/ata_device_driver.h" 20 | #include "drvs/drv_null.h" 21 | 22 | namespace strikebox { 23 | namespace hw { 24 | namespace ata { 25 | 26 | /*! 27 | * Represents one ATA device. The concrete implementation for the device is 28 | * provided by the IATADeviceDriver. 29 | */ 30 | class ATADevice { 31 | public: 32 | ATADevice(Channel channel, uint8_t devIndex, ATARegisters& regs, InterruptTrigger& interrupt); 33 | ~ATADevice(); 34 | 35 | ATARegisters& GetRegisters() { return m_regs; } 36 | IATADeviceDriver* GetDriver() { return m_driver; } 37 | const Channel GetChannel() const { return m_channel; } 38 | const uint8_t GetIndex() const { return m_devIndex; } 39 | InterruptTrigger& GetInterrupt() const { return m_interrupt; } 40 | 41 | // ----- Device driver management ----------------------------------------- 42 | 43 | void SetDeviceDriver(IATADeviceDriver *driver) { m_driver = driver; } 44 | bool IsAttached() const { return m_driver->IsAttached(); } 45 | 46 | private: 47 | friend class ATAChannel; 48 | 49 | const Channel m_channel; 50 | const uint8_t m_devIndex; 51 | 52 | InterruptTrigger& m_interrupt; 53 | 54 | // The device driver that responds to commands 55 | IATADeviceDriver *m_driver; 56 | 57 | // ----- Registers -------------------------------------------------------- 58 | 59 | // A reference to the registers of the ATA channel that owns this device 60 | ATARegisters& m_regs; 61 | }; 62 | 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/gpu/engines/pbus.cpp: -------------------------------------------------------------------------------- 1 | // StrikeBox NV2A PBUS (Bus control) engine emulation 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // Based on envytools and nouveau: 5 | // https://envytools.readthedocs.io/en/latest/index.html 6 | // https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau 7 | // 8 | // References to particular items in the documentation are denoted between 9 | // brackets optionally followed by a quote from the documentation. 10 | #include "strikebox/hw/gpu/engines/pbus.h" 11 | #include "strikebox/hw/gpu/state.h" 12 | 13 | #include "strikebox/log.h" 14 | 15 | namespace strikebox::nv2a { 16 | 17 | void PBUS::Reset() { 18 | m_interruptLevels = 0; 19 | m_enabledInterrupts = 0; 20 | } 21 | 22 | uint32_t PBUS::Read(const uint32_t addr) { 23 | switch (addr) { 24 | case Reg_PBUS_INTR: return m_interruptLevels; 25 | case Reg_PBUS_INTR_ENABLE: return m_enabledInterrupts; 26 | default: 27 | if (addr >= 0x800 && addr <= 0x8FF) { 28 | // PCI Configuration Space access 29 | // [https://envytools.readthedocs.io/en/latest/hw/bus/pci.html#pbus-mmio-pci] 30 | return m_nv2a.readPCIConfig(addr - 0x800); 31 | } 32 | 33 | log_spew("[NV2A] PBUS::Read: Unimplemented read! address = 0x%x\n", addr); 34 | return 0; 35 | } 36 | } 37 | 38 | void PBUS::Write(const uint32_t addr, const uint32_t value) { 39 | switch (addr) { 40 | case Reg_PBUS_INTR: 41 | // Clear specified interrupts 42 | m_interruptLevels &= ~value; 43 | m_nv2a.UpdateIRQ(); 44 | break; 45 | case Reg_PBUS_INTR_ENABLE: 46 | m_enabledInterrupts = value; 47 | m_nv2a.UpdateIRQ(); 48 | break; 49 | default: 50 | if (addr >= 0x800 && addr <= 0x8FF) { 51 | // PCI Configuration Space access 52 | // [https://envytools.readthedocs.io/en/latest/hw/bus/pci.html#pbus-mmio-pci] 53 | m_nv2a.writePCIConfig(addr - 0x800, value); 54 | } 55 | else { 56 | log_spew("[NV2A] PBUS::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value); 57 | } 58 | break; 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/pci/ac97.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/pci/ac97.h" 2 | 3 | #include "strikebox/log.h" 4 | 5 | namespace strikebox { 6 | 7 | AC97Device::AC97Device() 8 | : PCIDevice(PCI_HEADER_TYPE_NORMAL, PCI_VENDOR_ID_NVIDIA, 0x01B1, 0xB1, 9 | 0x04, 0x01, 0x00) // Multimedia Audio Controller 10 | { 11 | } 12 | 13 | AC97Device::~AC97Device() { 14 | } 15 | 16 | // PCI Device functions 17 | 18 | void AC97Device::Init() { 19 | RegisterBAR(0, 0x100, PCI_BAR_TYPE_IO); // 0xD000 - 0xD0FF 20 | RegisterBAR(1, 0x80, PCI_BAR_TYPE_IO); // 0xD200 - 0xD27F 21 | RegisterBAR(2, 0x1000, PCI_BAR_TYPE_MEMORY); // 0xFEC00000 - 0xFEC00FFF 22 | 23 | // Initialize configuration space 24 | Write16(m_configSpace, PCI_STATUS, PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_CAP_LIST); 25 | Write8(m_configSpace, PCI_CAPABILITY_LIST, 0x44); 26 | Write8(m_configSpace, PCI_MIN_GNT, 0x02); 27 | Write8(m_configSpace, PCI_MAX_LAT, 0x05); 28 | 29 | // Capability list 30 | Write8(m_configSpace, 0x44, PCI_CAP_ID_PM); 31 | Write8(m_configSpace, 0x45, 0x00); 32 | 33 | // Unknown registers 34 | Write16(m_configSpace, 0x46, 0x2); 35 | Write16(m_configSpace, 0x4c, 0x106); 36 | } 37 | 38 | void AC97Device::Reset() { 39 | } 40 | 41 | void AC97Device::PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) { 42 | //log_spew("AC97Device::PCIIORead: Unimplemented! bar = %d, port = 0x%x, size = %u\n", barIndex, port, size); 43 | } 44 | 45 | void AC97Device::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) { 46 | //log_spew("AC97Device::PCIIOWrite: Unimplemented! bar = %d, port = 0x%x, value = 0x%x, size = %u\n", barIndex, port, value, size); 47 | } 48 | 49 | void AC97Device::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) { 50 | //log_spew("AC97Device::PCIMMIORead: Unimplemented! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size); 51 | } 52 | 53 | void AC97Device::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) { 54 | //log_spew("AC97Device::PCIMMIOWrite: Unimplemented! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Top-level CMake project definitions. 2 | # ------------------------------------------------------------------------------- 3 | # MIT License 4 | # 5 | # Copyright (c) 2019 Ivan Roberto de Oliveira 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | cmake_minimum_required(VERSION 3.8) 26 | 27 | project(strikebox VERSION 1.0.0) 28 | 29 | # Differentiate between Linux and macOS 30 | if(UNIX AND NOT APPLE) 31 | set(LINUX TRUE) 32 | endif() 33 | 34 | # Define properties and include helpers for Visual Studio 35 | if(MSVC) 36 | include(cmake/VSHelpers.cmake) 37 | 38 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 39 | 40 | # Configure startup project 41 | set_property(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" PROPERTY VS_STARTUP_PROJECT strikebox-cli) 42 | endif() 43 | 44 | include(cmake/PrecompiledHeader.cmake) 45 | include(GNUInstallDirs) 46 | 47 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") 48 | 49 | # Require C++17 features 50 | set(CMAKE_CXX_STANDARD 17) 51 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 52 | set(CMAKE_CXX_EXTENSIONS ON) 53 | 54 | # Add modules and apps 55 | add_subdirectory(modules) 56 | add_subdirectory(apps) 57 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/atapi/cmds/cmd_mode_sense_10.h: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #pragma once 30 | 31 | #include 32 | 33 | #include "proto_data_in.h" 34 | 35 | namespace strikebox { 36 | namespace hw { 37 | namespace atapi { 38 | namespace cmd { 39 | 40 | /*! 41 | * Implements the MODE SENSE(10) command (0x5A) [p 6.10]. 42 | */ 43 | class ModeSense10 : public ATAPIDataInCommand { 44 | public: 45 | ModeSense10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver); 46 | virtual ~ModeSense10(); 47 | 48 | bool BeginTransfer() override; 49 | 50 | // This command only transfer one block; Execute() will never be invoked 51 | bool Execute() override { return false; } 52 | 53 | static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ModeSense10(packetCmdState, driver); } 54 | 55 | protected: 56 | uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override; 57 | }; 58 | 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/atapi/cmds/cmd_read_capacity.h: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #pragma once 30 | 31 | #include 32 | 33 | #include "proto_data_in.h" 34 | 35 | namespace strikebox { 36 | namespace hw { 37 | namespace atapi { 38 | namespace cmd { 39 | 40 | /*! 41 | * Implements the READ CAPACITY command (0x25) [m 5.16]. 42 | */ 43 | class ReadCapacity : public ATAPIDataInCommand { 44 | public: 45 | ReadCapacity(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver); 46 | virtual ~ReadCapacity(); 47 | 48 | bool BeginTransfer() override; 49 | 50 | // This command only transfer one block; Execute() will never be invoked 51 | bool Execute() override { return false; } 52 | 53 | static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ReadCapacity(packetCmdState, driver); } 54 | 55 | protected: 56 | uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override; 57 | }; 58 | 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/atapi/cmds/proto_nondata.h: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #pragma once 30 | 31 | #include 32 | 33 | #include "atapi_command.h" 34 | 35 | namespace strikebox { 36 | namespace hw { 37 | namespace atapi { 38 | namespace cmd { 39 | 40 | /*! 41 | * Base class for all ATAPI commands that do not transfer data. 42 | */ 43 | class ATAPINonDataCommand : public IATAPICommand { 44 | public: 45 | ATAPINonDataCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver); 46 | virtual ~ATAPINonDataCommand(); 47 | 48 | virtual bool Prepare() override = 0; 49 | virtual bool Execute() override = 0; 50 | 51 | PacketOperationType GetOperationType() override { return PktOpNonData; } 52 | 53 | // Technically, a non-data transfer doesn't transfer data. 54 | // Technically, if no transfer is needed then the transfer is complete. 55 | // So, technically, this should return true. 56 | bool IsTransferFinished() override { return true; } 57 | }; 58 | 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/atapi/cmds/cmd_read_dvd_structure.h: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #pragma once 30 | 31 | #include 32 | 33 | #include "proto_data_in.h" 34 | 35 | namespace strikebox { 36 | namespace hw { 37 | namespace atapi { 38 | namespace cmd { 39 | 40 | /*! 41 | * Implements the READ DVD STRUCTURE command (0xAD) [m 5.20]. 42 | */ 43 | class ReadDVDStructure : public ATAPIDataInCommand { 44 | public: 45 | ReadDVDStructure(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver); 46 | virtual ~ReadDVDStructure(); 47 | 48 | bool BeginTransfer() override; 49 | 50 | // This command only transfer one block; Execute() will never be invoked 51 | bool Execute() override { return false; } 52 | 53 | static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ReadDVDStructure(packetCmdState, driver); } 54 | 55 | protected: 56 | uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override; 57 | }; 58 | 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/proto_pio_data_in.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "ata_command.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Possible outcomes for the attempt to read a block of data. 25 | */ 26 | enum BlockReadResult { 27 | BlockReadOK, // Block successfully read 28 | BlockReadEnd, // Last block reached 29 | BlockReadError, // An error occurred during the read operation 30 | }; 31 | 32 | /*! 33 | * Base class for all commands based on the PIO data in protocol [9.7]. 34 | */ 35 | class PIODataInProtocolCommand : public IATACommand { 36 | public: 37 | PIODataInProtocolCommand(ATADevice& device); 38 | virtual ~PIODataInProtocolCommand() override; 39 | 40 | // ----- Low-level operations --------------------------------------------- 41 | 42 | void Execute() override; 43 | void ReadData(uint8_t *value, uint32_t size) override; 44 | void WriteData(uint8_t *value, uint32_t size) override; 45 | 46 | protected: 47 | // ----- Protocol operations ---------------------------------------------- 48 | 49 | // Reads the next block. 50 | // Returns BlockReadOK if the next block is available and was read without error. 51 | // Returns BlockReadEnd if there are no more blocks to read. 52 | // Returns BlockReadError if there was an error reading the next block. 53 | virtual BlockReadResult ReadBlock(uint8_t block[kSectorSize]) = 0; 54 | 55 | // Determines if there are more blocks to read from the device. 56 | virtual bool HasMoreData() = 0; 57 | 58 | private: 59 | uint8_t m_buffer[kSectorSize]; 60 | uint16_t m_bufferPos; 61 | 62 | void FillBuffer(); 63 | uint32_t ReadBuffer(uint8_t *dst, uint8_t size); 64 | }; 65 | 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/atapi/cmds/proto_data_in.cpp: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #include "strikebox/hw/atapi/cmds/proto_data_in.h" 30 | 31 | #include "strikebox/log.h" 32 | 33 | namespace strikebox { 34 | namespace hw { 35 | namespace atapi { 36 | namespace cmd { 37 | 38 | ATAPIDataInCommand::ATAPIDataInCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) 39 | : IATAPICommand(packetCmdState, driver) 40 | { 41 | } 42 | 43 | ATAPIDataInCommand::~ATAPIDataInCommand() { 44 | } 45 | 46 | bool ATAPIDataInCommand::Prepare() { 47 | // Get allocation length and allocate buffer 48 | uint32_t allocLength = GetAllocationLength(&m_packetCmdState.cdb); 49 | if (allocLength > m_packetCmdState.input.byteCountLimit) { 50 | allocLength = m_packetCmdState.input.byteCountLimit; 51 | } 52 | if (!m_packetCmdState.dataBuffer.Allocate(allocLength)) { 53 | return false; 54 | } 55 | 56 | // Initialize buffer with data. 57 | // May access the device if needed. 58 | return BeginTransfer(); 59 | } 60 | 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/ata/cmds/cmd_identify_packet_device.cpp: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #include "strikebox/hw/ata/cmds/cmd_identify_packet_device.h" 13 | 14 | #include "strikebox/log.h" 15 | 16 | namespace strikebox { 17 | namespace hw { 18 | namespace ata { 19 | namespace cmd { 20 | 21 | IdentifyPacketDevice::IdentifyPacketDevice(ATADevice& device) 22 | : PIODataInProtocolCommand(device) { 23 | } 24 | 25 | IdentifyPacketDevice::~IdentifyPacketDevice() { 26 | } 27 | 28 | bool IdentifyPacketDevice::HasMoreData() { 29 | return false; 30 | } 31 | 32 | BlockReadResult IdentifyPacketDevice::ReadBlock(uint8_t data[kSectorSize]) { 33 | // Ask the device driver to identify itself 34 | if (!m_driver->IdentifyPacketDevice(reinterpret_cast(data))) { 35 | // The device does not implement the Identify PACKET Device command 36 | // Return command aborted as specified in the error output section [8.13.6] 37 | m_regs.error |= ErrAbort; 38 | return BlockReadError; 39 | } 40 | 41 | // Handle normal output as specified in [8.13.5] 42 | 43 | // Device/Head register: 44 | // "DEV shall indicate the selected device." 45 | // Not necessary, but the spec says so 46 | m_regs.deviceHead = (m_regs.deviceHead & ~(1 << kDevSelectorBit)) | (m_devIndex << kDevSelectorBit); 47 | 48 | // Status register: 49 | // "BSY shall be cleared to zero indicating command completion." 50 | // Already handled by the caller 51 | 52 | // "DRDY shall be set to one." 53 | m_regs.status |= StReady; 54 | 55 | // "DF (Device Fault) shall be cleared to zero." 56 | // "DRQ shall be cleared to zero." 57 | // "ERR shall be cleared to zero." 58 | m_regs.status &= ~(StDeviceFault | StDataRequest | StError); 59 | 60 | return BlockReadOK; 61 | } 62 | 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/cmds/proto_pio_data_out.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "ata_command.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | namespace cmd { 22 | 23 | /*! 24 | * Possible outcomes for the attempt to read a block of data. 25 | */ 26 | enum BlockWriteResult { 27 | BlockWriteOK, // Block successfully written 28 | BlockWriteEnd, // Last block reached 29 | BlockWriteError, // An error occurred during the write operation 30 | }; 31 | 32 | /*! 33 | * Base class for all commands based on the PIO data out protocol [9.8]. 34 | */ 35 | class PIODataOutProtocolCommand : public IATACommand { 36 | public: 37 | PIODataOutProtocolCommand(ATADevice& device); 38 | virtual ~PIODataOutProtocolCommand() override; 39 | 40 | // ----- Low-level operations --------------------------------------------- 41 | 42 | void Execute() override; 43 | void ReadData(uint8_t *value, uint32_t size) override; 44 | void WriteData(uint8_t *value, uint32_t size) override; 45 | 46 | protected: 47 | // ----- Protocol operations ---------------------------------------------- 48 | 49 | // Initializes the command. 50 | // Returns false in case of error. 51 | virtual bool Initialize() = 0; 52 | 53 | // Writes the next block. 54 | // Returns BlockWriteOK if the next block was written successfully. 55 | // Returns BlockWriteEnd if there are no more blocks to write. 56 | // Returns BlockWriteError if there was an error writing the next block. 57 | virtual BlockWriteResult ProcessBlock(uint8_t block[kSectorSize]) = 0; 58 | 59 | private: 60 | uint8_t m_buffer[kSectorSize]; 61 | uint16_t m_bufferPos = 0; 62 | 63 | uint32_t WriteBuffer(uint8_t *src, uint8_t length); 64 | void DrainBuffer(); 65 | }; 66 | 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/bus/smbus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../pci/pci.h" 4 | #include "../sm/sm.h" 5 | #include "../basic/irq.h" 6 | 7 | #include 8 | 9 | namespace strikebox { 10 | 11 | #define SMB_ADDR_OFFSET 0xE0 12 | #define SMB_IOSIZE 16 13 | #define SMB_IRQ 11 14 | 15 | #define SMB_GLOBAL_STATUS 0x0 16 | #define SMB_GLOBAL_ENABLE 0x2 17 | #define SMB_HOST_ADDRESS 0x4 18 | #define SMB_HOST_DATA 0x6 19 | #define SMB_HOST_COMMAND 0x8 20 | #define SMB_HOST_BLOCK_DATA 0x9 21 | #define SMB_HAS_DATA 0xA 22 | #define SMB_HAS_DEVICE_ADDRESS 0xC 23 | #define SMB_HAS_HOST_ADDRESS 0xE 24 | #define SMB_SNOOP_ADDRESS 0xF 25 | 26 | /* AMD756 constants */ 27 | #define AMD756_QUICK 0x00 28 | #define AMD756_BYTE 0x01 29 | #define AMD756_BYTE_DATA 0x02 30 | #define AMD756_WORD_DATA 0x03 31 | #define AMD756_PROCESS_CALL 0x04 32 | #define AMD756_BLOCK_DATA 0x05 33 | 34 | // SMB_GLOBAL_STATUS flags 35 | #define GS_ABRT_STS (1 << 0) 36 | #define GS_COL_STS (1 << 1) 37 | #define GS_PRERR_STS (1 << 2) 38 | #define GS_HST_STS (1 << 3) 39 | #define GS_HCYC_STS (1 << 4) 40 | #define GS_TO_STS (1 << 5) 41 | #define GS_SMB_STS (1 << 11) 42 | 43 | #define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | GS_HCYC_STS | GS_TO_STS ) 44 | 45 | #define GE_CYC_TYPE_MASK (7) 46 | #define GE_HOST_STC (1 << 3) 47 | 48 | #define GE_HCYC_EN (1 << 4) 49 | #define GE_ABORT (1 << 5) 50 | 51 | class SMBus : public PCIDevice { 52 | public: 53 | SMBus(IRQ *irq); 54 | ~SMBus(); 55 | 56 | // PCI Functions 57 | void Init(); 58 | void Reset(); 59 | 60 | void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override; 61 | void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override; 62 | 63 | // Misc 64 | void ConnectDevice(uint8_t addr, SMDevice *device); 65 | 66 | private: 67 | uint8_t m_Status = 0; 68 | uint8_t m_Control = 0; 69 | uint8_t m_Command = 0; 70 | uint8_t m_Address = 0; 71 | uint8_t m_Data0 = 0; 72 | uint8_t m_Data1 = 0; 73 | uint8_t m_Data[32] = { 0 }; 74 | uint8_t m_Index = 0; 75 | 76 | IRQ *m_irq; 77 | 78 | void ExecuteTransaction(); 79 | 80 | std::map m_Devices; 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/atapi/cmds/cmd_test_unit_ready.cpp: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #include "strikebox/hw/atapi/cmds/cmd_test_unit_ready.h" 30 | 31 | #include "strikebox/log.h" 32 | 33 | namespace strikebox { 34 | namespace hw { 35 | namespace atapi { 36 | namespace cmd { 37 | 38 | TestUnitReady::TestUnitReady(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) 39 | : ATAPINonDataCommand(packetCmdState, driver) 40 | { 41 | } 42 | 43 | TestUnitReady::~TestUnitReady() { 44 | } 45 | 46 | bool TestUnitReady::Prepare() { 47 | // Nothing to prepare or validate 48 | return true; 49 | } 50 | 51 | bool TestUnitReady::Execute() { 52 | // If there is no disc in the drive, return the expected sense key and parameters. 53 | // The default values tell that there is media in the drive and the device is ready to accept commands. 54 | if (!m_driver->HasMedium()) { 55 | m_packetCmdState.result.status = StCheckCondition; 56 | m_packetCmdState.result.senseKey = SKNotReady; 57 | m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent; 58 | } 59 | return true; 60 | } 61 | 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/dynamic_variant.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace strikebox { 6 | 7 | /*! 8 | * Stores any type of object. 9 | * 10 | * Constructors and destructors are automatically invoked. A block of memory is 11 | * automatically managed by this object and resized if needed by the new type. 12 | */ 13 | class DynamicVariant { 14 | public: 15 | DynamicVariant() {} 16 | ~DynamicVariant() { 17 | if (m_dtor != nullptr) { 18 | m_dtor(*this); 19 | } 20 | if (m_memory != nullptr) { 21 | free(m_memory); 22 | } 23 | } 24 | 25 | /*! 26 | * Reserves memory for the given data structure, invoking the constructor 27 | * with the given arguments. Placement new is used to initialize the object 28 | * or value directly into the allocated memory block. 29 | * 30 | * If another data structure is currently occupying the shared memory, it 31 | * will be destructed before reserving memory for the new data structure. 32 | * 33 | * If the new data structure is larger than the currently allocated memory 34 | * block, a new block will be allocated with the new data structure size, 35 | * otherwise the existing memory block is reused. 36 | */ 37 | template 38 | T* Allocate(Args&&... args) { 39 | // Invoke destructor from previous data structure 40 | if (m_dtor != nullptr) { 41 | m_dtor(*this); 42 | } 43 | 44 | // Reallocate memory if new data structure is larger than the current buffer 45 | if (m_size < sizeof(T)) { 46 | if (m_memory != nullptr) { 47 | free(m_memory); 48 | } 49 | m_memory = malloc(sizeof(T)); 50 | m_size = sizeof(T); 51 | } 52 | 53 | // Update destructor to new data structure and call constructor 54 | m_dtor = [](DynamicVariant& u) { ((T*)u.m_memory)->~T(); }; 55 | return new(m_memory) T(std::forward(args)...); 56 | } 57 | 58 | /*! 59 | * Destructs the data structure present in the shared memory, if any. 60 | */ 61 | void Free() { 62 | if (m_dtor != nullptr) { 63 | m_dtor(*this); 64 | m_dtor = nullptr; 65 | } 66 | } 67 | 68 | private: 69 | void *m_memory = nullptr; 70 | size_t m_size = 0; 71 | void (*m_dtor)(DynamicVariant&) = nullptr; 72 | }; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/i8259.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "virt86/virt86.hpp" 7 | 8 | #include "strikebox/io.h" 9 | #include "irq.h" 10 | 11 | namespace strikebox { 12 | 13 | #define PORT_PIC_MASTER_COMMAND 0x20 14 | #define PORT_PIC_MASTER_DATA 0x21 15 | #define PORT_PIC_SLAVE_COMMAND 0xA0 16 | #define PORT_PIC_SLAVE_DATA 0xA1 17 | #define PORT_PIC_MASTER_ELCR 0x4D0 18 | #define PORT_PIC_SLAVE_ELCR 0x4D1 19 | 20 | #define PORT_PIC_MASTER_BASE PORT_PIC_MASTER_COMMAND 21 | #define PORT_PIC_SLAVE_BASE PORT_PIC_SLAVE_COMMAND 22 | #define PORT_PIC_ELCR_BASE PORT_PIC_MASTER_ELCR 23 | #define PORT_PIC_COUNT 2 24 | 25 | #define PIC_MASTER 0 26 | #define PIC_SLAVE 1 27 | 28 | class i8259 : public IODevice, public IRQHandler { 29 | public: 30 | i8259(virt86::VirtualProcessor& cpu); 31 | virtual ~i8259(); 32 | void Reset(); 33 | 34 | bool MapIO(IOMapper *mapper); 35 | 36 | bool IORead(uint32_t port, uint32_t *value, uint8_t size) override; 37 | bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override; 38 | 39 | void HandleIRQ(uint8_t irqNum, bool level) override; 40 | 41 | int GetCurrentIRQ(); 42 | private: 43 | virt86::VirtualProcessor& m_vp; 44 | 45 | uint8_t m_PreviousIRR[2]; // used for edge-detection 46 | uint8_t m_IRR[2]; 47 | uint8_t m_IMR[2]; 48 | uint8_t m_ISR[2]; 49 | uint8_t m_Base[2]; 50 | uint8_t m_ReadRegisterSelect[2]; 51 | uint8_t m_SpecialMask[2]; 52 | uint8_t m_InitState[2]; 53 | uint8_t m_ELCR[2]; 54 | uint8_t m_ELCRMask[2]; 55 | uint8_t m_PriorityAdd[2]; 56 | 57 | bool m_Poll[2]; 58 | bool m_RotateOnAutoEOI[2]; 59 | bool m_Is4ByteInit[2]; 60 | bool m_InterruptOutput[2]; 61 | bool m_AutoEOI[2]; 62 | bool m_IsSpecialFullyNestedMode[2]; 63 | 64 | std::mutex m_handleIRQMutex; 65 | 66 | uint32_t CommandRead(int pic); 67 | void CommandWrite(int pic, uint32_t value); 68 | uint32_t DataRead(int pic); 69 | void DataWrite(int pic, uint32_t value); 70 | 71 | void AcknowledgeIRQ(int pic, int index); 72 | int GetIRQ(int pic); 73 | void SetIRQ(int pic, int index, bool value); 74 | int GetPriority(int pic, uint8_t mask); 75 | uint8_t Poll(int pic); 76 | void Reset(int pic); 77 | void UpdateIRQ(int pic); 78 | 79 | void RaiseIRQ(int index); 80 | void LowerIRQ(int index); 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/pci/usb_pci.cpp: -------------------------------------------------------------------------------- 1 | #include "strikebox/hw/pci/usb_pci.h" 2 | 3 | #include "strikebox/log.h" 4 | 5 | namespace strikebox { 6 | 7 | USBPCIDevice::USBPCIDevice(uint8_t irqn, virt86::VirtualProcessor& vp) 8 | : PCIDevice(PCI_HEADER_TYPE_NORMAL, PCI_VENDOR_ID_NVIDIA, 0x01C2, 0xB1, 9 | 0x0c, 0x03, 0x10) // USB OHCI 10 | , m_irqn(irqn) 11 | , m_vp(vp) 12 | { 13 | } 14 | 15 | USBPCIDevice::~USBPCIDevice() { 16 | } 17 | 18 | // PCI Device functions 19 | 20 | void USBPCIDevice::Init() { 21 | RegisterBAR(0, 0x1000, PCI_BAR_TYPE_MEMORY); // 0xFED00000 - 0xFED00FFF and 0xFED08000 - 0xFED08FFF 22 | 23 | // Initialize configuration space 24 | Write16(m_configSpace, PCI_STATUS, PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_CAP_LIST); 25 | Write8(m_configSpace, PCI_CAPABILITY_LIST, 0x44); 26 | Write8(m_configSpace, PCI_MIN_GNT, 0x03); 27 | Write8(m_configSpace, PCI_MAX_LAT, 0x01); 28 | 29 | // Capability list 30 | Write8(m_configSpace, 0x44, PCI_CAP_ID_PM); 31 | Write8(m_configSpace, 0x45, 0x00); 32 | 33 | // Unknown registers 34 | Write16(m_configSpace, 0x46, 0xda02); 35 | Write32(m_configSpace, 0x4c, 0x2); 36 | } 37 | 38 | void USBPCIDevice::Reset() { 39 | } 40 | 41 | void USBPCIDevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) { 42 | //log_spew("USBPCIDevice::PCIMMIORead: bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size); 43 | if (barIndex != 0) { 44 | log_spew("USBPCIDevice::PCIMMIORead: Unhandled BAR access: %d, address = 0x%x, size = %u\n", barIndex, addr, size); 45 | *value = 0; 46 | return; 47 | } 48 | 49 | *value = 0; 50 | log_spew("USBPCIDevice::PCIMMIORead: Unimplemented read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size); 51 | } 52 | 53 | void USBPCIDevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) { 54 | //log_spew("USBPCIDevice::PCIMMIOWrite: bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size); 55 | if (barIndex != 0) { 56 | log_spew("USBPCIDevice::PCIMMIOWrite: Unhandled BAR access: %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size); 57 | return; 58 | } 59 | 60 | log_spew("USBPCIDevice::PCIMMIOWrite: Unimplemented write! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/atapi/cmds/cmd_read_10.h: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #pragma once 30 | 31 | #include 32 | 33 | #include "proto_data_in.h" 34 | 35 | namespace strikebox { 36 | namespace hw { 37 | namespace atapi { 38 | namespace cmd { 39 | 40 | /*! 41 | * Implements the READ(10) command (0x28) [b 5.11]. 42 | */ 43 | class Read10 : public ATAPIDataInCommand { 44 | public: 45 | Read10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver); 46 | virtual ~Read10(); 47 | 48 | bool BeginTransfer() override; 49 | bool Execute() override; 50 | 51 | static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new Read10(packetCmdState, driver); } 52 | 53 | protected: 54 | uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override; 55 | 56 | private: 57 | // Maximum number of bytes to transfer in a single read operation 58 | uint32_t m_transferLength; 59 | 60 | // Next starting byte to read 61 | uint64_t m_currentByte; 62 | 63 | // Last byte to read (exclusive) 64 | uint64_t m_lastByte; 65 | 66 | // Read buffer 67 | uint8_t *m_buffer; 68 | }; 69 | 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/cmos.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strikebox/io.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace strikebox { 9 | 10 | #define CMOS_IRQ 8 11 | 12 | #define PORT_CMOS_BASE 0x70 13 | #define PORT_CMOS_COUNT 3 14 | 15 | #define PORT_CMOS_CONTROL 0 16 | #define PORT_CMOS_DATA 1 17 | #define PORT_CMOS_EXT_CONTROL 2 18 | 19 | enum CMOSRegister { 20 | RTCSeconds = 0x0, 21 | RTCSecondsAlarm = 0x1, 22 | RTCMinutes = 0x2, 23 | RTCMinutesAlarm = 0x3, 24 | RTCHours = 0x4, 25 | RTCHoursAlarm = 0x5, 26 | 27 | RTCDayOfWeek = 0x6, 28 | RTCDayOfMonth = 0x7, 29 | RTCMonth = 0x8, 30 | RTCYear = 0x9, 31 | RTCCentury = 0x7f, // Xbox only 32 | 33 | RegA = 0xa, 34 | RegB = 0xb, 35 | RegC = 0xc, 36 | RegD = 0xd, 37 | }; 38 | 39 | enum CMOSRegisterBit { 40 | RegA_UIP = (1 << 7), // (UIP) Update in progress 41 | 42 | RegB_SET = (1 << 7), // (SET) 43 | RegB_PIE = (1 << 6), // (PIE) Periodic interrupt enable 44 | RegB_AIE = (1 << 5), // (AIE) Alarm interrupt enable 45 | RegB_UIE = (1 << 4), // (UIE) Update-ended interrupt enable 46 | RegB_SQWE = (1 << 3), // (SQWE) Square wave enable 47 | RegB_DM = (1 << 2), // (DM) Data mode 48 | RegB_24_12 = (1 << 1), // (24/12) Format output to: 1 = 24-hour format, 2 = 12-hour 49 | RegB_DSE = (1 << 0), // (DSE) Daylight savings enable 50 | 51 | RegC_IRQF = (1 << 7), // (IRQF) Interrupt request flag 52 | RegC_PF = (1 << 6), // (PF) Periodic interrupt flag 53 | RegC_AF = (1 << 5), // (AF) Alarm flag 54 | RegC_UF = (1 << 4), // (AF) Update-ended interrupt flag 55 | }; 56 | 57 | class CMOS : public IODevice { 58 | public: 59 | CMOS(); 60 | virtual ~CMOS(); 61 | void Reset(); 62 | 63 | bool MapIO(IOMapper *mapper); 64 | 65 | bool IORead(uint32_t port, uint32_t *value, uint8_t size) override; 66 | bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override; 67 | private: 68 | // Selected register address 69 | uint8_t m_regAddr; 70 | 71 | // CMOS memory 72 | uint8_t m_memory[0x100]; 73 | 74 | // Offset from host RTC (in seconds), used to virtualize the RTC 75 | int64_t m_offset; 76 | 77 | void ReadRTC(uint8_t reg, uint8_t *value); 78 | void WriteRTC(uint8_t reg, uint8_t value); 79 | 80 | uint8_t ToBCD(uint8_t value); 81 | uint8_t FromBCD(uint8_t value); 82 | 83 | uint8_t ToBCDHour(uint8_t hour); 84 | uint8_t FromBCDHour(uint8_t hour); 85 | }; 86 | 87 | } 88 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/basic/char.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "strikebox/util/fifo.h" 6 | 7 | namespace strikebox { 8 | 9 | #define CHR_EVENT_BREAK 0 // Serial break char 10 | #define CHR_EVENT_FOCUS 1 // Focus to this terminal (modal input needed) 11 | #define CHR_EVENT_OPENED 2 // New connection established 12 | #define CHR_EVENT_MUX_IN 3 // Mux-focus was set to this terminal 13 | #define CHR_EVENT_MUX_OUT 4 // Mux-focus will move on 14 | #define CHR_EVENT_CLOSED 5 // Connection closed 15 | 16 | #define CHR_TIOCM_CTS 0x020 17 | #define CHR_TIOCM_CAR 0x040 18 | #define CHR_TIOCM_DSR 0x100 19 | #define CHR_TIOCM_RI 0x080 20 | #define CHR_TIOCM_DTR 0x002 21 | #define CHR_TIOCM_RTS 0x004 22 | 23 | #define CHR_IO_IN 0 24 | #define CHR_IO_OUT 1 25 | 26 | struct SerialParams { 27 | int baudRate; 28 | int divider; 29 | int parity; 30 | int dataBits; 31 | int stopBits; 32 | }; 33 | 34 | typedef int (*CanReceiveCallback)(void *userData); 35 | typedef void (*ReceiveCallback)(void *userData, const uint8_t *buf, int size); 36 | typedef void (*EventCallback)(void *userData, int event); 37 | 38 | 39 | /*! 40 | * Base class for objects that can transmit and receive characters. 41 | */ 42 | class CharDriver { 43 | public: 44 | virtual bool Init() = 0; 45 | virtual int Write(const uint8_t *buf, int len) = 0; 46 | virtual void AcceptInput() = 0; 47 | virtual void Stop() = 0; 48 | 49 | // IOCTLs 50 | virtual void SetBreakEnable(bool breakEnable) = 0; 51 | virtual void SetSerialParameters(SerialParams *params) = 0; 52 | 53 | // Callbacks 54 | CanReceiveCallback m_cbCanReceive = nullptr; 55 | ReceiveCallback m_cbReceive = nullptr; 56 | EventCallback m_cbEvent = nullptr; 57 | void *m_handler; 58 | protected: 59 | bool m_open; 60 | 61 | int CanReceive() { 62 | if (m_cbCanReceive != nullptr && m_handler != nullptr) { 63 | return m_cbCanReceive(m_handler); 64 | } 65 | return 0; 66 | } 67 | 68 | void Receive(const uint8_t *buf, int size) { 69 | if (m_cbReceive != nullptr && m_handler != nullptr) { 70 | m_cbReceive(m_handler, buf, size); 71 | } 72 | } 73 | 74 | void Event(int event) { 75 | // Keep track if the char device is open 76 | switch (event) { 77 | case CHR_EVENT_OPENED: 78 | m_open = true; 79 | break; 80 | case CHR_EVENT_CLOSED: 81 | m_open = false; 82 | break; 83 | } 84 | 85 | if (m_cbEvent) { 86 | m_cbEvent(m_handler, event); 87 | } 88 | } 89 | }; 90 | 91 | } 92 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/hw/ata/drvs/drv_vdvd_base.h: -------------------------------------------------------------------------------- 1 | // ATA/ATAPI-4 emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement a subset of the ATA/ATAPI-4 specification 5 | // that satisifies the requirements of an IDE interface for the Original Xbox. 6 | // 7 | // Specification: 8 | // http://www.t13.org/documents/UploadedDocuments/project/d1153r18-ATA-ATAPI-4.pdf 9 | // 10 | // References to particular items in the specification are denoted between brackets 11 | // optionally followed by a quote from the specification. 12 | #pragma once 13 | 14 | #include 15 | 16 | #include "ata_device_driver.h" 17 | 18 | namespace strikebox { 19 | namespace hw { 20 | namespace ata { 21 | 22 | /*! 23 | * Base class for virtual DVD drive ATA device drivers. 24 | */ 25 | class BaseDVDDriveATADeviceDriver : public IATADeviceDriver { 26 | public: 27 | BaseDVDDriveATADeviceDriver(); 28 | virtual ~BaseDVDDriveATADeviceDriver() override; 29 | 30 | // ----- ATA commands ----------------------------------------------------- 31 | 32 | void IdentifyDevice(IdentifyDeviceData *data) override; 33 | bool IdentifyPacketDevice(IdentifyPacketDeviceData *data) override; 34 | bool SecurityUnlock(uint8_t unlockData[kSectorSize]) override; 35 | bool SetDeviceParameters(uint8_t heads, uint8_t sectorsPerTrack) override; 36 | 37 | // ----- Data access ------------------------------------------------------ 38 | 39 | virtual bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override = 0; 40 | bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override; 41 | 42 | // ----- Feature sets ----------------------------------------------------- 43 | 44 | bool SupportsPacketCommands() override { return true; } 45 | bool SupportsOverlap() override { return false; } 46 | bool IsOverlapEnabled() override { return false; } 47 | 48 | // ----- Medium ----------------------------------------------------------- 49 | 50 | virtual bool HasMedium() override = 0; 51 | virtual uint32_t GetMediumCapacitySectors() override = 0; 52 | uint32_t GetSectorSize() override { return atapi::kDVDSectorSize; } 53 | 54 | // ----- Utility functions ------------------------------------------------ 55 | 56 | bool IsAttached() override { return true; } 57 | bool IsLBAAddressUserAccessible(uint32_t lbaAddress) override; 58 | uint32_t CHSToLBA(uint32_t cylinder, uint8_t head, uint8_t sector) override; 59 | void LBAToCHS(uint32_t lbaAddress, uint16_t *cylinder, uint8_t *head, uint8_t *sector) override; 60 | uint8_t GetPacketCommandSize() override; 61 | }; 62 | 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/atapi/atapi_common.cpp: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #include "strikebox/hw/atapi/atapi_common.h" 30 | 31 | namespace strikebox { 32 | namespace hw { 33 | namespace atapi { 34 | 35 | PacketCommandState::DataBuffer::~DataBuffer() { 36 | if (m_buf != nullptr) { 37 | delete[] m_buf; 38 | } 39 | } 40 | 41 | bool PacketCommandState::DataBuffer::Allocate(uint32_t size) { 42 | // Should allocate only once 43 | assert(m_buf == nullptr); 44 | 45 | m_buf = new uint8_t[size]; 46 | if (m_buf == nullptr) { 47 | return false; 48 | } 49 | m_size = 0; 50 | m_cap = size; 51 | Clear(); 52 | return true; 53 | } 54 | 55 | uint32_t PacketCommandState::DataBuffer::Read(void *dst, uint32_t length) { 56 | assert(m_buf != nullptr); 57 | 58 | // Truncate to data length 59 | if (length + m_readPos > m_size) { 60 | length = m_size - m_readPos; 61 | } 62 | memcpy(dst, m_buf + m_readPos, length); 63 | m_readPos += length; 64 | return length; 65 | } 66 | 67 | uint32_t PacketCommandState::DataBuffer::Write(void *src, uint32_t length) { 68 | assert(m_buf != nullptr); 69 | 70 | // Truncate to allocation length 71 | if (length + m_writePos > m_cap) { 72 | length = m_cap - m_writePos; 73 | } 74 | memcpy(m_buf, src, length); 75 | m_size = length; 76 | return length; 77 | } 78 | 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /modules/core/include/strikebox/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace strikebox { 8 | 9 | class IOMapper; 10 | 11 | /*! 12 | * Abstract base class that represents devices that respond to port-mapped 13 | * and/or memory-mapped I/O. 14 | * 15 | * I/O functions return true if the I/O operation was handled by the device. 16 | * 17 | * The default implementations read the value 0 and don't handle I/O. 18 | */ 19 | class IODevice { 20 | public: 21 | virtual bool MapIO(IOMapper *mapper) = 0; 22 | 23 | virtual bool IORead(uint32_t port, uint32_t *value, uint8_t size); 24 | virtual bool IOWrite(uint32_t port, uint32_t value, uint8_t size); 25 | 26 | virtual bool MMIORead(uint32_t addr, uint32_t *value, uint8_t size); 27 | virtual bool MMIOWrite(uint32_t addr, uint32_t value, uint8_t size); 28 | }; 29 | 30 | /*! 31 | * A mapped I/O device with specified I/O or MMIO ranges. 32 | */ 33 | struct MappedDevice { 34 | // I/O or MMIO addresses 35 | uint32_t baseAddress; 36 | uint32_t lastAddress; 37 | 38 | // The device itself 39 | IODevice *device; 40 | }; 41 | 42 | /*! 43 | * Maps I/O and MMIO reads and writes to the corresponding devices. 44 | */ 45 | class IOMapper { 46 | public: 47 | /*! 48 | * Maps a device to the specified range of ports. 49 | */ 50 | bool MapIODevice(uint32_t basePort, uint32_t numPorts, IODevice *device); 51 | 52 | /*! 53 | * Maps a device to the specified MMIO range. 54 | */ 55 | bool MapMMIODevice(uint32_t baseAddress, uint32_t numAddresses, IODevice *device); 56 | 57 | /*! 58 | * Adds a device with dynamic I/O address mapping. 59 | */ 60 | bool AddDevice(IODevice *device); 61 | 62 | bool IORead(uint32_t addr, uint32_t *value, uint8_t size); 63 | bool IOWrite(uint32_t addr, uint32_t value, uint8_t size); 64 | 65 | bool MMIORead(uint32_t addr, uint32_t *value, uint8_t size); 66 | bool MMIOWrite(uint32_t addr, uint32_t value, uint8_t size); 67 | 68 | private: 69 | /*! 70 | * Looks up the I/O device mapped to the specified I/O or MMIO address, 71 | * depending on the map used. 72 | * 73 | * Returns true if found. 74 | */ 75 | bool LookupDevice(std::map& iomap, uint32_t addr, IODevice **device); 76 | 77 | /*! 78 | * Maps a device to the specified address range. 79 | */ 80 | bool MapDevice(std::map& iomap, uint32_t base, uint32_t size, IODevice *device); 81 | 82 | std::map m_mappedIODevices; 83 | std::map m_mappedMMIODevices; 84 | std::set m_dynamicDevices; 85 | }; 86 | 87 | } 88 | -------------------------------------------------------------------------------- /modules/core/src/common/strikebox/hw/atapi/cmds/cmd_read_capacity.cpp: -------------------------------------------------------------------------------- 1 | // ATAPI Command set emulation for the Original Xbox 2 | // (C) Ivan "StrikerX3" Oliveira 3 | // 4 | // This code aims to implement the subset of the ATAPI Command set used by the 5 | // Original Xbox to access the DVD drive. 6 | // 7 | // Based on: 8 | // [p] SCSI Primary Commands - 3 (SPC-3) Draft 9 | // http://t10.org/ftp/t10/document.08/08-309r1.pdf 10 | // 11 | // [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g 12 | // https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf 13 | // 14 | // [b] SCSI Block Commands - 3 (SBC-3) Revision 25 15 | // http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf 16 | // 17 | // [a] SCSI Architecture Model - 3 (SAM-3) Revision 13 18 | // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf 19 | // 20 | // [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed 21 | // http://www.bswd.com/sff8020i.pdf 22 | // 23 | // [s] SCSI Commands Reference Manual 100293068, Rev. J 24 | // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf 25 | // 26 | // References to particular items in the specification are denoted between brackets 27 | // optionally followed by a quote from the specification. References are prefixed by 28 | // the letter in brackets as listed above. 29 | #include "strikebox/hw/atapi/cmds/cmd_read_capacity.h" 30 | 31 | #include "strikebox/log.h" 32 | 33 | namespace strikebox { 34 | namespace hw { 35 | namespace atapi { 36 | namespace cmd { 37 | 38 | ReadCapacity::ReadCapacity(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) 39 | : ATAPIDataInCommand(packetCmdState, driver) 40 | { 41 | } 42 | 43 | ReadCapacity::~ReadCapacity() { 44 | } 45 | 46 | bool ReadCapacity::BeginTransfer() { 47 | auto& cdb = m_packetCmdState.cdb.readCapacity; 48 | ReadCapacityData capData = { 0 }; 49 | 50 | if (m_driver->HasMedium()) { 51 | L2B32(capData.lba, m_driver->GetMediumCapacitySectors()); 52 | L2B32(capData.blockLength, m_driver->GetSectorSize()); 53 | } 54 | else { 55 | // Say that there is no disc in the drive 56 | m_packetCmdState.result.status = StCheckCondition; 57 | m_packetCmdState.result.senseKey = SKNotReady; 58 | m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent; 59 | 60 | L2B32(capData.lba, 0); 61 | L2B32(capData.blockLength, 0); 62 | } 63 | m_packetCmdState.dataBuffer.Write(&capData, sizeof(capData)); 64 | EndTransfer(); 65 | 66 | return true; 67 | } 68 | 69 | uint32_t ReadCapacity::GetAllocationLength(CommandDescriptorBlock *cdb) { 70 | return sizeof(ReadCapacityData); 71 | } 72 | 73 | } 74 | } 75 | } 76 | } 77 | --------------------------------------------------------------------------------