Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial CX II support #165

Merged
merged 59 commits into from
Apr 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
2145bb4
Initial CX II support
Vogtinator Apr 30, 2019
b989cdd
Set more Aladdin PMU values
Vogtinator Jul 26, 2019
61424f5
Set some other bits in the FTDDR3030 state register
Vogtinator Sep 2, 2019
4562faa
Some USB stuff
Vogtinator Apr 12, 2019
70344ac
Some USB stuff
Vogtinator Sep 1, 2019
96d8ab7
Some USB communication is happening
Vogtinator Sep 2, 2019
bd9b1b4
Implement USB FIFOs and DMAs
Vogtinator Sep 26, 2019
7a97d0c
Miscellaneous usb fixes, now gets to "USB Download is enabled."
jacobly0 Oct 1, 2019
4125f17
More usb fixes, now can receive and probably send packets.
jacobly0 Oct 3, 2019
629b0d8
Move fifos and dmas into structs
Vogtinator Oct 4, 2019
8f70194
Some more usb_cx2 cleanups
Vogtinator Oct 4, 2019
9815741
Merge rtc and rtc_cx
Vogtinator Oct 9, 2019
5c1355d
Add NNSE implementation from libnspire
Vogtinator Oct 9, 2019
1ea96ee
Fix FDMA IRQ states
Vogtinator Oct 19, 2019
c2b75b6
Implement NNSE quirk in usblink_cx2
Vogtinator Oct 19, 2019
55cc556
Fix sending packets bigger than 63 bytes
Vogtinator Oct 20, 2019
ab50b07
Fix NNSE checksum computation
Vogtinator Oct 21, 2019
81456a5
Fix sending and receiving files over NNSE
Vogtinator Oct 23, 2019
993b5bd
Use large NavNet packets for sending files
Vogtinator Oct 24, 2019
e32a4ed
Handle other CX II OS file extensions
Vogtinator Oct 24, 2019
07a71af
Implement the FTDMAC020 on CX II
Vogtinator Oct 26, 2019
8615fab
Disable verbose usb_cx2 debugging
Vogtinator Oct 26, 2019
7d18e4f
[headless] Add --print-on-warn option
Vogtinator Oct 26, 2019
fb41efd
Disable some more usb related debugging
Vogtinator Oct 26, 2019
e3cec4b
Implement the PL111 HW cursor
Vogtinator Oct 26, 2019
9180896
Implement suspend/resume for new CX II peripherals
Vogtinator Oct 26, 2019
7e9dd4c
Use usual c++ member initialization instead of designated initializers
Vogtinator Nov 24, 2019
323f7c8
Add workaround for a bug in MinGW 7 as shipped by Qt
Vogtinator Mar 14, 2020
f24baa8
Make the flash param struct size a static_assert
Vogtinator Mar 14, 2020
bc9ef51
Include winsock2 instead of arpa/inet.h on windows
Vogtinator Mar 14, 2020
54b1b28
C++ initializers compatibliity.
adriweb Mar 14, 2020
7ce241f
Better fast-forward in timer_cx_read for CX II
Vogtinator Sep 8, 2020
4f8e6c3
Implement the On button handling in the CX II PMU
Vogtinator Sep 8, 2020
47c1deb
Fix a comment
Vogtinator Sep 12, 2020
6b342ec
Add CX II entries to TODO.md
Vogtinator Sep 15, 2020
3f8a649
Implement CX II manuf parsing and efuses
Vogtinator Sep 14, 2020
e60badf
Fix accidential use of the comma operator
Vogtinator Sep 16, 2020
f168702
Read hw flags from CX II manuf
Vogtinator Sep 24, 2020
2450a3a
WIP: capTIvate touchpad support
Vogtinator Sep 24, 2020
711e825
Avoid cursor jumping with captivate
Vogtinator Sep 25, 2020
fb1447d
Finish captivate implementation
Vogtinator Sep 26, 2020
1b0ec54
Fix OS freezing after reconnecting USB
Vogtinator Sep 27, 2020
52f4ec1
Improve reliability of usblink_cx2 handshake
Vogtinator Oct 2, 2020
3e9e0b1
usb_cx2: Generalize FDMA handling
Vogtinator Jan 24, 2021
1876eda
Take default clock values from the CX II OS
Vogtinator Jan 24, 2021
fc02968
Implement flash preloading for the CX II
Vogtinator Jan 24, 2021
4895d1e
Send INT_POWER on On key presses on the CX II as well
Vogtinator Mar 24, 2021
3cd157b
usb_cx2: Allow USB IN transfers bigger than the FIFO size
Vogtinator Mar 24, 2021
7c1db9d
Clear more in touchpad_cx_reset
Vogtinator Mar 25, 2021
fc52d87
Allow coexistance of usb and usb_cx2
Vogtinator Mar 26, 2021
0f7f275
Update TODO.md
Vogtinator Mar 28, 2021
f57da79
Rename nope_(read/write)_(byte/half/word) to null_
Vogtinator Mar 28, 2021
370dccb
Remove spurious include in misc.h
Vogtinator Mar 28, 2021
7be75a7
Implement CX II backlight handling
Vogtinator Mar 29, 2021
e2c09c8
Error only when a write to the fast timer actually enables it
Vogtinator Mar 29, 2021
20f8785
Add some miscellaneous registers accessed when the CX II OS enters de…
Vogtinator Mar 29, 2021
22ef8fb
Update TODO.md
Vogtinator Apr 1, 2021
3b6318a
Don't use FASTCALL for null_(read/write)_(byte/half/word)
Vogtinator Apr 1, 2021
bf0ee23
Implement LED registers
Vogtinator Apr 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
##CX II:
* Standby needs fast timer + GPIO bits
* Check other aladdin PMU bits
* Flash dialog needs to be adapted (rewrite in QML anyway?)
* Refactor flash code, split controllers and image manipulation?
* Handle the LCD and "Magic VRAM" correctly
* Support "deep sleep"
* Inform when an incomplete boot rom is used

