mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2025-04-14 21:51:27 +02:00
[SC64][SW] Added controller reading functions in the bootloader
This commit is contained in:
parent
bb1ce45dfe
commit
0739ca624c
@ -34,6 +34,7 @@ SRC_FILES = \
|
||||
interrupts.c \
|
||||
interrupts.S \
|
||||
io.c \
|
||||
joybus.c \
|
||||
main.c \
|
||||
menu.c \
|
||||
reboot.S \
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
169
sw/bootloader/src/joybus.c
Normal 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;
|
||||
}
|
39
sw/bootloader/src/joybus.h
Normal file
39
sw/bootloader/src/joybus.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user