[SC64][SW] Added controller reading functions in the bootloader

This commit is contained in:
Mateusz Faderewski 2025-03-09 20:48:15 +01:00
parent bb1ce45dfe
commit 0739ca624c
6 changed files with 264 additions and 4 deletions

View File

@ -34,6 +34,7 @@ SRC_FILES = \
interrupts.c \
interrupts.S \
io.c \
joybus.c \
main.c \
menu.c \
reboot.S \

View File

@ -79,6 +79,7 @@ void boot (boot_params_t *params) {
while (cpu_io_read(&SP->DMA_BUSY));
cpu_io_write(&PI->SR, PI_SR_CLR_INTR | PI_SR_RESET);
cpu_io_write(&SI->SR, 0);
while ((cpu_io_read(&VI->CURR_LINE) & ~(VI_CURR_LINE_FIELD)) != 0);
cpu_io_write(&VI->V_INTR, 0x3FF);
cpu_io_write(&VI->H_LIMITS, 0);

View File

@ -3,7 +3,7 @@
#include "vr4300.h"
static void cache_operation (uint8_t operation, uint8_t line_size, void *address, size_t length) {
static inline void cache_operation (const uint8_t operation, uint8_t line_size, void *address, size_t length) {
uint32_t cache_address = (((uint32_t) (address)) & (~(line_size - 1)));
while (cache_address < ((uint32_t) (address) + length)) {
asm volatile (
@ -109,3 +109,27 @@ void pi_dma_write (io32_t *address, void *buffer, size_t length) {
});
while (pi_busy());
}
uint32_t si_busy (void) {
return (cpu_io_read(&SI->SR) & (SI_SR_IO_BUSY | SI_SR_DMA_BUSY));
}
void si_dma_read (void *buffer) {
cache_data_hit_writeback_invalidate(buffer, PIF_RAM_LENGTH);
WITH_INTERRUPTS_DISABLED({
while (si_busy());
cpu_io_write(&SI->MADDR, (uint32_t) (PHYSICAL(buffer)));
cpu_io_write(&SI->RDMA, (uint32_t) (PIF_RAM));
});
while (si_busy());
}
void si_dma_write (void *buffer) {
cache_data_hit_writeback(buffer, PIF_RAM_LENGTH);
WITH_INTERRUPTS_DISABLED({
while (si_busy());
cpu_io_write(&SI->MADDR, (uint32_t) (PHYSICAL(buffer)));
cpu_io_write(&SI->WDMA, (uint32_t) (PIF_RAM));
});
while (si_busy());
}

View File

@ -202,6 +202,24 @@ typedef struct {
#define PI_SR_CLR_INTR (1 << 1)
typedef struct {
io32_t MADDR;
io32_t RDMA;
io32_t __reserved_0[2];
io32_t WDMA;
io32_t __reserved_1[1];
io32_t SR;
} si_regs_t;
#define SI_BASE (0x04800000UL)
#define SI ((si_regs_t *) SI_BASE)
#define SI_SR_DMA_BUSY (1 << 0)
#define SI_SR_IO_BUSY (1 << 1)
#define SI_SR_DMA_ERROR (1 << 3)
#define SI_SR_INTERRUPT (1 << 12)
#define ROM_DDIPL_BASE (0x06000000UL)
#define ROM_DDIPL ((io32_t *) ROM_DDIPL_BASE)
@ -210,6 +228,14 @@ typedef struct {
#define ROM_CART ((io32_t *) ROM_CART_BASE)
#define PIF_RAM_BASE (0x1FC007C0)
#define PIF_RAM_LENGTH (64)
#define PIF_RAM ((io32_t *) PIF_RAM_BASE)
void cache_data_hit_writeback_invalidate (void *address, size_t length);
void cache_data_hit_writeback (void *address, size_t length);
void cache_inst_hit_invalidate (void *address, size_t length);
uint32_t c0_count (void);
void delay_ms (int ms);
uint32_t cpu_io_read (io32_t *address);
@ -220,9 +246,9 @@ uint32_t pi_io_read (io32_t *address);
void pi_io_write (io32_t *address, uint32_t value);
void pi_dma_read (io32_t *address, void *buffer, size_t length);
void pi_dma_write (io32_t *address, void *buffer, size_t length);
void cache_data_hit_writeback_invalidate (void *address, size_t length);
void cache_data_hit_writeback (void *address, size_t length);
void cache_inst_hit_invalidate (void *address, size_t length);
uint32_t si_busy (void);
void si_dma_read (void *buffer);
void si_dma_write (void *buffer);
#endif

169
sw/bootloader/src/joybus.c Normal file
View File

@ -0,0 +1,169 @@
#include <string.h>
#include "io.h"
#include "joybus.h"
#define PIF_ESCAPE_SKIP_CHANNEL (0x00)
#define PIF_ESCAPE_END_OF_FRAME (0xFE)
#define PIF_COMMAND_JOYBUS_START (1 << 0)
#define JOYBUS_CMD_INFO (0x00)
#define JOYBUS_CMD_STATE (0x01)
#define JOYBUS_CMD_RESET (0xFF)
typedef struct __attribute__((packed)) {
struct __attribute__((packed)) {
uint8_t skip : 1;
uint8_t reset : 1;
uint8_t length : 6;
} tx;
struct __attribute__((packed)) {
uint8_t no_device : 1;
uint8_t timeout : 1;
uint8_t length : 6;
} rx;
uint8_t cmd;
} joybus_trx_info_t;
typedef struct __attribute__((packed)) {
joybus_trx_info_t info;
struct __attribute__((packed)) {
uint16_t id;
uint8_t flags;
} rx;
} joybus_cmd_info_t;
typedef struct __attribute__((packed)) {
joybus_trx_info_t info;
struct __attribute__((packed)) {
uint8_t a : 1;
uint8_t b : 1;
uint8_t z : 1;
uint8_t start : 1;
uint8_t up : 1;
uint8_t down : 1;
uint8_t left : 1;
uint8_t right : 1;
uint8_t reset : 1;
uint8_t __unused : 1;
uint8_t l : 1;
uint8_t r : 1;
uint8_t c_up : 1;
uint8_t c_down : 1;
uint8_t c_left : 1;
uint8_t c_right : 1;
int8_t x;
int8_t y;
} rx;
} joybus_cmd_state_t;
static void joybus_clear_buffer (uint8_t *buffer) {
for (int i = 0; i < PIF_RAM_LENGTH; i++) {
buffer[i] = 0;
}
}
static void joybus_set_starting_channel (uint8_t **ptr, int channel) {
for (int i = 0; i < channel; i++) {
**ptr = PIF_ESCAPE_SKIP_CHANNEL;
*ptr += 1;
}
}
static uint8_t *joybus_append_command (uint8_t **ptr, void *cmd, size_t length) {
((joybus_trx_info_t *) (cmd))->tx.length += 1;
uint8_t *cmd_ptr = *ptr;
memcpy(cmd_ptr, cmd, length);
*ptr += length;
return cmd_ptr;
}
static void joybus_load_result (uint8_t *cmd_ptr, void *cmd, size_t length) {
memcpy(cmd, cmd_ptr, length);
}
static void joybus_finish_frame (uint8_t **ptr) {
**ptr = PIF_ESCAPE_END_OF_FRAME;
*ptr += 1;
}
static void joybus_perform_transaction (uint8_t *buffer) {
buffer[PIF_RAM_LENGTH - 1] = PIF_COMMAND_JOYBUS_START;
si_dma_write(buffer);
si_dma_read(buffer);
}
static bool joybus_device_present (joybus_trx_info_t *trx_info) {
return !(trx_info->rx.no_device || trx_info->rx.timeout);
}
static bool joybus_execute_command (int port, void *cmd, size_t length) {
uint8_t buffer[PIF_RAM_LENGTH] __attribute__((aligned(8)));
uint8_t *ptr = buffer;
joybus_clear_buffer(buffer);
joybus_set_starting_channel(&ptr, port);
uint8_t *cmd_ptr = joybus_append_command(&ptr, cmd, length);
joybus_finish_frame(&ptr);
joybus_perform_transaction(buffer);
joybus_load_result(cmd_ptr, cmd, length);
return joybus_device_present((joybus_trx_info_t *) (cmd_ptr));
}
static void joybus_copy_controller_info (joybus_cmd_info_t *cmd, joybus_controller_info_t *info) {
info->id = cmd->rx.id;
info->flags = cmd->rx.flags;
}
static void joybus_copy_controller_state (joybus_cmd_state_t *cmd, joybus_controller_state_t *state) {
state->a = cmd->rx.a;
state->b = cmd->rx.b;
state->z = cmd->rx.z;
state->start = cmd->rx.start;
state->up = cmd->rx.up;
state->down = cmd->rx.down;
state->left = cmd->rx.left;
state->right = cmd->rx.right;
state->reset = cmd->rx.reset;
state->l = cmd->rx.l;
state->r = cmd->rx.r;
state->c_up = cmd->rx.c_up;
state->c_down = cmd->rx.c_down;
state->c_left = cmd->rx.c_left;
state->c_right = cmd->rx.c_right;
state->x = cmd->rx.x;
state->y = cmd->rx.y;
}
bool joybus_get_controller_info (int port, joybus_controller_info_t *info, bool reset) {
joybus_cmd_info_t cmd = { .info = {
.cmd = reset ? JOYBUS_CMD_RESET : JOYBUS_CMD_INFO,
.rx = { .length = sizeof(cmd.rx) }
} };
if (joybus_execute_command(port, &cmd, sizeof(cmd))) {
joybus_copy_controller_info(&cmd, info);
return true;
}
return false;
}
bool joybus_get_controller_state (int port, joybus_controller_state_t *state) {
joybus_cmd_state_t cmd = { .info = {
.cmd = JOYBUS_CMD_STATE,
.rx = { .length = sizeof(cmd.rx) }
} };
if (joybus_execute_command(port, &cmd, sizeof(cmd))) {
joybus_copy_controller_state(&cmd, state);
return true;
}
return false;
}

View File

@ -0,0 +1,39 @@
#ifndef JOYBUS_H__
#define JOYBUS_H__
#include <stdbool.h>
#include <stdint.h>
typedef struct {
uint16_t id;
uint8_t flags;
} joybus_controller_info_t;
typedef struct {
bool a;
bool b;
bool z;
bool start;
bool up;
bool down;
bool left;
bool right;
bool reset;
bool l;
bool r;
bool c_up;
bool c_down;
bool c_left;
bool c_right;
int8_t x;
int8_t y;
} joybus_controller_state_t;
bool joybus_get_controller_info (int port, joybus_controller_info_t *info, bool reset);
bool joybus_get_controller_state (int port, joybus_controller_state_t *state);
#endif