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

debug: added support for SummerCart64 AUX register #595

Draft
wants to merge 4 commits into
base: preview
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 10 additions & 1 deletion include/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ extern "C" {
#define DEBUG_FEATURE_FILE_SD (1 << 3)


#define DEBUG_FEATURE_HOST_COMMANDS (1 << 4)


/**
* @brief Flag to activate all supported debugging features.
*
Expand All @@ -142,6 +145,10 @@ extern "C" {
/** @brief Shutdown SD filesystem. */
void debug_close_sdfs(void);


bool debug_init_host_commands(void);
void debug_close_host_commands(void);

/**
* @brief Initialize debugging features of libdragon.
*
Expand All @@ -163,7 +170,9 @@ extern "C" {
if (features & DEBUG_FEATURE_FILE_SD)
ok = debug_init_sdfs("sd:/", -1) || ok;
if (features & DEBUG_FEATURE_LOG_SD)
ok = debug_init_sdlog("sd:/libdragon.log", "a");
ok = debug_init_sdlog("sd:/libdragon.log", "a") || ok;
if (features & DEBUG_FEATURE_HOST_COMMANDS)
ok = debug_init_host_commands() || ok;
return ok;
}

Expand Down
16 changes: 16 additions & 0 deletions include/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ extern "C" {
#define PI_WR_LEN ((volatile uint32_t*)0xA460000C) ///< PI DMA: write length register
#define PI_STATUS ((volatile uint32_t*)0xA4600010) ///< PI: status register

/**
* @name PI Status Register Bit Definitions
* @{
*/
/** @brief PI DMA Busy */
#define PI_STATUS_DMA_BUSY ( 1 << 0 )
/** @brief PI IO Busy */
#define PI_STATUS_IO_BUSY ( 1 << 1 )
/** @brief PI Error */
#define PI_STATUS_ERROR ( 1 << 2 )
/** @brief PI Reset */
#define PI_STATUS_RESET ( 1 << 0 )
/** @brief PI Clear interrupt */
#define PI_STATUS_CLEAR_INTERRUPT ( 1 << 1 )
/** @} */

/**
* @brief Start writing data to a peripheral through PI DMA (low-level)
*
Expand Down
5 changes: 5 additions & 0 deletions include/n64sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ void wait_ticks( unsigned long wait );
*/
void wait_ms( unsigned long wait_ms );

void sys_rcp_halt(void);

/**
* @brief Force a complete halt of all processors
*
Expand All @@ -292,6 +294,9 @@ void wait_ms( unsigned long wait_ms );
__attribute__((noreturn))
void die(void);

__attribute__((noreturn))
void sys_reboot(void);

/**
* @brief Force a data cache invalidate over a memory region
*
Expand Down
2 changes: 2 additions & 0 deletions include/regsinternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ typedef struct PI_regs_s {
uint32_t dom1_latency;
/** @brief Cartridge domain 1 pulse width in RCP clock cycles. Requires DMA status bit guards to work reliably */
uint32_t dom1_pulse_width;
uint32_t dom1_page_size;
uint32_t dom1_release;
// TODO: add remaining registers
} PI_regs_t;

Expand Down
97 changes: 97 additions & 0 deletions src/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,103 @@ void debug_close_sdfs(void)
}
}

#define SC64_REG_SCR (0x1FFF0000)
#define SC64_REG_IRQ (0x1FFF0014)
#define SC64_REG_AUX (0x1FFF0018)

#define SC64_SCR_AUX_IRQ_PENDING (1 << 23)
#define SC64_SCR_AUX_IRQ_MASK (1 << 22)

#define SC64_IRQ_AUX_CLEAR (1 << 28)
#define SC64_IRQ_AUX_DISABLE (1 << 9)
#define SC64_IRQ_AUX_ENABLE (1 << 8)

#define SC64_AUX_MSG_PING (0xFF000000)
#define SC64_AUX_MSG_HALT (0xFF000001)
#define SC64_AUX_MSG_REBOOT (0xFF000002)

static void debug_cart_interrupt_handler_sc64(void)
{
bool rcp_halted = false;

do {
uint32_t scr = io_read(SC64_REG_SCR);

if ((scr & SC64_SCR_AUX_IRQ_MASK) && (scr & SC64_SCR_AUX_IRQ_PENDING)) {
io_write(SC64_REG_IRQ, SC64_IRQ_AUX_CLEAR);

switch (io_read(SC64_REG_AUX)) {
case SC64_AUX_MSG_PING:
io_write(SC64_REG_AUX, SC64_AUX_MSG_PING);
break;

case SC64_AUX_MSG_HALT:
if (!rcp_halted) {
sys_rcp_halt();
rcp_halted = true;
}
io_write(SC64_REG_AUX, SC64_AUX_MSG_HALT);
break;

case SC64_AUX_MSG_REBOOT:
io_write(SC64_REG_IRQ, SC64_IRQ_AUX_DISABLE);
io_write(SC64_REG_AUX, SC64_AUX_MSG_REBOOT);
sys_reboot();
break;

default:
break;
}
}
} while (rcp_halted);
}