##TODO:
* Implement write_action for non-x86 to handle SMC and clearing RF_CODE_NO_TRANSLATE correctly
* File transfer: Move by D'n'D, drop folders, download folders
* Better debugger integration
* Don't use a 60Hz timer for LCD redrawing, hook lcd_event instead
* Less global vars (emu.h), move into structs
* Support content:/ URLs returned by the native file dialog on Android with Qt 5.13
* Use streams for reading/writing snapshots instead of struct emu_snapshot

##Wishlist:
Expand Down
10 changes: 10 additions & 0 deletions core/cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ void cpu_arm_loop()
{
arm.reg[15] &= ~0x3; // Align PC
Instruction *p = static_cast<Instruction*>(read_instruction(arm.reg[15]));
if(!p)
error("Jumped out of memory\n");

#ifdef BENCHMARK
static clock_t start = 0;
Expand All @@ -44,6 +46,14 @@ void cpu_arm_loop()

uint32_t *flags_ptr = &RAM_FLAGS(p);

/* Force use of capTIvate on 5.2.0.722 CX II CAS
if(arm.reg[15] == 0x100114D4)
{
*flags_ptr |= RF_CODE_NO_TRANSLATE;
features = 1;
arm.reg[0] = features; // captivate
}*/

// Check for pending events
if(cpu_events)
{
Expand Down
339 changes: 339 additions & 0 deletions core/cx2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
#include "emu.h"

#include "cx2.h"
#include "misc.h"

/* 90140000 */
struct aladdin_pmu_state aladdin_pmu;

void aladdin_pmu_reset(void) {
memset(&aladdin_pmu, 0, sizeof(aladdin_pmu));
aladdin_pmu.clocks = 0x21020303;
aladdin_pmu.disable[0] = 0;
aladdin_pmu.noidea[0] = 0x1A;
aladdin_pmu.noidea[1] = 0x101;
// Special cases for 0x808-0x810, see aladdin_pmu_read
//aladdin_pmu.noidea[4] = 0x111;
aladdin_pmu.noidea[5] = 0x1;
aladdin_pmu.noidea[6] = 0x100;
aladdin_pmu.noidea[7] = 0x10;

uint32_t cpu = 396000000;
sched.clock_rates[CLOCK_CPU] = cpu;
sched.clock_rates[CLOCK_AHB] = cpu / 2;
sched.clock_rates[CLOCK_APB] = cpu / 4;
}

static void aladdin_pmu_update_int()
{
int_set(INT_POWER, aladdin_pmu.int_state != 0);
}

uint32_t aladdin_pmu_read(uint32_t addr)
{
uint32_t offset = addr & 0xFFFF;
if(offset < 0x100)
{
switch (addr & 0xFF)
{
case 0x00: return 0x040000; // Wakeup reason
case 0x04: return 0; // No idea
case 0x08: return 0x2000;
case 0x20: return aladdin_pmu.disable[0];
case 0x24: return aladdin_pmu.int_state;
case 0x30: return aladdin_pmu.clocks;
case 0x50: return aladdin_pmu.disable[1];
case 0x60: return aladdin_pmu.disable[2];
}
}
else if(offset == 0x808) // efuse
return 0x0021DB19; // TODO: Taken from CX II CAS, same on other models?
else if(offset == 0x80C) // also efuse
return asic_user_flags << 20; // Has to match the 80E0 field in OS images
else if(offset == 0x810)
/* Bit 8 clear when ON key pressed */
return 0x11 | ((keypad.key_map[0] & 1<<9) ? 0 : 0x100);
else if(offset >= 0x800 && offset < 0x900)
return aladdin_pmu.noidea[(offset & 0xFF) >> 2];

return bad_read_word(addr);
}

void aladdin_pmu_write(uint32_t addr, uint32_t value)
{
uint32_t offset = addr & 0xFFFF;
if(offset < 0x100)
{
switch (offset & 0xFF)
{
case 0x00: return;
case 0x04: return; // No idea
case 0x08: return;
case 0x20:
if(value & 2)
/* enter sleep, jump to 0 when On pressed. */
warn("Sleep not implemented");
else
aladdin_pmu.disable[0] = value;

return;
case 0x24:
aladdin_pmu.int_state &= ~value;
aladdin_pmu_update_int();
return;
case 0x30:
aladdin_pmu.clocks = value;
aladdin_pmu.int_state |= 1;
aladdin_pmu_update_int();
return;
case 0x50: aladdin_pmu.disable[1] = value; return;
case 0x60: aladdin_pmu.disable[2] = value; return;
case 0xC4: return;
}
}
else if(offset == 0x80C || offset == 0x810)
return bad_write_word(addr, value);
else if(offset >= 0x800 && offset < 0x900)
{
aladdin_pmu.noidea[(offset & 0xFF) >> 2] = value;
return;
}

bad_write_word(addr, value);
}

bool aladdin_pmu_suspend(emu_snapshot *snapshot)
{
snapshot->mem.aladdin_pmu = aladdin_pmu;
return true;
}

bool aladdin_pmu_resume(const emu_snapshot *snapshot)
{
aladdin_pmu = snapshot->mem.aladdin_pmu;
return true;
}

/* 90120000: FTDDR3030 */
uint32_t memc_ddr_read(uint32_t addr)
{
switch(addr & 0xFFFF)
{
case 0x04:
return 0x102;
case 0x10:
return 3; // Size
case 0x28:
return 0;
case 0x74:
return 0;
}
return bad_read_word(addr);
}

void memc_ddr_write(uint32_t addr, uint32_t value)
{
uint16_t offset = addr;
if(offset < 0x40)
return; // Config data - don't care

switch(addr & 0xFFFF)
{
case 0x074:
case 0x0A8:
case 0x0AC:
case 0x138:
return;
}
bad_write_word(addr, value);
}

/* 90130000: ??? for LCD backlight */
static struct cx2_backlight_state cx2_backlight;

void cx2_backlight_reset()
{
cx2_backlight.pwm_value = cx2_backlight.pwm_period = 0;
}

void cx2_backlight_write(uint32_t addr, uint32_t value)
{
auto offset = addr & 0xFFF;
if(offset == 0x014)
cx2_backlight.pwm_value = value;
else if(offset == 0x018)
cx2_backlight.pwm_period = value;
else if(offset != 0x020)
bad_write_word(addr, value);

// Hack: Mirror the value in hdq1w
if(cx2_backlight.pwm_period == 0)
hdq1w.lcd_contrast = 0;
else
// Lower value -> brighter
hdq1w.lcd_contrast = 255 - (cx2_backlight.pwm_value * 255) / cx2_backlight.pwm_period;
}

bool cx2_backlight_suspend(emu_snapshot *snapshot)
{
snapshot->mem.cx2_backlight = cx2_backlight;
return true;
}

bool cx2_backlight_resume(const emu_snapshot *snapshot)
{
cx2_backlight = snapshot->mem.cx2_backlight;
return true;
}

/* 90040000: FTSSP010 SPI controller connected to the LCD.
Only the bare minimum to get the OS to boot is implemented. */
struct cx2_lcd_spi_state cx2_lcd_spi;

uint32_t cx2_lcd_spi_read(uint32_t addr)
{
switch (addr & 0xFFF)
{
case 0x0C: // REG_SR
{
uint32_t ret = 0x10 | (cx2_lcd_spi.busy ? 0x04 : 0x02);
cx2_lcd_spi.busy = false;
return ret;
}
default:
// Ignored.
return 0;
}
}

void cx2_lcd_spi_write(uint32_t addr, uint32_t value)
{
(void) value;

switch (addr & 0xFF)
{
case 0x18: // REG_DR
cx2_lcd_spi.busy = true;
break;
default:
// Ignored
break;
}
}

bool cx2_lcd_spi_suspend(emu_snapshot *snapshot)
{
snapshot->mem.cx2_lcd_spi = cx2_lcd_spi;
return true;
}

bool cx2_lcd_spi_resume(const emu_snapshot *snapshot)
{
cx2_lcd_spi = snapshot->mem.cx2_lcd_spi;
return true;
}

/* BC000000: An FTDMAC020 */
static dma_state dma;

void dma_cx2_reset()
{
memset(&dma, 0, sizeof(dma));
}

enum class DMAMemDir {
INC=0,
DEC=1,
FIX=2
};

static void dma_cx2_update()
{
if(!(dma.csr & 1)) // Enabled?
return;

if(dma.csr & 0b110) // Big-endian?
return;

for(auto &channel : dma.channels)
{
if(!(channel.control & 1)) // Start?
continue;

if((channel.control & 0b110) != 0b110) // AHB1?
error("Not implemented");

if(channel.control & (1 << 15)) // Abort
error("Not implemented");

auto dstdir = DMAMemDir((channel.control >> 3) & 3),
srcdir = DMAMemDir((channel.control >> 5) & 3);

if(srcdir != DMAMemDir::INC || dstdir != DMAMemDir::INC)
error("Not implemented");

auto dstwidth = (channel.control >> 8) & 7,
srcwidth = (channel.control >> 11) & 7;

if(dstwidth != srcwidth || dstwidth > 2)
error("Not implemented");

// Convert to bytes
srcwidth = 1 << srcwidth;

size_t total_len = channel.len * srcwidth;

void *srcp = phys_mem_ptr(channel.src, total_len),
*dstp = phys_mem_ptr(channel.dest, total_len);

if(!srcp || !dstp)
error("Invalid DMA transfer?");

/* Doesn't trigger any read or write actions, but on HW
* special care has to be taken anyway regarding caches
* and so on, so should be fine. */
memcpy(dstp, srcp, total_len);

channel.control &= ~1; // Clear start bit
}
}

uint32_t dma_cx2_read_word(uint32_t addr)
{
switch (addr & 0x3FFFFFF) {
case 0x00C: return 0;
case 0x01C: return 0;
case 0x024: return dma.csr;
case 0x100: return dma.channels[0].control;
case 0x104: return dma.channels[0].config;
}
return bad_read_word(addr);
}

void dma_cx2_write_word(uint32_t addr, uint32_t value)
{
switch (addr & 0x3FFFFFF) {
case 0x024: dma.csr = value; return;
case 0x100:
dma.channels[0].control = value;
dma_cx2_update();
return;
case 0x104: dma.channels[0].config = value; return;
case 0x108: dma.channels[0].src = value; return;
case 0x10C: dma.channels[0].dest = value; return;
case 0x114: dma.channels[0].len = value & 0x003fffff; return;
}
bad_write_word(addr, value);
}

bool dma_cx2_suspend(emu_snapshot *snapshot)
{
snapshot->mem.dma = dma;
return true;
}

bool dma_cx2_resume(const emu_snapshot *snapshot)
{
dma = snapshot->mem.dma;
return true;
}
Loading