From 58e3ff61ac31a6ac20e12d03c518a6c16715e83c Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 15 Jun 2019 16:58:02 +0200 Subject: add I2C shito --- src/DSi_I2C.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/DSi_I2C.cpp (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp new file mode 100644 index 0000000..1836c31 --- /dev/null +++ b/src/DSi_I2C.cpp @@ -0,0 +1,185 @@ +/* + Copyright 2016-2019 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include +#include "DSi.h" +#include "DSi_I2C.h" + + +namespace DSi_BPTWL +{ + +u8 Registers[0x100]; +u32 CurPos; + +bool Init() +{ + return true; +} + +void DeInit() +{ +} + +void Reset() +{ + CurPos = 0; + memset(Registers, 0x5A, 0x100); + + Registers[0x00] = 0x33; // TODO: support others?? + Registers[0x01] = 0x00; + Registers[0x02] = 0x50; + Registers[0x10] = 0x00; // power btn + Registers[0x11] = 0x00; // reset + Registers[0x12] = 0x00; // power btn tap + Registers[0x20] = 0x83; // battery + Registers[0x21] = 0x07; + Registers[0x30] = 0x13; + Registers[0x31] = 0x00; // camera power + Registers[0x40] = 0x1F; // volume + Registers[0x41] = 0x04; // backlight + Registers[0x60] = 0x00; + Registers[0x61] = 0x01; + Registers[0x62] = 0x50; + Registers[0x63] = 0x00; + Registers[0x70] = 0x00; // boot flag + Registers[0x71] = 0x00; + Registers[0x72] = 0x00; + Registers[0x73] = 0x00; + Registers[0x74] = 0x00; + Registers[0x75] = 0x00; + Registers[0x76] = 0x00; + Registers[0x77] = 0x00; + Registers[0x80] = 0x10; + Registers[0x81] = 0x64; +} + +void Start() +{ + CurPos = 0; +} + +u8 Read(bool last) +{ + return Registers[CurPos++]; +} + +void Write(u8 val, bool last) +{ + if (CurPos == 0x11 || CurPos == 0x12 || + CurPos == 0x21 || + CurPos == 0x30 || CurPos == 0x31 || + CurPos == 0x40 || CurPos == 0x31 || + CurPos == 0x60 || CurPos == 0x63 || + (CurPos >= 0x70 && CurPos <= 0x77) || + CurPos == 0x80 || CurPos == 0x81) + { + Registers[CurPos] = val; + } + + CurPos++; +} + +} + + +namespace DSi_I2C +{ + +u8 Cnt; +u32 Device; + +bool Init() +{ + if (!DSi_BPTWL::Init()) return false; + + return true; +} + +void DeInit() +{ + DSi_BPTWL::DeInit(); +} + +void Reset() +{ + Device = -1; + + DSi_BPTWL::Reset(); +} + +void WriteCnt(u8 val) +{ + val &= 0xF7; + // TODO: check ACK flag + // TODO: transfer delay + + if (val & (1<<7)) + { + if (val & (1<<2)) + { + Device = -1; + printf("I2C: start\n"); + } + } + + Cnt = val; +} + +u8 ReadData() +{ + switch (Device) + { + case 0x4A: return DSi_BPTWL::Read(Cnt & (1<<0)); + + default: + printf("I2C: read from unknown device %02X\n", Device); + break; + } + + return 0; +} + +void WriteData(u8 val) +{ + if (Device == -1) + { + Device = val; + switch (Device) + { + case 0x4A: DSi_BPTWL::Start(); return; + + default: + printf("I2C: start on unknown device %02X\n", Device); + break; + } + return; + } + + switch (Device) + { + case 0x4A: DSi_BPTWL::Write(val, Cnt & (1<<0)); return; + + default: + printf("I2C: write to unknown device %02X\n", Device); + break; + } +} + +} -- cgit v1.2.3 From 93330d267037460a2af25744ab169ebc31d1d45f Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 15 Jun 2019 17:23:48 +0200 Subject: fix I2C shit? I think --- src/DSi.cpp | 4 +++ src/DSi_I2C.cpp | 82 +++++++++++++++++++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 35 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index 057d229..3ec5ab1 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -59,6 +59,10 @@ u32 NWRAMMask[2][3]; void Reset() { + //NDS::ARM9->CP15Write(0x910, 0x0D00000A); + //NDS::ARM9->CP15Write(0x911, 0x00000020); + //NDS::ARM9->CP15Write(0x100, NDS::ARM9->CP15Read(0x100) | 0x00050000); + NDS::ARM9->JumpTo(BootAddr[0]); NDS::ARM7->JumpTo(BootAddr[1]); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 1836c31..03fe85e 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -103,6 +103,8 @@ namespace DSi_I2C { u8 Cnt; +u8 Data; + u32 Device; bool Init() @@ -119,6 +121,9 @@ void DeInit() void Reset() { + Cnt = 0; + Data = 0; + Device = -1; DSi_BPTWL::Reset(); @@ -126,17 +131,54 @@ void Reset() void WriteCnt(u8 val) { + printf("I2C: write CNT %02X\n", val); + val &= 0xF7; // TODO: check ACK flag // TODO: transfer delay + // TODO: IRQ + // TODO: check read/write direction if (val & (1<<7)) { - if (val & (1<<2)) + bool islast = Cnt & (1<<0); + + if (val & (1<<5)) + { + // read + printf("I2C read, device=%02X, cnt=%02X, last=%d\n", Device, Cnt, islast); + + switch (Device) + { + case 0x4A: Data = DSi_BPTWL::Read(islast); break; + default: Data = 0; break; + } + } + else { - Device = -1; - printf("I2C: start\n"); + // write + printf("I2C write, device=%02X, cnt=%02X, last=%d\n", Device, Cnt, islast); + + if (val & (1<<1)) + { + Device = Data; + printf("I2C: start, device=%02X\n", Device); + + switch (Device) + { + case 0x4A: DSi_BPTWL::Start(); return; + } + } + else + { + switch (Device) + { + case 0x4A: DSi_BPTWL::Write(Data, islast); break; + } + } } + + val &= 0x7F; } Cnt = val; @@ -144,42 +186,12 @@ void WriteCnt(u8 val) u8 ReadData() { - switch (Device) - { - case 0x4A: return DSi_BPTWL::Read(Cnt & (1<<0)); - - default: - printf("I2C: read from unknown device %02X\n", Device); - break; - } - - return 0; + return Data; } void WriteData(u8 val) { - if (Device == -1) - { - Device = val; - switch (Device) - { - case 0x4A: DSi_BPTWL::Start(); return; - - default: - printf("I2C: start on unknown device %02X\n", Device); - break; - } - return; - } - - switch (Device) - { - case 0x4A: DSi_BPTWL::Write(val, Cnt & (1<<0)); return; - - default: - printf("I2C: write to unknown device %02X\n", Device); - break; - } + Data = val; } } -- cgit v1.2.3 From 4d3f346edcd8b7edff2415d7c90903c54d4ee34f Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 15 Jun 2019 18:30:12 +0200 Subject: get it to do more interesting things --- src/ARM.cpp | 4 +++- src/DSi.cpp | 1 + src/DSi_I2C.cpp | 19 ++++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/ARM.cpp b/src/ARM.cpp index 870c455..ee72fbe 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -175,7 +175,7 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) // aging cart debug crap //if (addr == 0x0201764C) printf("capture test %d: R1=%08X\n", R[6], R[1]); //if (addr == 0x020175D8) printf("capture test %d: res=%08X\n", R[6], R[0]); - if (addr==0x037CA0D0) printf("VLORP %08X\n", R[15]); + //if (addr==0x037CA0D0) printf("VLORP %08X\n", R[15]); u32 oldregion = R[15] >> 24; u32 newregion = addr >> 24; @@ -243,6 +243,8 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr) else addr &= ~0x1; } + //if (addr==0x037D5A18) printf("SHITTY FUNC. %08X\n", R[15]); + u32 oldregion = R[15] >> 23; u32 newregion = addr >> 23; diff --git a/src/DSi.cpp b/src/DSi.cpp index 3ec5ab1..0472f1d 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -817,6 +817,7 @@ u16 ARM9IORead16(u32 addr) { switch (addr) { + case 0x04004004: return 0; // TODO } return NDS::ARM9IORead16(addr); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 03fe85e..4a4f1e7 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -133,7 +133,6 @@ void WriteCnt(u8 val) { printf("I2C: write CNT %02X\n", val); - val &= 0xF7; // TODO: check ACK flag // TODO: transfer delay // TODO: IRQ @@ -141,41 +140,47 @@ void WriteCnt(u8 val) if (val & (1<<7)) { - bool islast = Cnt & (1<<0); + bool islast = val & (1<<0); if (val & (1<<5)) { // read - printf("I2C read, device=%02X, cnt=%02X, last=%d\n", Device, Cnt, islast); + val &= 0xF7; switch (Device) { case 0x4A: Data = DSi_BPTWL::Read(islast); break; default: Data = 0; break; } + + printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); } else { // write - printf("I2C write, device=%02X, cnt=%02X, last=%d\n", Device, Cnt, islast); + val &= 0xE7; if (val & (1<<1)) { - Device = Data; - printf("I2C: start, device=%02X\n", Device); + Device = Data & 0xFE; + printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); switch (Device) { - case 0x4A: DSi_BPTWL::Start(); return; + case 0x4A: DSi_BPTWL::Start(); break; } } else { + printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + switch (Device) { case 0x4A: DSi_BPTWL::Write(Data, islast); break; } } + + val |= (1<<4); } val &= 0x7F; -- cgit v1.2.3 From 7b19a012040185a28474b6782da206c46a53c614 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 15 Jun 2019 18:39:34 +0200 Subject: betterer I2C --- src/DSi_I2C.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 4a4f1e7..b7b7022 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -39,7 +39,7 @@ void DeInit() void Reset() { - CurPos = 0; + CurPos = -1; memset(Registers, 0x5A, 0x100); Registers[0x00] = 0x33; // TODO: support others?? @@ -72,16 +72,36 @@ void Reset() void Start() { - CurPos = 0; + printf("BPTWL: start\n"); } u8 Read(bool last) { + if (last) + { + CurPos = -1; + return 0; + } + + printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); return Registers[CurPos++]; } void Write(u8 val, bool last) { + if (last) + { + CurPos = -1; + return; + } + + if (CurPos == -1) + { + CurPos = val; + printf("BPTWL: reg=%02X\n", val); + return; + } + if (CurPos == 0x11 || CurPos == 0x12 || CurPos == 0x21 || CurPos == 0x30 || CurPos == 0x31 || @@ -93,7 +113,8 @@ void Write(u8 val, bool last) Registers[CurPos] = val; } - CurPos++; + printf("BPTWL: write %02X -> %02X\n", CurPos, val); + CurPos++; // CHECKME } } -- cgit v1.2.3 From 78c41736c391f65d8e6af5492ee621c956c6ed01 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 16 Jun 2019 14:26:54 +0200 Subject: fix fucking ass-stupid bug with new-WRAM handling --- src/ARM.cpp | 6 ------ src/DSi.cpp | 27 ++++++++++++++++++++++++++- src/DSi_I2C.cpp | 1 + 3 files changed, 27 insertions(+), 7 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/ARM.cpp b/src/ARM.cpp index ee72fbe..b7fe3c7 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -175,7 +175,6 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) // aging cart debug crap //if (addr == 0x0201764C) printf("capture test %d: R1=%08X\n", R[6], R[1]); //if (addr == 0x020175D8) printf("capture test %d: res=%08X\n", R[6], R[0]); - //if (addr==0x037CA0D0) printf("VLORP %08X\n", R[15]); u32 oldregion = R[15] >> 24; u32 newregion = addr >> 24; @@ -222,9 +221,6 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) CPSR &= ~0x20; } - // TODO: investigate this - // firmware jumps to region 01FFxxxx, but region 5 (01000000-02000000) is set to non-executable - // is melonDS fucked up somewhere, or is the DS PU just incomplete/crapoed? /*if (!(PU_Map[addr>>12] & 0x04)) { printf("jumped to %08X. very bad\n", addr); @@ -243,8 +239,6 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr) else addr &= ~0x1; } - //if (addr==0x037D5A18) printf("SHITTY FUNC. %08X\n", R[15]); - u32 oldregion = R[15] >> 23; u32 newregion = addr >> 23; diff --git a/src/DSi.cpp b/src/DSi.cpp index 0472f1d..ae1bed2 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -484,16 +484,19 @@ void ARM9Write8(u32 addr, u8 val) { u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]]; if (ptr) *(u8*)&ptr[addr & 0xFFFF] = val; + return; } if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1]) { u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]]; if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val; + return; } if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2]) { u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]]; if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val; + return; } return NDS::ARM9Write8(addr, val); @@ -514,16 +517,19 @@ void ARM9Write16(u32 addr, u16 val) { u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]]; if (ptr) *(u16*)&ptr[addr & 0xFFFF] = val; + return; } if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1]) { u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]]; if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val; + return; } if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2]) { u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]]; if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val; + return; } return NDS::ARM9Write16(addr, val); @@ -544,16 +550,19 @@ void ARM9Write32(u32 addr, u32 val) { u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]]; if (ptr) *(u32*)&ptr[addr & 0xFFFF] = val; + return; } if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1]) { u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]]; if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val; + return; } if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2]) { u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]]; if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val; + return; } return NDS::ARM9Write32(addr, val); @@ -684,16 +693,19 @@ void ARM7Write8(u32 addr, u8 val) { u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]]; if (ptr) *(u8*)&ptr[addr & 0xFFFF] = val; + return; } if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1]) { u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]]; if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val; + return; } if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2]) { u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]]; if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val; + return; } return NDS::ARM7Write8(addr, val); @@ -714,16 +726,19 @@ void ARM7Write16(u32 addr, u16 val) { u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]]; if (ptr) *(u16*)&ptr[addr & 0xFFFF] = val; + return; } if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1]) { u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]]; if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val; + return; } if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2]) { u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]]; if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val; + return; } return NDS::ARM7Write16(addr, val); @@ -744,16 +759,19 @@ void ARM7Write32(u32 addr, u32 val) { u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]]; if (ptr) *(u32*)&ptr[addr & 0xFFFF] = val; + return; } if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1]) { u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]]; if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val; + return; } if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2]) { u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]]; if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val; + return; } return NDS::ARM7Write32(addr, val); @@ -827,6 +845,7 @@ u32 ARM9IORead32(u32 addr) { switch (addr) { + case 0x04004010: return 1; // todo } return NDS::ARM9IORead32(addr); @@ -864,8 +883,11 @@ u8 ARM7IORead8(u32 addr) { switch (addr) { + case 0x04004000: return 0x01; + case 0x04004001: return 0x01; + case 0x04004500: return DSi_I2C::ReadData(); - case 0x04004501: return DSi_I2C::Cnt; + case 0x04004501: printf("read I2C CNT %02X\n", DSi_I2C::Cnt); return DSi_I2C::Cnt; } return NDS::ARM7IORead8(addr); @@ -875,6 +897,8 @@ u16 ARM7IORead16(u32 addr) { switch (addr) { + case 0x04004004: return 0x0187; + case 0x04004006: return 0; // JTAG register } return NDS::ARM7IORead16(addr); @@ -884,6 +908,7 @@ u32 ARM7IORead32(u32 addr) { switch (addr) { + case 0x04004008: return 0x80000000; // HAX } return NDS::ARM7IORead32(addr); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index b7b7022..8b01b0e 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -212,6 +212,7 @@ void WriteCnt(u8 val) u8 ReadData() { + printf("I2C: read the data: %02X\n", Data); return Data; } -- cgit v1.2.3 From d943a51b9658e1898f49b6773f85778ae7348400 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 20 Jun 2019 03:19:51 +0200 Subject: ayyy getting there! --- src/DSi.cpp | 2 +- src/DSi_I2C.cpp | 9 ++++----- src/DSi_NDMA.cpp | 4 ++-- src/DSi_SD.cpp | 5 ++++- src/NDS.cpp | 4 ++-- 5 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index ee9d21c..0e35d53 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -1239,7 +1239,7 @@ u8 ARM7IORead8(u32 addr) CASE_READ8_32BIT(0x04004060, MBK[1][8]) case 0x04004500: return DSi_I2C::ReadData(); - case 0x04004501: printf("read I2C CNT %02X\n", DSi_I2C::Cnt); return DSi_I2C::Cnt; + case 0x04004501: return DSi_I2C::Cnt; case 0x04004D00: return ConsoleID & 0xFF; case 0x04004D01: return (ConsoleID >> 8) & 0xFF; diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 8b01b0e..845dd9d 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -152,7 +152,7 @@ void Reset() void WriteCnt(u8 val) { - printf("I2C: write CNT %02X\n", val); + //printf("I2C: write CNT %02X\n", val); // TODO: check ACK flag // TODO: transfer delay @@ -174,7 +174,7 @@ void WriteCnt(u8 val) default: Data = 0; break; } - printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); } else { @@ -184,7 +184,7 @@ void WriteCnt(u8 val) if (val & (1<<1)) { Device = Data & 0xFE; - printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); + //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); switch (Device) { @@ -193,7 +193,7 @@ void WriteCnt(u8 val) } else { - printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); switch (Device) { @@ -212,7 +212,6 @@ void WriteCnt(u8 val) u8 ReadData() { - printf("I2C: read the data: %02X\n", Data); return Data; } diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp index a62904a..37eb687 100644 --- a/src/DSi_NDMA.cpp +++ b/src/DSi_NDMA.cpp @@ -135,8 +135,8 @@ void DSi_NDMA::Start() // TODO eventually: not stop if we're running code in ITCM - if (SubblockTimer & 0xFFFF) - printf("TODO! NDMA SUBBLOCK TIMER: %08X\n", SubblockTimer); + //if (SubblockTimer & 0xFFFF) + // printf("TODO! NDMA SUBBLOCK TIMER: %08X\n", SubblockTimer); if (NDS::DMAsRunning(CPU)) Running = 1; diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index fbb2e14..3764a3c 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -218,6 +218,8 @@ u16 DSi_SDHost::Read(u32 addr) case 0x026: return BlockLen16; case 0x028: return SDOption; + case 0x02C: return 0; // TODO + case 0x030: // FIFO16 { // TODO: decrement BlockLen???? @@ -275,7 +277,7 @@ u16 DSi_SDHost::Read(u32 addr) case 0x108: return BlockCount32; } - printf("unknown %s read %08X\n", SD_DESC, addr); + printf("unknown %s read %08X @ %08X\n", SD_DESC, addr, NDS::GetPC(1)); return 0; } @@ -356,6 +358,7 @@ void DSi_SDHost::Write(u32 addr, u16 val) break; } } + else printf("%s: SENDING CMD %04X TO NULL DEVICE\n", SD_DESC, val); } return; diff --git a/src/NDS.cpp b/src/NDS.cpp index 6622373..61cf547 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1600,7 +1600,7 @@ void debug(u32 param) fwrite(&val, 4, 1, shit); } fclose(shit);*/ - FILE* + /*FILE* shit = fopen("debug/dump9.bin", "wb"); for (u32 i = 0x02000000; i < 0x04000000; i+=4) { @@ -1614,7 +1614,7 @@ void debug(u32 param) u32 val = DSi::ARM7Read32(i); fwrite(&val, 4, 1, shit); } - fclose(shit); + fclose(shit);*/ } -- cgit v1.2.3 From c5e14074c3b999d09b8a8612cfa7f011423e83ab Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 3 Jul 2019 12:37:34 +0200 Subject: * add SCFG_EXT * quick hack to detect cartridges --- src/DSi.cpp | 24 +++++++++++++++++++++--- src/DSi.h | 2 ++ src/DSi_I2C.cpp | 8 ++++---- src/NDSCart.cpp | 8 +++++--- 4 files changed, 32 insertions(+), 10 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index e601da9..26a67f4 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -46,6 +46,7 @@ u32 BootAddr[2]; u16 SCFG_Clock9; u16 SCFG_Clock7; +u32 SCFG_EXT[2]; u32 SCFG_MC; u32 MBK[2][9]; @@ -127,7 +128,9 @@ void Reset() SCFG_Clock9 = 0x0187; // CHECKME SCFG_Clock7 = 0x0187; - SCFG_MC = 0x0011; + SCFG_EXT[0] = 0x8307F100; + SCFG_EXT[1] = 0x93FFFB06; + SCFG_MC = 0x0010;//0x0011; // LCD init flag GPU::DispStat[0] |= (1<<6); @@ -1038,7 +1041,7 @@ u32 ARM9IORead32(u32 addr) { switch (addr) { - case 0x04004008: return 0x8307F100; + case 0x04004008: return SCFG_EXT[0]; case 0x04004010: return SCFG_MC & 0xFFFF; case 0x04004040: return MBK[0][0]; @@ -1183,6 +1186,14 @@ void ARM9IOWrite32(u32 addr, u32 val) { switch (addr) { + case 0x04004008: + SCFG_EXT[0] &= ~0x8007F19F; + SCFG_EXT[0] |= (val & 0x8007F19F); + SCFG_EXT[1] &= ~0x0000F080; + SCFG_EXT[1] |= (val & 0x0000F080); + printf("SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val); + return; + case 0x04004040: MapNWRAM_A(0, val & 0xFF); MapNWRAM_A(1, (val >> 8) & 0xFF); @@ -1333,7 +1344,7 @@ u32 ARM7IORead32(u32 addr) case 0x04000218: return NDS::IE2; case 0x0400021C: return NDS::IF2; - case 0x04004008: return 0x80000000; // HAX + case 0x04004008: return SCFG_EXT[1]; case 0x04004010: return SCFG_MC; case 0x04004040: return MBK[1][0]; @@ -1449,6 +1460,13 @@ void ARM7IOWrite32(u32 addr, u32 val) case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return; case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return; + case 0x04004008: + SCFG_EXT[0] &= ~0x03000000; + SCFG_EXT[0] |= (val & 0x03000000); + SCFG_EXT[1] &= ~0x93FF0F07; + SCFG_EXT[1] |= (val & 0x93FF0F07); + printf("SCFG_EXT = %08X / %08X (val7 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val); + return; case 0x04004010: val &= 0xFFFF800C; if ((val & 0xC) == 0xC) val &= ~0xC; // hax diff --git a/src/DSi.h b/src/DSi.h index 642a56a..db585b4 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -31,6 +31,8 @@ extern u64 ConsoleID; extern DSi_SDHost* SDMMC; extern DSi_SDHost* SDIO; +extern u8 ITCMInit[0x8000]; + bool Init(); void DeInit(); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 845dd9d..e88858b 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -72,7 +72,7 @@ void Reset() void Start() { - printf("BPTWL: start\n"); + //printf("BPTWL: start\n"); } u8 Read(bool last) @@ -83,7 +83,7 @@ u8 Read(bool last) return 0; } - printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); + //printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); return Registers[CurPos++]; } @@ -98,7 +98,7 @@ void Write(u8 val, bool last) if (CurPos == -1) { CurPos = val; - printf("BPTWL: reg=%02X\n", val); + //printf("BPTWL: reg=%02X\n", val); return; } @@ -113,7 +113,7 @@ void Write(u8 val, bool last) Registers[CurPos] = val; } - printf("BPTWL: write %02X -> %02X\n", CurPos, val); + //printf("BPTWL: write %02X -> %02X\n", CurPos, val); CurPos++; // CHECKME } diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 0ecd304..0bb8b5c 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -19,6 +19,7 @@ #include #include #include "NDS.h" +#include "DSi.h" #include "NDSCart.h" #include "ARM.h" #include "CRC32.h" @@ -558,7 +559,8 @@ void Key1_ApplyKeycode(u32* keycode, u32 mod) void Key1_InitKeycode(u32 idcode, u32 level, u32 mod) { - memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax + //memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax + memcpy(Key1_KeyBuf, &DSi::ITCMInit[0x4894], 0x1048); // hax u32 keycode[3] = {idcode, idcode>>1, idcode<<1}; if (level >= 1) Key1_ApplyKeycode(keycode, mod); @@ -1185,11 +1187,11 @@ void WriteROMCnt(u32 val) *(u32*)&cmd[4] = *(u32*)&ROMCommand[4]; } - /*printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n", + printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n", SPICnt, ROMCnt, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], - datasize);*/ + datasize); switch (cmd[0]) { -- cgit v1.2.3 From 62a605cd9223e63ebeacc6f1270f98447592ebe8 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 6 Aug 2019 02:27:54 +0200 Subject: lay base for camera shito --- melonDS.cbp | 2 + src/DSi_Camera.cpp | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/DSi_Camera.h | 55 +++++++++++++++++++++ src/DSi_I2C.cpp | 32 ++++++++++-- 4 files changed, 227 insertions(+), 5 deletions(-) create mode 100644 src/DSi_Camera.cpp create mode 100644 src/DSi_Camera.h (limited to 'src/DSi_I2C.cpp') diff --git a/melonDS.cbp b/melonDS.cbp index cc5357b..be1f30b 100644 --- a/melonDS.cbp +++ b/melonDS.cbp @@ -106,6 +106,8 @@ + + diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp new file mode 100644 index 0000000..66d08cb --- /dev/null +++ b/src/DSi_Camera.cpp @@ -0,0 +1,143 @@ +/* + Copyright 2016-2019 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include +#include "DSi_Camera.h" + + +DSi_Camera* DSi_Camera0; // 78 / facing outside +DSi_Camera* DSi_Camera1; // 7A / selfie cam + + +bool DSi_Camera::Init() +{ + DSi_Camera0 = new DSi_Camera(0); + DSi_Camera1 = new DSi_Camera(1); + + return true; +} + +void DSi_Camera::DeInit() +{ + delete DSi_Camera0; + delete DSi_Camera1; +} + +void DSi_Camera::Reset() +{ + DSi_Camera0->ResetCam(); + DSi_Camera1->ResetCam(); +} + + +DSi_Camera::DSi_Camera(u32 num) +{ + Num = num; +} + +DSi_Camera::~DSi_Camera() +{ + // +} + +void DSi_Camera::ResetCam() +{ + DataPos = 0; + RegAddr = 0; + RegData = 0; +} + + +void DSi_Camera::Start() +{ +} + +u8 DSi_Camera::Read(bool last) +{ + u8 ret; + + if (DataPos < 2) + { + printf("DSi_Camera: WHAT??\n"); + ret = 0; + } + else + { + if (DataPos & 0x1) + { + ret = RegData & 0xFF; + RegAddr += 2; // checkme + } + else + { + RegData = ReadReg(RegAddr); + ret = RegData >> 8; + } + } + + if (last) DataPos = 0; + else DataPos++; + + return ret; +} + +void DSi_Camera::Write(u8 val, bool last) +{ + if (DataPos < 2) + { + if (DataPos == 0) + RegAddr = val << 8; + else + RegAddr |= val; + + if (RegAddr & 0x1) printf("DSi_Camera: !! UNALIGNED REG ADDRESS %04X\n", RegAddr); + } + else + { + if (DataPos & 0x1) + { + RegData |= val; + WriteReg(RegAddr, RegData); + RegAddr += 2; // checkme + } + else + { + RegData = val << 8; + } + } + + if (last) DataPos = 0; + else DataPos++; +} + +u16 DSi_Camera::ReadReg(u16 addr) +{ + switch (addr) + { + case 0x301A: return 0x0002; // HAX + } + + printf("DSi_Camera%d: unknown read %04X\n", Num, addr); + return 0; +} + +void DSi_Camera::WriteReg(u16 addr, u16 val) +{ + printf("DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val); +} diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h new file mode 100644 index 0000000..eba35cb --- /dev/null +++ b/src/DSi_Camera.h @@ -0,0 +1,55 @@ +/* + Copyright 2016-2019 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef DSI_CAMERA_H +#define DSI_CAMERA_H + +#include "types.h" + +class DSi_Camera +{ +public: + static bool Init(); + static void DeInit(); + static void Reset(); + + DSi_Camera(u32 num); + ~DSi_Camera(); + + void ResetCam(); + + void Start(); + u8 Read(bool last); + void Write(u8 val, bool last); + +private: + u32 Num; + + u32 DataPos; + u32 RegAddr; + u16 RegData; + + u16 ReadReg(u16 addr); + void WriteReg(u16 addr, u16 val); +}; + + +extern DSi_Camera* DSi_Camera0; +extern DSi_Camera* DSi_Camera1; + +#endif // DSI_CAMERA_H diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index e88858b..907d0ef 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -20,6 +20,7 @@ #include #include "DSi.h" #include "DSi_I2C.h" +#include "DSi_Camera.h" namespace DSi_BPTWL @@ -131,6 +132,7 @@ u32 Device; bool Init() { if (!DSi_BPTWL::Init()) return false; + if (!DSi_Camera::Init()) return false; return true; } @@ -138,6 +140,7 @@ bool Init() void DeInit() { DSi_BPTWL::DeInit(); + DSi_Camera::DeInit(); } void Reset() @@ -148,6 +151,7 @@ void Reset() Device = -1; DSi_BPTWL::Reset(); + DSi_Camera::Reset(); } void WriteCnt(u8 val) @@ -171,37 +175,55 @@ void WriteCnt(u8 val) switch (Device) { case 0x4A: Data = DSi_BPTWL::Read(islast); break; - default: Data = 0; break; + case 0x78: Data = DSi_Camera0->Read(islast); break; + case 0x7A: Data = DSi_Camera1->Read(islast); break; + default: + printf("I2C: read on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, 0, islast); + Data = 0; + break; } - //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); } else { // write val &= 0xE7; + bool ack = true; if (val & (1<<1)) { Device = Data & 0xFE; - //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); + printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); switch (Device) { case 0x4A: DSi_BPTWL::Start(); break; + case 0x78: DSi_Camera0->Start(); break; + case 0x7A: DSi_Camera1->Start(); break; + default: + printf("I2C: %s start on unknown device %02X\n", (Data&0x01)?"read":"write", Device); + ack = false; + break; } } else { - //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); switch (Device) { case 0x4A: DSi_BPTWL::Write(Data, islast); break; + case 0x78: DSi_Camera0->Write(Data, islast); break; + case 0x7A: DSi_Camera1->Write(Data, islast); break; + default: + printf("I2C: write on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + ack = false; + break; } } - val |= (1<<4); + if (ack) val |= (1<<4); } val &= 0x7F; -- cgit v1.2.3 From 28a9c7d9d1c44066e91664101362eab69ab12f4d Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 6 Aug 2019 13:06:14 +0200 Subject: camera: enough stub to pass firmware init --- src/DSi_Camera.cpp | 25 ++++++++++++++++++++++++- src/DSi_Camera.h | 3 +++ src/DSi_I2C.cpp | 14 +++++++------- 3 files changed, 34 insertions(+), 8 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp index 66d08cb..45061b2 100644 --- a/src/DSi_Camera.cpp +++ b/src/DSi_Camera.cpp @@ -61,6 +61,9 @@ void DSi_Camera::ResetCam() DataPos = 0; RegAddr = 0; RegData = 0; + + PLLCnt = 0; + StandbyCnt = 0x4029; // checkme } @@ -130,7 +133,11 @@ u16 DSi_Camera::ReadReg(u16 addr) { switch (addr) { - case 0x301A: return 0x0002; // HAX + case 0x0000: return 0x2280; // chip ID + case 0x0014: return PLLCnt; + case 0x0018: return StandbyCnt; + + case 0x301A: return ((~StandbyCnt) & 0x4000) >> 12; } printf("DSi_Camera%d: unknown read %04X\n", Num, addr); @@ -139,5 +146,21 @@ u16 DSi_Camera::ReadReg(u16 addr) void DSi_Camera::WriteReg(u16 addr, u16 val) { + switch (addr) + { + case 0x0014: + // shouldn't be instant either? + val &= 0x7FFF; + val |= ((val & 0x0002) << 14); + PLLCnt = val; + return; + case 0x0018: + // TODO: this shouldn't be instant, but uh + val &= 0x003F; + val |= ((val & 0x0001) << 14); + StandbyCnt = val; + return; + } + printf("DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val); } diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h index eba35cb..78629b5 100644 --- a/src/DSi_Camera.h +++ b/src/DSi_Camera.h @@ -46,6 +46,9 @@ private: u16 ReadReg(u16 addr); void WriteReg(u16 addr, u16 val); + + u16 PLLCnt; + u16 StandbyCnt; }; diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 907d0ef..ffb724f 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -156,7 +156,7 @@ void Reset() void WriteCnt(u8 val) { - //printf("I2C: write CNT %02X\n", val); + //printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1)); // TODO: check ACK flag // TODO: transfer delay @@ -179,11 +179,11 @@ void WriteCnt(u8 val) case 0x7A: Data = DSi_Camera1->Read(islast); break; default: printf("I2C: read on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, 0, islast); - Data = 0; + Data = 0xFF; break; } - printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); } else { @@ -194,7 +194,7 @@ void WriteCnt(u8 val) if (val & (1<<1)) { Device = Data & 0xFE; - printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); + //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); switch (Device) { @@ -203,13 +203,13 @@ void WriteCnt(u8 val) case 0x7A: DSi_Camera1->Start(); break; default: printf("I2C: %s start on unknown device %02X\n", (Data&0x01)?"read":"write", Device); - ack = false; + //ack = false; break; } } else { - printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); switch (Device) { @@ -218,7 +218,7 @@ void WriteCnt(u8 val) case 0x7A: DSi_Camera1->Write(Data, islast); break; default: printf("I2C: write on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); - ack = false; + //ack = false; break; } } -- cgit v1.2.3 From 9c1ea0e539d797720ec5b0eaf999577ee5747eef Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 6 Aug 2019 13:31:27 +0200 Subject: guess after all we shouldn't send ACKs for nonexistant I2C devices --- src/DSi_I2C.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index ffb724f..5ced51e 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -203,7 +203,7 @@ void WriteCnt(u8 val) case 0x7A: DSi_Camera1->Start(); break; default: printf("I2C: %s start on unknown device %02X\n", (Data&0x01)?"read":"write", Device); - //ack = false; + ack = false; break; } } @@ -218,7 +218,7 @@ void WriteCnt(u8 val) case 0x7A: DSi_Camera1->Write(Data, islast); break; default: printf("I2C: write on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); - //ack = false; + ack = false; break; } } -- cgit v1.2.3 From 1c72df43ab8a45c3d7253274d8b1cb6e286a41eb Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 20 Oct 2019 18:35:16 +0200 Subject: messing around --- src/DSi.cpp | 36 ++++++++++++++++++++++++++++++------ src/DSi.h | 2 ++ src/DSi_I2C.cpp | 7 +++++++ 3 files changed, 39 insertions(+), 6 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index ef4e6da..71ef6d3 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -160,6 +160,27 @@ void Reset() ARM7Write16(eaddr+0x42, 0x0001); } +void SoftReset() +{ + // TODO: check exactly what is reset + // presumably, main RAM isn't reset, since the DSi can be told + // to boot a specific title this way + // BPTWL state wouldn't be reset either since BPTWL[0x70] is + // the warmboot flag + + // also, BPTWL[0x70] could be abused to quickly boot specific titles + + NDS::ARM9->Reset(); + NDS::ARM7->Reset(); + + DSi_AES::Reset(); + + LoadNAND(); + + NDS::ARM9->JumpTo(BootAddr[0]); + NDS::ARM7->JumpTo(BootAddr[1]); +} + bool LoadBIOS() { FILE* f; @@ -636,7 +657,8 @@ void Set_SCFG_MC(u32 val) u8 ARM9Read8(u32 addr) -{ +{if(addr==0x02FFC1B0) printf("ARM9 READ8 ROM REGION %08X\n", NDS::GetPC(0)); +if(addr==0x02FFFD70) printf("ARM9 READ8 CONSOLE REGION %08X\n", NDS::GetPC(0)); if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1)))) { if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0))) @@ -673,7 +695,7 @@ u8 ARM9Read8(u32 addr) } u16 ARM9Read16(u32 addr) -{ +{if(addr==0x02FFC1B0) printf("ARM9 READ16 ROM REGION %08X\n", NDS::GetPC(0)); if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1)))) { if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0))) @@ -710,7 +732,8 @@ u16 ARM9Read16(u32 addr) } u32 ARM9Read32(u32 addr) -{ +{if(addr==0x02FFC1B0) printf("ARM9 READ32 ROM REGION %08X\n", NDS::GetPC(0)); +if(addr==0x2FE71B0) return 0xFFFFFFFF; // hax: bypass region lock if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1)))) { if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0))) @@ -883,7 +906,8 @@ bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region) u8 ARM7Read8(u32 addr) -{ +{if(addr==0x02FFC1B0) printf("ARM7 READ8 ROM REGION %08X\n", NDS::GetPC(1)); +if(addr==0x02FFFD70) printf("ARM7 READ8 CONSOLE REGION %08X\n", NDS::GetPC(1)); if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9)))) { if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8))) @@ -924,7 +948,7 @@ u8 ARM7Read8(u32 addr) } u16 ARM7Read16(u32 addr) -{ +{if(addr==0x02FFC1B0) printf("ARM7 READ16 ROM REGION %08X\n", NDS::GetPC(1)); if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9)))) { if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8))) @@ -965,7 +989,7 @@ u16 ARM7Read16(u32 addr) } u32 ARM7Read32(u32 addr) -{ +{if(addr==0x02FFC1B0) printf("ARM7 READ32 ROM REGION %08X\n", NDS::GetPC(1)); if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9)))) { if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8))) diff --git a/src/DSi.h b/src/DSi.h index 5697237..08712de 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -42,6 +42,8 @@ bool Init(); void DeInit(); void Reset(); +void SoftReset(); + bool LoadBIOS(); bool LoadNAND(); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 5ced51e..0ab7008 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -103,6 +103,13 @@ void Write(u8 val, bool last) return; } + if (CurPos == 0x11 && val == 0x01) + { + printf("BPTWL: soft-reset\n"); + val = 0; // checkme + DSi::SoftReset(); + } + if (CurPos == 0x11 || CurPos == 0x12 || CurPos == 0x21 || CurPos == 0x30 || CurPos == 0x31 || -- cgit v1.2.3 From 8f5dff17251b759651d967fe072cf4f56b9edb35 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 30 May 2020 13:52:51 +0200 Subject: make soft-reset work somewhat better --- src/DSi.cpp | 29 +++++++++++++++++++++++++++++ src/DSi_I2C.cpp | 19 +++++++++++-------- 2 files changed, 40 insertions(+), 8 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi.cpp b/src/DSi.cpp index 15f06a2..fb4b37a 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -173,12 +173,41 @@ void SoftReset() NDS::ARM9->Reset(); NDS::ARM7->Reset(); + memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000); + + for (u32 i = 0; i < 0x3C00; i+=4) + ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]); + DSi_AES::Reset(); LoadNAND(); NDS::ARM9->JumpTo(BootAddr[0]); NDS::ARM7->JumpTo(BootAddr[1]); + + SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS + SCFG_Clock9 = 0x0187; // CHECKME + SCFG_Clock7 = 0x0187; + SCFG_EXT[0] = 0x8307F100; + SCFG_EXT[1] = 0x93FFFB06; + SCFG_MC = 0x0010;//0x0011; + + // LCD init flag + GPU::DispStat[0] |= (1<<6); + GPU::DispStat[1] |= (1<<6); + + NDS::MapSharedWRAM(3); + + u32 eaddr = 0x03FFE6E4; + ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]); + ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]); + ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]); + ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]); + ARM7Write16(eaddr+0x2C, 0x0001); + ARM7Write16(eaddr+0x2E, 0x0001); + ARM7Write16(eaddr+0x3C, 0x0100); + ARM7Write16(eaddr+0x3E, 0x40E0); + ARM7Write16(eaddr+0x42, 0x0001); } bool LoadBIOS() diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index 0ab7008..b2ca6e4 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -84,7 +84,7 @@ u8 Read(bool last) return 0; } - //printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); + printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); return Registers[CurPos++]; } @@ -107,7 +107,10 @@ void Write(u8 val, bool last) { printf("BPTWL: soft-reset\n"); val = 0; // checkme + // TODO: soft-reset might need to be scheduled later! DSi::SoftReset(); + CurPos = -1; + return; } if (CurPos == 0x11 || CurPos == 0x12 || @@ -121,7 +124,7 @@ void Write(u8 val, bool last) Registers[CurPos] = val; } - //printf("BPTWL: write %02X -> %02X\n", CurPos, val); + printf("BPTWL: write %02X -> %02X\n", CurPos, val); CurPos++; // CHECKME } @@ -163,7 +166,7 @@ void Reset() void WriteCnt(u8 val) { - //printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1)); + printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1)); // TODO: check ACK flag // TODO: transfer delay @@ -190,7 +193,7 @@ void WriteCnt(u8 val) break; } - //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); } else { @@ -201,7 +204,7 @@ void WriteCnt(u8 val) if (val & (1<<1)) { Device = Data & 0xFE; - //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); + printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); switch (Device) { @@ -216,7 +219,7 @@ void WriteCnt(u8 val) } else { - //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); switch (Device) { @@ -240,12 +243,12 @@ void WriteCnt(u8 val) } u8 ReadData() -{ +{printf("I2C: read data: %02X\n", Data); return Data; } void WriteData(u8 val) -{ +{printf("I2C: write data: %02X\n", val); Data = val; } -- cgit v1.2.3 From 77f4663f49caffbfb948ab14e42b6f8ade11d58d Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 1 Jun 2020 16:24:59 +0200 Subject: betterer SD/MMC code. Flipnote can save shit! --- src/DSi_AES.cpp | 12 +- src/DSi_I2C.cpp | 16 +-- src/DSi_NWifi.cpp | 10 +- src/DSi_SD.cpp | 398 +++++++++++++++++++++++++++++------------------------- src/DSi_SD.h | 18 ++- 5 files changed, 253 insertions(+), 201 deletions(-) (limited to 'src/DSi_I2C.cpp') diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 7aae8f3..4cb1169 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -213,12 +213,12 @@ u32 ReadCnt() ret |= InputFIFO->Level(); ret |= (OutputFIFO->Level() << 5); -//printf("READ AES CNT: %08X, LEVELS: IN=%d OUT=%d\n", ret, InputFIFO->Level(), OutputFIFO->Level()); + return ret; } void WriteCnt(u32 val) -{printf("AES CNT = %08X\n", val); +{ u32 oldcnt = Cnt; Cnt = val & 0xFC1FF000; @@ -294,12 +294,12 @@ void WriteCnt(u32 val) } } - printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n", - val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks); + //printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d\n", + // val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks); } void WriteBlkCnt(u32 val) -{printf("AES BLOCK CNT %08X / %d\n", val, val>>16); +{ BlkCnt = val; } @@ -405,7 +405,7 @@ void Update() // CHECKME Cnt &= ~(1<<21); } -printf("AES: FINISHED\n"); + Cnt &= ~(1<<31); if (Cnt & (1<<30)) NDS::SetIRQ2(NDS::IRQ2_DSi_AES); DSi::StopNDMAs(1, 0x2A); diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index b2ca6e4..9984f5e 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -84,7 +84,7 @@ u8 Read(bool last) return 0; } - printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); + //printf("BPTWL: read %02X -> %02X\n", CurPos, Registers[CurPos]); return Registers[CurPos++]; } @@ -124,7 +124,7 @@ void Write(u8 val, bool last) Registers[CurPos] = val; } - printf("BPTWL: write %02X -> %02X\n", CurPos, val); + //printf("BPTWL: write %02X -> %02X\n", CurPos, val); CurPos++; // CHECKME } @@ -166,7 +166,7 @@ void Reset() void WriteCnt(u8 val) { - printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1)); + //printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1)); // TODO: check ACK flag // TODO: transfer delay @@ -193,7 +193,7 @@ void WriteCnt(u8 val) break; } - printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); } else { @@ -204,7 +204,7 @@ void WriteCnt(u8 val) if (val & (1<<1)) { Device = Data & 0xFE; - printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); + //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device); switch (Device) { @@ -219,7 +219,7 @@ void WriteCnt(u8 val) } else { - printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); + //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast); switch (Device) { @@ -243,12 +243,12 @@ void WriteCnt(u8 val) } u8 ReadData() -{printf("I2C: read data: %02X\n", Data); +{ return Data; } void WriteData(u8 val) -{printf("I2C: write data: %02X\n", val); +{ Data = val; } diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp index 013173f..79bc632 100644 --- a/src/DSi_NWifi.cpp +++ b/src/DSi_NWifi.cpp @@ -515,6 +515,12 @@ void DSi_NWifi::SendCMD(u8 cmd, u32 param) { switch (cmd) { + case 12: + // stop command + // CHECKME: does the SDIO controller actually send those?? + // DSi firmware sets it to send them + return; + case 52: // IO_RW_DIRECT { u32 func = (param >> 28) & 0x7; @@ -608,7 +614,7 @@ void DSi_NWifi::ReadBlock() TransferAddr &= 0x1FFFF; // checkme } } - len = Host->SendData(data, len); + len = Host->DataRX(data, len); if (RemSize > 0) { @@ -628,7 +634,7 @@ void DSi_NWifi::WriteBlock() len = Host->GetTransferrableLen(len); u8 data[0x200]; - if (len = Host->ReceiveData(data, len)) + if (len = Host->DataTX(data, len)) { for (u32 i = 0; i < len; i++) { diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index a45a8ce..5231b99 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -24,7 +24,27 @@ #include "Platform.h" -#define SD_DESC (Num?"SDIO":"SD/MMC") +// observed IRQ behavior during transfers +// +// during reads: +// * bit23 is cleared during the first block, always set otherwise. weird +// * bit24 (RXRDY) gets set when the FIFO is full +// +// during reads with FIFO32: +// * FIFO16 drains directly into FIFO32 +// * when bit24 is set, FIFO32 is already full (with contents from the other FIFO) +// * reading from an empty FIFO just wraps around (and sets bit21) +// * FIFO32 starts filling when bit24 would be set? +// +// +// TX: +// * when sending command, if current FIFO full +// * upon ContinueTransfer(), if current FIFO full +// * -> upon DataTX() if current FIFO full +// * when filling FIFO + + +#define SD_DESC Num?"SDIO":"SD/MMC" DSi_SDHost::DSi_SDHost(u32 num) @@ -33,6 +53,7 @@ DSi_SDHost::DSi_SDHost(u32 num) DataFIFO[0] = new FIFO(0x100); DataFIFO[1] = new FIFO(0x100); + DataFIFO32 = new FIFO(0x80); Ports[0] = NULL; Ports[1] = NULL; @@ -42,6 +63,7 @@ DSi_SDHost::~DSi_SDHost() { delete DataFIFO[0]; delete DataFIFO[1]; + delete DataFIFO32; if (Ports[0]) delete Ports[0]; if (Ports[1]) delete Ports[1]; @@ -69,6 +91,7 @@ void DSi_SDHost::Reset() DataFIFO[0]->Clear(); DataFIFO[1]->Clear(); CurFIFO = 0; + DataFIFO32->Clear(); IRQStatus = 0; IRQMask = 0x8B7F031D; @@ -84,6 +107,8 @@ void DSi_SDHost::Reset() BlockLen16 = 0; BlockLen32 = 0; StopAction = 0; + TXReq = false; + if (Ports[0]) delete Ports[0]; if (Ports[1]) delete Ports[1]; Ports[0] = NULL; @@ -125,8 +150,8 @@ void DSi_SDHost::UpdateData32IRQ() oldflags &= (Data32IRQ >> 11); Data32IRQ &= ~0x0300; - if (IRQStatus & (1<<24)) Data32IRQ |= (1<<8); - if (!(IRQStatus & (1<<25))) Data32IRQ |= (1<<9); + if (DataFIFO32->Level() >= (BlockLen32>>2)) Data32IRQ |= (1<<8); + if (!DataFIFO32->IsEmpty()) Data32IRQ |= (1<<9); u32 newflags = ((Data32IRQ >> 8) & 0x1) | (((~Data32IRQ) >> 8) & 0x2); newflags &= (Data32IRQ >> 11); @@ -138,8 +163,6 @@ void DSi_SDHost::UpdateData32IRQ() void DSi_SDHost::ClearIRQ(u32 irq) { IRQStatus &= ~(1<CurFIFO ^= 1; + host->CheckSwapFIFO(); - host->ClearIRQ(25); - host->SetIRQ(24); - //if (param & 0x2) host->SetIRQ(2); - - // TODO: this is an assumption and should eventually be confirmed - // Flipnote sets DMA blocklen to 128 words and totallen to 1024 words - // so, presumably, DMA should trigger when the FIFO is full - // 'full' being when it reaches whatever BlockLen16 is set to, or the - // other blocklen register, or when it is actually full (but that makes - // less sense) - DSi::CheckNDMAs(1, host->Num ? 0x29 : 0x28); + if (host->DataMode == 1) + host->UpdateFIFO32(); + else + host->SetIRQ(24); } -u32 DSi_SDHost::SendData(u8* data, u32 len) +u32 DSi_SDHost::DataRX(u8* data, u32 len) { - //printf("%s: data RX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; } bool last = (BlockCountInternal == 0); @@ -232,52 +245,112 @@ u32 DSi_SDHost::SendData(u8* data, u32 len) // send-command function starts polling IRQ status u32 param = Num | (last << 1); NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, - false, 512, FinishSend, param); + false, 512, FinishRX, param); return len; } -void DSi_SDHost::FinishReceive(u32 param) +void DSi_SDHost::FinishTX(u32 param) { DSi_SDHost* host = (param & 0x1) ? DSi::SDIO : DSi::SDMMC; DSi_SDDevice* dev = host->Ports[host->PortSelect & 0x1]; - host->ClearIRQ(24); - host->SetIRQ(25); + if (host->BlockCountInternal == 0) + { + if (host->StopAction & (1<<8)) + { + if (dev) dev->SendCMD(12, 0); + } - if (dev) dev->ContinueTransfer(); + // CHECKME: presumably IRQ2 should not trigger here, but rather + // when the data transfer is done + //SetIRQ(0); + host->SetIRQ(2); + host->TXReq = false; + } + else + { + if (dev) dev->ContinueTransfer(); + } } -u32 DSi_SDHost::ReceiveData(u8* data, u32 len) +u32 DSi_SDHost::DataTX(u8* data, u32 len) { - printf("%s: data TX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); - if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; } + TXReq = true; u32 f = CurFIFO; - if ((DataFIFO[f]->Level() << 1) < len) + + if (DataMode == 1) { - printf("%s: FIFO not full enough for a transfer (%d / %d)\n", SD_DESC, DataFIFO[f]->Level()<<1, len); - return 0; + if ((DataFIFO32->Level() << 2) < len) + { + if (DataFIFO32->IsEmpty()) + { + SetIRQ(25); + DSi::CheckNDMAs(1, Num ? 0x29 : 0x28); + } + return 0; + } + + // drain FIFO32 into FIFO16 + + if (!DataFIFO[f]->IsEmpty()) printf("VERY BAD!! TRYING TO DRAIN FIFO32 INTO FIFO16 BUT IT CONTAINS SHIT ALREADY\n"); + for (;;) + { + u32 f = CurFIFO; + if ((DataFIFO[f]->Level() << 1) >= BlockLen16) break; + if (DataFIFO32->IsEmpty()) break; + + u32 val = DataFIFO32->Read(); + DataFIFO[f]->Write(val & 0xFFFF); + DataFIFO[f]->Write(val >> 16); + } + + UpdateData32IRQ(); + + if (BlockCount32 > 1) + BlockCount32--; + } + else + { + if ((DataFIFO[f]->Level() << 1) < len) + { + if (DataFIFO[f]->IsEmpty()) SetIRQ(25); + return 0; + } } - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; for (u32 i = 0; i < len; i += 2) *(u16*)&data[i] = DataFIFO[f]->Read(); CurFIFO ^= 1; + BlockCountInternal--; + + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 512, FinishTX, Num); + + return len; +} + +u32 DSi_SDHost::GetTransferrableLen(u32 len) +{ + if (len > BlockLen16) len = BlockLen16; // checkme + return len; +} + +void DSi_SDHost::CheckRX() +{ + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + + CheckSwapFIFO(); if (BlockCountInternal <= 1) { - printf("%s: data TX complete", SD_DESC); - if (StopAction & (1<<8)) { - printf(", sending CMD12"); if (dev) dev->SendCMD(12, 0); } - printf("\n"); - // CHECKME: presumably IRQ2 should not trigger here, but rather // when the data transfer is done //SetIRQ(0); @@ -286,22 +359,34 @@ u32 DSi_SDHost::ReceiveData(u8* data, u32 len) else { BlockCountInternal--; - } - return len; + if (dev) dev->ContinueTransfer(); + } } -u32 DSi_SDHost::GetTransferrableLen(u32 len) +void DSi_SDHost::CheckTX() { - if (len > BlockLen16) len = BlockLen16; // checkme - return len; + if (!TXReq) return; + + if (DataMode == 1) + { + if ((DataFIFO32->Level() << 2) < BlockLen32) + return; + } + else + { + u32 f = CurFIFO; + if ((DataFIFO[f]->Level() << 1) < BlockLen16) + return; + } + + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + if (dev) dev->ContinueTransfer(); } u16 DSi_SDHost::Read(u32 addr) { - if(!Num)printf("SDMMC READ %08X %08X\n", addr, NDS::GetPC(1)); - switch (addr & 0x1FF) { case 0x000: return Command; @@ -353,53 +438,7 @@ u16 DSi_SDHost::Read(u32 addr) case 0x036: return CardIRQStatus; case 0x038: return CardIRQMask; - case 0x030: // FIFO16 - { - // TODO: decrement BlockLen???? - - u32 f = CurFIFO; - if (DataFIFO[f]->IsEmpty()) - { - // TODO - return 0; - } - - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; - u16 ret = DataFIFO[f]->Read(); - - if (DataFIFO[f]->IsEmpty()) - { - ClearIRQ(24); - - if (BlockCountInternal <= 1) - { - printf("%s: data RX complete", SD_DESC); - - if (StopAction & (1<<8)) - { - printf(", sending CMD12"); - if (dev) dev->SendCMD(12, 0); - } - - printf("\n"); - - // CHECKME: presumably IRQ2 should not trigger here, but rather - // when the data transfer is done - //SetIRQ(0); - SetIRQ(2); - } - else - { - BlockCountInternal--; - - if (dev) dev->ContinueTransfer(); - } - - SetIRQ(25); - } - - return ret; - } + case 0x030: return ReadFIFO16(); case 0x0D8: return DataCtl; @@ -414,61 +453,52 @@ u16 DSi_SDHost::Read(u32 addr) return 0; } -u32 DSi_SDHost::ReadFIFO32() +u16 DSi_SDHost::ReadFIFO16() { - if (DataMode != 1) return 0; - - // TODO: decrement BlockLen???? - u32 f = CurFIFO; if (DataFIFO[f]->IsEmpty()) { // TODO + // on hardware it seems to wrap around. underflow bit is set upon the first 'empty' read. return 0; } DSi_SDDevice* dev = Ports[PortSelect & 0x1]; - u32 ret = DataFIFO[f]->Read(); - ret |= (DataFIFO[f]->Read() << 16); + u16 ret = DataFIFO[f]->Read(); if (DataFIFO[f]->IsEmpty()) { - ClearIRQ(24); - - if (BlockCountInternal <= 1) - { - printf("%s: data32 RX complete", SD_DESC); + CheckRX(); + } - if (StopAction & (1<<8)) - { - printf(", sending CMD12"); - if (dev) dev->SendCMD(12, 0); - } + return ret; +} - printf("\n"); +u32 DSi_SDHost::ReadFIFO32() +{ + if (DataMode != 1) return 0; - // CHECKME: presumably IRQ2 should not trigger here, but rather - // when the data transfer is done - //SetIRQ(0); - SetIRQ(2); - } - else - { - BlockCountInternal--; + if (DataFIFO32->IsEmpty()) + { + // TODO + return 0; + } - if (dev) dev->ContinueTransfer(); - } + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + u32 ret = DataFIFO32->Read(); - SetIRQ(25); + if (DataFIFO32->IsEmpty()) + { + CheckRX(); } + UpdateData32IRQ(); + return ret; } void DSi_SDHost::Write(u32 addr, u16 val) { - if(!Num)printf("SDMMC WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); - switch (addr & 0x1FF) { case 0x000: @@ -528,36 +558,10 @@ void DSi_SDHost::Write(u32 addr, u16 val) return; case 0x028: SDOption = val & 0xC1FF; return; - case 0x030: // FIFO16 - { - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; - u32 f = CurFIFO; - if (DataFIFO[f]->IsFull()) - { - // TODO - printf("!!!! %s FIFO (16) FULL\n", SD_DESC); - return; - } - - DataFIFO[f]->Write(val); - - if (DataFIFO[f]->Level() < (BlockLen16>>1)) - { - ClearIRQ(25); - SetIRQ(24); - return; - } - - // we completed one block, send it to the SD card - // TODO measure the actual delay!! - NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, - false, 2048, FinishReceive, Num); - } - return; + case 0x030: WriteFIFO16(val); return; case 0x034: CardIRQCtl = val & 0x0305; - printf("[%d] CardIRQCtl = %04X\n", Num, val); SetCardIRQ(); return; case 0x036: @@ -565,7 +569,6 @@ void DSi_SDHost::Write(u32 addr, u16 val) return; case 0x038: CardIRQMask = val & 0xC007; - printf("[%d] CardIRQMask = %04X\n", Num, val); SetCardIRQ(); return; @@ -593,12 +596,7 @@ void DSi_SDHost::Write(u32 addr, u16 val) case 0x100: Data32IRQ = (val & 0x1802) | (Data32IRQ & 0x0300); - if (val & (1<<10)) - { - // kind of hacky - u32 f = CurFIFO; - DataFIFO[f]->Clear(); - } + if (val & (1<<10)) DataFIFO32->Clear(); DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1); printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16); return; @@ -609,35 +607,76 @@ void DSi_SDHost::Write(u32 addr, u16 val) printf("unknown %s write %08X %04X\n", SD_DESC, addr, val); } -void DSi_SDHost::WriteFIFO32(u32 val) +void DSi_SDHost::WriteFIFO16(u16 val) { - if (DataMode != 1) return; - - printf("%s: WRITE FIFO32: LEVEL=%d/%d\n", SD_DESC, DataFIFO[CurFIFO]->Level(), (BlockLen16>>1)); - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; u32 f = CurFIFO; if (DataFIFO[f]->IsFull()) { // TODO - printf("!!!! %s FIFO (32) FULL\n", SD_DESC); + printf("!!!! %s FIFO (16) FULL\n", SD_DESC); return; } - DataFIFO[f]->Write(val & 0xFFFF); - DataFIFO[f]->Write(val >> 16); + DataFIFO[f]->Write(val); + + CheckTX(); +} + +void DSi_SDHost::WriteFIFO32(u32 val) +{ + if (DataMode != 1) return; - if (DataFIFO[f]->Level() < (BlockLen16>>1)) + if (DataFIFO32->IsFull()) { - ClearIRQ(25); - SetIRQ(24); + // TODO + printf("!!!! %s FIFO (32) FULL\n", SD_DESC); return; } - // we completed one block, send it to the SD card - // TODO measure the actual delay!! - NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, - false, 2048, FinishReceive, Num); + DataFIFO32->Write(val); + + CheckTX(); + + UpdateData32IRQ(); +} + +void DSi_SDHost::UpdateFIFO32() +{ + // check whether we can drain FIFO32 into FIFO16, or vice versa + + if (DataMode != 1) return; + + if (!DataFIFO32->IsEmpty()) printf("VERY BAD!! TRYING TO DRAIN FIFO16 INTO FIFO32 BUT IT CONTAINS SHIT ALREADY\n"); + for (;;) + { + u32 f = CurFIFO; + if ((DataFIFO32->Level() << 2) >= BlockLen32) break; + if (DataFIFO[f]->IsEmpty()) break; + + u32 val = DataFIFO[f]->Read(); + val |= (DataFIFO[f]->Read() << 16); + DataFIFO32->Write(val); + } + + UpdateData32IRQ(); + + if ((DataFIFO32->Level() << 2) >= BlockLen32) + { + DSi::CheckNDMAs(1, Num ? 0x29 : 0x28); + } +} + +void DSi_SDHost::CheckSwapFIFO() +{ + // check whether we can swap the FIFOs + + u32 f = CurFIFO; + bool cur_empty = (DataMode == 1) ? DataFIFO32->IsEmpty() : DataFIFO[f]->IsEmpty(); + if (cur_empty && ((DataFIFO[f^1]->Level() << 1) >= BlockLen16)) + { + CurFIFO ^= 1; + } } @@ -813,7 +852,7 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param) case 13: // get SSR Host->SendResponse(CSR, true); - Host->SendData(SSR, 64); + Host->DataRX(SSR, 64); return; case 41: // set operating conditions @@ -834,7 +873,7 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param) case 51: // get SCR Host->SendResponse(CSR, true); - Host->SendData(SCR, 8); + Host->DataRX(SCR, 8); return; } @@ -863,8 +902,6 @@ void DSi_MMCStorage::ContinueTransfer() u32 DSi_MMCStorage::ReadBlock(u64 addr) { - //printf("SD/MMC: reading block @ %08X, len=%08X\n", addr, BlockSize); - u32 len = BlockSize; len = Host->GetTransferrableLen(len); @@ -874,18 +911,17 @@ u32 DSi_MMCStorage::ReadBlock(u64 addr) fseek(File, addr, SEEK_SET); fread(data, 1, len, File); } - return Host->SendData(data, len); + + return Host->DataRX(data, len); } u32 DSi_MMCStorage::WriteBlock(u64 addr) { - printf("SD/MMC: write block @ %08X, len=%08X\n", addr, BlockSize); - u32 len = BlockSize; len = Host->GetTransferrableLen(len); u8 data[0x200]; - if (len = Host->ReceiveData(data, len)) + if (len = Host->DataTX(data, len)) { if (File) { diff --git a/src/DSi_SD.h b/src/DSi_SD.h index f4ca26c..2862173 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -36,20 +36,29 @@ public: void DoSavestate(Savestate* file); - static void FinishSend(u32 param); - static void FinishReceive(u32 param); + static void FinishRX(u32 param); + static void FinishTX(u32 param); void SendResponse(u32 val, bool last); - u32 SendData(u8* data, u32 len); - u32 ReceiveData(u8* data, u32 len); + u32 DataRX(u8* data, u32 len); + u32 DataTX(u8* data, u32 len); u32 GetTransferrableLen(u32 len); + void CheckRX(); + void CheckTX(); + bool TXReq; + void SetCardIRQ(); u16 Read(u32 addr); void Write(u32 addr, u16 val); + u16 ReadFIFO16(); + void WriteFIFO16(u16 val); u32 ReadFIFO32(); void WriteFIFO32(u32 val); + void UpdateFIFO32(); + void CheckSwapFIFO(); + private: u32 Num; @@ -78,6 +87,7 @@ private: FIFO* DataFIFO[2]; u32 CurFIFO; // FIFO accessible for read/write + FIFO* DataFIFO32; DSi_SDDevice* Ports[2]; -- cgit v1.2.3