bool debug_poll_host_commands(void)
{
if (!(enabled_features & DEBUG_FEATURE_HOST_COMMANDS))
return false;

if (cart_type == CART_SC) {
debug_cart_interrupt_handler_sc64();
return true;
}

return false;
}

bool debug_init_host_commands(void)
{
if (!sd_initialize_once())
return false;

if (cart_type == CART_SC) {
register_CART_handler(debug_cart_interrupt_handler_sc64);
set_CART_interrupt(true);

io_write(SC64_REG_IRQ, SC64_IRQ_AUX_ENABLE);

enabled_features |= DEBUG_FEATURE_HOST_COMMANDS;

return true;
}

return false;
}

void debug_close_host_commands(void)
{
if (enabled_features & DEBUG_FEATURE_HOST_COMMANDS) {
enabled_features &= ~(DEBUG_FEATURE_HOST_COMMANDS);

if (cart_type == CART_SC) {
io_write(SC64_REG_IRQ, SC64_IRQ_AUX_DISABLE);

set_CART_interrupt(false);
unregister_CART_handler(debug_cart_interrupt_handler_sc64);
}
}
}

void debug_assert_func_f(const char *file, int line, const char *func, const char *failedexpr, const char *msg, ...)
{
disable_interrupts();
Expand Down
12 changes: 1 addition & 11 deletions src/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,14 @@
* @ingroup dma
*/
#include <stdbool.h>
#include "dma.h"
#include "n64types.h"
#include "n64sys.h"
#include "interrupt.h"
#include "debug.h"
#include "utils.h"
#include "regsinternal.h"

/**
* @name PI Status Register Bit Definitions
* @{
*/
/** @brief PI DMA Busy */
#define PI_STATUS_DMA_BUSY ( 1 << 0 )
/** @brief PI IO Busy */
#define PI_STATUS_IO_BUSY ( 1 << 1 )
/** @brief PI Error */
#define PI_STATUS_ERROR ( 1 << 2 )
/** @} */

/** @brief Structure used to interact with the PI registers */
static volatile struct PI_regs_s * const PI_regs = (struct PI_regs_s *)0xa4600000;
Expand Down
14 changes: 8 additions & 6 deletions src/entrypoint.S
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ _start:
sw t1, %gprel(__entropy_state+4)(gp)

/* Copy other bootcode flags */
lbu t0, 0x0009(v0)
lbu t1, 0x000A(v0)
lbu t2, 0x000B(v0)
sw t0, %gprel(__boot_tvtype)(gp)
sw t1, %gprel(__boot_resettype)(gp)
sw t2, %gprel(__boot_consoletype)(gp)
lbu t0, 0x0008(v0)
lbu t1, 0x0009(v0)
lbu t2, 0x000A(v0)
lbu t3, 0x000B(v0)
sw t0, %gprel(__boot_romtype)(gp)
sw t1, %gprel(__boot_tvtype)(gp)
sw t2, %gprel(__boot_resettype)(gp)
sw t3, %gprel(__boot_consoletype)(gp)

la t0, debug_assert_func /* install assert function in system.c */
la t1, __assert_func_ptr
Expand Down
3 changes: 3 additions & 0 deletions src/inspector.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,9 @@ static void inspector(exception_t* ex, enum Mode mode) {
backtrace = true;
break;
}
// Poll incoming commands from the host
extern bool debug_poll_host_commands(void);
debug_poll_host_commands();
// Avoid constantly banging the PIF with controller reads, that
// would prevent the RESET button from working.
wait_ms(1);
Expand Down
102 changes: 93 additions & 9 deletions src/n64sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
#include <malloc.h>
#include "n64sys.h"
#include "regsinternal.h"
#include "dma.h"
#include "interrupt.h"
#include "vi.h"
#include "rsp.h"
#include "rdp.h"
#include "utils.h"

int __boot_memsize; ///< Memory size as detected by IPL3
int __boot_romtype; ///< ROM type as detected by IPL3
int __boot_tvtype; ///< TV type as detected by IPL3
int __boot_resettype; ///< Reset type as detected by IPL3
int __boot_consoletype; ///< Console type as detected by IPL3
Expand All @@ -27,6 +29,9 @@ static uint32_t ticks64_base_tick;
/** @brief Last value of the 64-bit counter */
static uint64_t ticks64_base;

/** @brief Structure used to interact with the PI registers */
static volatile struct PI_regs_s * const PI_regs = (struct PI_regs_s *)0xa4600000;

/**
* @brief Helper macro to perform cache refresh operations
*
Expand Down Expand Up @@ -175,6 +180,41 @@ void wait_ms( unsigned long wait_ms )
wait_ticks(TICKS_FROM_MS(wait_ms));
}

void sys_rcp_halt(void)
{
// Can't have any interrupts here
disable_interrupts();

// Stop PI transaction
*PI_STATUS = PI_STATUS_CLEAR_INTERRUPT | PI_STATUS_RESET;

// Halt the RSP
*SP_STATUS = SP_WSTATUS_SET_HALT;

// Wait for RSP to halt execution
while( !(*SP_STATUS & SP_STATUS_HALTED) );

// Wait for RSP IO and DMA operations to finish
while( *SP_STATUS & (SP_STATUS_IO_BUSY | SP_STATUS_DMA_BUSY) );

// Flush the RDP and wait for DMA to finish fetching commands
*DP_STATUS = DP_WSTATUS_SET_FLUSH;
RSP_WAIT_LOOP(200) {
if ( !(*DP_STATUS & DP_STATUS_DMA_BUSY) ) {
break;
}
}
*DP_STATUS = DP_WSTATUS_RESET_FLUSH;
Comment on lines +200 to +207
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently this code does not safely shutdown the RDP - there are occasional cases of RDP hard lock that prevents console from using it until full power cycle, thus limiting the soft reboot functionality severely.


// Shut the video off
if ( vi_is_active() ) { vi_wait_for_vblank(); }
vi_set_blank_image();

// Turn off and clear VI interrupt
*VI_V_INTR = 0x3FF;
*VI_V_CURRENT = 0;
}

/**
* @brief Force a complete halt of all processors
*
Expand All @@ -187,19 +227,63 @@ void wait_ms( unsigned long wait_ms )
*/
void die(void)
{
// Can't have any interrupts here
disable_interrupts();
// Halt the RSP
*SP_STATUS = SP_WSTATUS_SET_HALT;
// Flush the RDP
*DP_STATUS = DP_WSTATUS_SET_FLUSH | DP_WSTATUS_SET_FREEZE;
*DP_STATUS = DP_WSTATUS_RESET_FLUSH | DP_WSTATUS_RESET_FREEZE;
// Shut the video off
*VI_CTRL = *VI_CTRL & (~VI_CTRL_TYPE);
// Terminate the RCP execution
sys_rcp_halt();

// Terminate the CPU execution
abort();
}

void sys_reboot(void)
{
const uint32_t ROM_ADDRESS = __boot_romtype ? 0x06000000 : 0x10000000;
const int IPL3_SIZE = 0xFC0;
const uint32_t IPL3_OFFSET = 0x40;

uint8_t ipl3_data[IPL3_SIZE] __attribute__((aligned(8)));

// Halt RCP execution before soft rebooting
sys_rcp_halt();

// Set the default PI DOM1 timings
PI_regs->dom1_latency = 0xFF;
PI_regs->dom1_pulse_width = 0xFF;
PI_regs->dom1_page_size = 0x0F;
PI_regs->dom1_release = 0x03;

// Read and set PI DOM1 timings from the ROM header
uint32_t pi_config = io_read(ROM_ADDRESS);
PI_regs->dom1_latency = pi_config;
PI_regs->dom1_pulse_width = (pi_config >> 8);
PI_regs->dom1_page_size = (pi_config >> 16);
PI_regs->dom1_release = (pi_config >> 20);

// Load IPL3 into RSP DMEM
dma_read_raw_async(&ipl3_data, (ROM_ADDRESS + IPL3_OFFSET), sizeof(ipl3_data));
dma_wait();
rsp_load_data(ipl3_data, sizeof(ipl3_data), IPL3_OFFSET);

// Prepare entry arguments
void (*run_ipl3)(void) = (void (*)(void))((uint32_t)(SP_DMEM) + IPL3_OFFSET);
register uint32_t rom_type asm ("s3") = __boot_romtype;
register uint32_t tv_type asm ("s4") = __boot_tvtype;
register uint32_t reset_type asm ("s5") = RESET_WARM;

// Set CU1, CU0 and FR bits
C0_WRITE_STATUS((1 << 29) | (1 << 28) | (1 << 26));

// Jump to IPL3
asm volatile (
"jalr %[run_ipl3] \n" ::
[run_ipl3] "r" (run_ipl3),
[rom_type] "r" (rom_type),
[tv_type] "r" (tv_type),
[reset_type] "r" (reset_type)
);

abort();
}

/**
* @brief Initialize COP1 with default settings that prevent undesirable exceptions.
*
Expand Down
5 changes: 5 additions & 0 deletions src/rsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ void __rsp_crash(const char *file, int line, const char *func, const char *msg,

// OK we're done. Render on the screen and abort
console_render();

// Poll incoming commands from the host
extern bool debug_poll_host_commands(void);
while (debug_poll_host_commands());

abort();
}
/// @endcond
Expand Down