diff options
Diffstat (limited to 'src/SPI.cpp')
-rw-r--r-- | src/SPI.cpp | 338 |
1 files changed, 125 insertions, 213 deletions
diff --git a/src/SPI.cpp b/src/SPI.cpp index 1a4c12e..8eb8b0e 100644 --- a/src/SPI.cpp +++ b/src/SPI.cpp @@ -29,18 +29,6 @@ using namespace Platform; -namespace SPI_Firmware -{ - -std::unique_ptr<Firmware> Firmware; - -u32 Hold; -u8 CurCmd; -u32 DataPos; -u8 Data; - -u8 StatusReg; -u32 Addr; u16 CRC16(const u8* data, u32 len, u32 start) { @@ -65,7 +53,9 @@ u16 CRC16(const u8* data, u32 len, u32 start) return start & 0xFFFF; } -bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) + + +bool FirmwareMem::VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) { u16 crc_stored = *(u16*)&Firmware->Buffer()[crcoffset]; u16 crc_calced = CRC16(&Firmware->Buffer()[offset], len, start); @@ -73,40 +63,16 @@ bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset) } -bool Init() +FirmwareMem::FirmwareMem(SPIHost* host) : SPIDevice(host) { - return true; } -void DeInit() +FirmwareMem::~FirmwareMem() { RemoveFirmware(); } -u32 FixFirmwareLength(u32 originalLength) -{ - if (originalLength != 0x20000 && originalLength != 0x40000 && originalLength != 0x80000) - { - Log(LogLevel::Warn, "Bad firmware size %d, ", originalLength); - - // pick the nearest power-of-two length - originalLength |= (originalLength >> 1); - originalLength |= (originalLength >> 2); - originalLength |= (originalLength >> 4); - originalLength |= (originalLength >> 8); - originalLength |= (originalLength >> 16); - originalLength++; - - // ensure it's a sane length - if (originalLength > 0x80000) originalLength = 0x80000; - else if (originalLength < 0x20000) originalLength = 0x20000; - - Log(LogLevel::Debug, "assuming %d\n", originalLength); - } - return originalLength; -} - -void Reset() +void FirmwareMem::Reset() { if (!Firmware) { @@ -115,7 +81,7 @@ void Reset() } // fix touchscreen coords - for (UserData& u : Firmware->UserData()) + for (auto& u : Firmware->GetUserData()) { u.TouchCalibrationADC1[0] = 0; u.TouchCalibrationADC1[1] = 0; @@ -132,7 +98,7 @@ void Reset() // disable autoboot //Firmware[userdata+0x64] &= 0xBF; - MacAddress mac = Firmware->Header().MacAddress; + MacAddress mac = Firmware->GetHeader().MacAddress; Log(LogLevel::Info, "MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); // verify shit @@ -150,14 +116,14 @@ void Reset() StatusReg = 0x00; } -void DoSavestate(Savestate* file) +void FirmwareMem::DoSavestate(Savestate* file) { file->Section("SPFW"); // CHECKME/TODO: trust the firmware to stay the same????? // embedding the whole firmware in the savestate would be derpo tho?? - file->Var32(&Hold); + file->Bool32(&Hold); file->Var8(&CurCmd); file->Var32(&DataPos); file->Var8(&Data); @@ -166,10 +132,10 @@ void DoSavestate(Savestate* file) file->Var32(&Addr); } -void SetupDirectBoot(bool dsi) +void FirmwareMem::SetupDirectBoot(bool dsi) { - const FirmwareHeader& header = Firmware->Header(); - const UserData& userdata = Firmware->EffectiveUserData(); + const auto& header = Firmware->GetHeader(); + const auto& userdata = Firmware->GetEffectiveUserData(); if (dsi) { for (u32 i = 0; i < 6; i += 2) @@ -194,17 +160,17 @@ void SetupDirectBoot(bool dsi) } } -const class Firmware* GetFirmware() +const class Firmware* FirmwareMem::GetFirmware() { return Firmware.get(); } -bool IsLoadedFirmwareBuiltIn() +bool FirmwareMem::IsLoadedFirmwareBuiltIn() { - return Firmware->Header().Identifier == GENERATED_FIRMWARE_IDENTIFIER; + return Firmware->GetHeader().Identifier == GENERATED_FIRMWARE_IDENTIFIER; } -bool InstallFirmware(class Firmware&& firmware) +bool FirmwareMem::InstallFirmware(class Firmware&& firmware) { if (!firmware.Buffer()) { @@ -214,13 +180,13 @@ bool InstallFirmware(class Firmware&& firmware) Firmware = std::make_unique<class Firmware>(std::move(firmware)); - FirmwareIdentifier id = Firmware->Header().Identifier; + FirmwareIdentifier id = Firmware->GetHeader().Identifier; Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]); return true; } -bool InstallFirmware(std::unique_ptr<class Firmware>&& firmware) +bool FirmwareMem::InstallFirmware(std::unique_ptr<class Firmware>&& firmware) { if (!firmware) { @@ -236,40 +202,42 @@ bool InstallFirmware(std::unique_ptr<class Firmware>&& firmware) Firmware = std::move(firmware); - FirmwareIdentifier id = Firmware->Header().Identifier; + FirmwareIdentifier id = Firmware->GetHeader().Identifier; Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]); return true; } -void RemoveFirmware() +void FirmwareMem::RemoveFirmware() { Firmware.reset(); Log(LogLevel::Debug, "Removed installed firmware (if any)\n"); } -u8 Read() -{ - return Data; -} - -void Write(u8 val, u32 hold) +void FirmwareMem::Write(u8 val) { - if (!hold) - { - if (!Hold) // commands with no paramters - CurCmd = val; - - Hold = 0; - } - - if (hold && (!Hold)) + if (!Hold) { CurCmd = val; - Hold = 1; + Hold = true; Data = 0; DataPos = 1; Addr = 0; + + // handle commands with no parameters + switch (CurCmd) + { + case 0x04: // write disable + StatusReg &= ~(1<<1); + Data = 0; + break; + + case 0x06: // write enable + StatusReg |= (1<<1); + Data = 0; + break; + } + return; } @@ -293,20 +261,10 @@ void Write(u8 val, u32 hold) } break; - case 0x04: // write disable - StatusReg &= ~(1<<1); - Data = 0; - break; - case 0x05: // read status reg Data = StatusReg; break; - case 0x06: // write enable - StatusReg |= (1<<1); - Data = 0; - break; - case 0x0A: // write { // TODO: what happens if you write too many bytes? (max 256, they say) @@ -345,45 +303,38 @@ void Write(u8 val, u32 hold) Data = 0xFF; break; } +} - if (!hold && (CurCmd == 0x02 || CurCmd == 0x0A)) +void FirmwareMem::Release() +{ + if (CurCmd == 0x02 || CurCmd == 0x0A) { // If the SPI firmware chip just finished a write... // We only notify the frontend of changes to the Wi-fi/userdata settings region // (although it might still decide to flush the whole thing) - u32 wifioffset = Firmware->WifiAccessPointOffset(); + u32 wifioffset = Firmware->GetWifiAccessPointOffset(); // Request that the start of the Wi-fi/userdata settings region // through the end of the firmware blob be flushed to disk Platform::WriteFirmware(*Firmware, wifioffset, Firmware->Length() - wifioffset); } -} + SPIDevice::Release(); + CurCmd = 0; } -namespace SPI_Powerman -{ - -u32 Hold; -u32 DataPos; -u8 Index; -u8 Data; - -u8 Registers[8]; -u8 RegMasks[8]; -bool Init() +PowerMan::PowerMan(SPIHost* host) : SPIDevice(host) { - return true; } -void DeInit() +PowerMan::~PowerMan() { } -void Reset() +void PowerMan::Reset() { - Hold = 0; + Hold = false; Index = 0; Data = 0; @@ -399,14 +350,11 @@ void Reset() RegMasks[4] = 0x0F; } -bool GetBatteryLevelOkay() { return !Registers[1]; } -void SetBatteryLevelOkay(bool okay) { Registers[1] = okay ? 0x00 : 0x01; } - -void DoSavestate(Savestate* file) +void PowerMan::DoSavestate(Savestate* file) { file->Section("SPPW"); - file->Var32(&Hold); + file->Bool32(&Hold); file->Var32(&DataPos); file->Var8(&Index); file->Var8(&Data); @@ -415,22 +363,15 @@ void DoSavestate(Savestate* file) file->VarArray(RegMasks, 8); // is that needed?? } -u8 Read() -{ - return Data; -} +bool PowerMan::GetBatteryLevelOkay() { return !Registers[1]; } +void PowerMan::SetBatteryLevelOkay(bool okay) { Registers[1] = okay ? 0x00 : 0x01; } -void Write(u8 val, u32 hold) +void PowerMan::Write(u8 val) { - if (!hold) - { - Hold = 0; - } - - if (hold && (!Hold)) + if (!Hold) { Index = val; - Hold = 1; + Hold = true; Data = 0; DataPos = 1; return; @@ -465,35 +406,19 @@ void Write(u8 val, u32 hold) Data = 0; } -} - - -namespace SPI_TSC -{ - -u32 DataPos; -u8 ControlByte; -u8 Data; - -u16 ConvResult; - -u16 TouchX, TouchY; -s16 MicBuffer[1024]; -int MicBufferLen; - -bool Init() +TSC::TSC(SPIHost* host) : SPIDevice(host) { - return true; } -void DeInit() +TSC::~TSC() { } -void Reset() +void TSC::Reset() { + Hold = false; ControlByte = 0; Data = 0; @@ -502,7 +427,7 @@ void Reset() MicBufferLen = 0; } -void DoSavestate(Savestate* file) +void TSC::DoSavestate(Savestate* file) { file->Section("SPTS"); @@ -513,7 +438,7 @@ void DoSavestate(Savestate* file) file->Var16(&ConvResult); } -void SetTouchCoords(u16 x, u16 y) +void TSC::SetTouchCoords(u16 x, u16 y) { // scr.x = (adc.x-adc.x1) * (scr.x2-scr.x1) / (adc.x2-adc.x1) + (scr.x1-1) // scr.y = (adc.y-adc.y1) * (scr.y2-scr.y1) / (adc.y2-adc.y1) + (scr.y1-1) @@ -522,13 +447,19 @@ void SetTouchCoords(u16 x, u16 y) TouchX = x; TouchY = y; - if (y == 0xFFF) return; + if (y == 0xFFF) + { + // released + NDS::KeyInput |= (1 << (16+6)); + return; + } TouchX <<= 4; TouchY <<= 4; + NDS::KeyInput &= ~(1 << (16+6)); } -void MicInputFrame(s16* data, int samples) +void TSC::MicInputFrame(s16* data, int samples) { if (!data) { @@ -541,12 +472,7 @@ void MicInputFrame(s16* data, int samples) MicBufferLen = samples; } -u8 Read() -{ - return Data; -} - -void Write(u8 val, u32 hold) +void TSC::Write(u8 val) { if (DataPos == 1) Data = (ConvResult >> 5) & 0xFF; @@ -599,79 +525,71 @@ void Write(u8 val, u32 hold) DataPos++; } -} - - -namespace SPI -{ - -u16 Cnt; - -u32 CurDevice; // remove me -bool Init() +SPIHost::SPIHost() { - NDS::RegisterEventFunc(NDS::Event_SPITransfer, 0, TransferDone); - - if (!SPI_Firmware::Init()) return false; - if (!SPI_Powerman::Init()) return false; - if (!SPI_TSC::Init()) return false; - if (!DSi_SPI_TSC::Init()) return false; + NDS::RegisterEventFunc(NDS::Event_SPITransfer, 0, MemberEventFunc(SPIHost, TransferDone)); - return true; + Devices[SPIDevice_FirmwareMem] = new FirmwareMem(this); + Devices[SPIDevice_PowerMan] = new PowerMan(this); + Devices[SPIDevice_TSC] = nullptr; } -void DeInit() +SPIHost::~SPIHost() { - SPI_Firmware::DeInit(); - SPI_Powerman::DeInit(); - SPI_TSC::DeInit(); - DSi_SPI_TSC::DeInit(); + for (int i = 0; i < SPIDevice_MAX; i++) + { + if (Devices[i]) + delete Devices[i]; + + Devices[i] = nullptr; + } NDS::UnregisterEventFunc(NDS::Event_SPITransfer, 0); } -void Reset() +void SPIHost::Reset() { Cnt = 0; - SPI_Firmware::Reset(); - SPI_Powerman::Reset(); - SPI_TSC::Reset(); - if (NDS::ConsoleType == 1) DSi_SPI_TSC::Reset(); + if (Devices[SPIDevice_TSC]) + delete Devices[SPIDevice_TSC]; + + if (NDS::ConsoleType == 1) + Devices[SPIDevice_TSC] = new DSi_TSC(this); + else + Devices[SPIDevice_TSC] = new TSC(this); + + for (int i = 0; i < SPIDevice_MAX; i++) + { + Devices[i]->Reset(); + } } -void DoSavestate(Savestate* file) +void SPIHost::DoSavestate(Savestate* file) { file->Section("SPIG"); file->Var16(&Cnt); - file->Var32(&CurDevice); - SPI_Firmware::DoSavestate(file); - SPI_Powerman::DoSavestate(file); - SPI_TSC::DoSavestate(file); - if (NDS::ConsoleType == 1) DSi_SPI_TSC::DoSavestate(file); + for (int i = 0; i < SPIDevice_MAX; i++) + { + Devices[i]->DoSavestate(file); + } } -void WriteCnt(u16 val) +void SPIHost::WriteCnt(u16 val) { // turning it off should clear chipselect // TODO: confirm on hardware. libnds expects this, though. if ((Cnt & (1<<15)) && !(val & (1<<15))) { - switch (Cnt & 0x0300) + int dev = (Cnt >> 8) & 0x3; + if (dev < SPIDevice_MAX) { - case 0x0000: SPI_Powerman::Hold = 0; break; - case 0x0100: SPI_Firmware::Hold = 0; break; - case 0x0200: - if (NDS::ConsoleType == 1) - DSi_SPI_TSC::DataPos = 0; - else - SPI_TSC::DataPos = 0; - break; + Devices[dev]->Release(); } } @@ -682,7 +600,7 @@ void WriteCnt(u16 val) if (Cnt & (1<<7)) Log(LogLevel::Warn, "!! CHANGING SPICNT DURING TRANSFER: %04X\n", val); } -void TransferDone(u32 param) +void SPIHost::TransferDone(u32 param) { Cnt &= ~(1<<7); @@ -690,46 +608,40 @@ void TransferDone(u32 param) NDS::SetIRQ(1, NDS::IRQ_SPI); } -u8 ReadData() +u8 SPIHost::ReadData() { if (!(Cnt & (1<<15))) return 0; if (Cnt & (1<<7)) return 0; // checkme - switch (Cnt & 0x0300) + int dev = (Cnt >> 8) & 0x3; + if (dev < SPIDevice_MAX) { - case 0x0000: return SPI_Powerman::Read(); - case 0x0100: return SPI_Firmware::Read(); - case 0x0200: - if (NDS::ConsoleType == 1) - return DSi_SPI_TSC::Read(); - else - return SPI_TSC::Read(); - default: return 0; + return Devices[dev]->Read(); } + + return 0; } -void WriteData(u8 val) +void SPIHost::WriteData(u8 val) { if (!(Cnt & (1<<15))) return; if (Cnt & (1<<7)) return; Cnt |= (1<<7); - switch (Cnt & 0x0300) + + int dev = (Cnt >> 8) & 0x3; + if (dev < SPIDevice_MAX) { - case 0x0000: SPI_Powerman::Write(val, Cnt&(1<<11)); break; - case 0x0100: SPI_Firmware::Write(val, Cnt&(1<<11)); break; - case 0x0200: - if (NDS::ConsoleType == 1) - DSi_SPI_TSC::Write(val, Cnt&(1<<11)); - else - SPI_TSC::Write(val, Cnt&(1<<11)); - break; - default: Log(LogLevel::Warn, "SPI to unknown device %04X %02X\n", Cnt, val); break; + Devices[dev]->Write(val); + if (!(Cnt & (1<<11))) // release chipselect + Devices[dev]->Release(); + } + else + { + Log(LogLevel::Warn, "SPI to unknown device %04X %02X\n", Cnt, val); } // SPI transfers one bit per cycle -> 8 cycles per byte u32 delay = 8 * (8 << (Cnt & 0x3)); NDS::ScheduleEvent(NDS::Event_SPITransfer, false, delay, 0, 0); } - -} |