mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
progress
This commit is contained in:
parent
3d1daf3fc6
commit
f8ff05c79b
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
**/.vscode
|
||||
*.bak
|
||||
*.zip
|
||||
.DS_Store
|
||||
|
18
build.sh
18
build.sh
@ -21,6 +21,8 @@ BUILT_RELEASE=false
|
||||
|
||||
FORCE_CLEAN=false
|
||||
SKIP_FPGA_REBUILD=false
|
||||
DEBUG_ENABLED=false
|
||||
USER_FLAGS+=" -D__SC64_VERSION=\"$__SC64_VERSION\""
|
||||
|
||||
build_cic () {
|
||||
if [ "$BUILT_CIC" = true ]; then return; fi
|
||||
@ -39,7 +41,7 @@ build_n64 () {
|
||||
if [ "$FORCE_CLEAN" = true ]; then
|
||||
make clean
|
||||
fi
|
||||
make all -j USER_FLAGS="-D__SC64_VERSION=\"$__SC64_VERSION\""
|
||||
make all -j USER_FLAGS="$USER_FLAGS"
|
||||
popd > /dev/null
|
||||
|
||||
BUILT_N64=true
|
||||
@ -52,7 +54,7 @@ build_riscv () {
|
||||
if [ "$FORCE_CLEAN" = true ]; then
|
||||
make clean -j
|
||||
fi
|
||||
make all USER_FLAGS="-D__SC64_VERSION=\"$__SC64_VERSION\""
|
||||
make all USER_FLAGS="$USER_FLAGS"
|
||||
popd > /dev/null
|
||||
|
||||
BUILT_RISCV=true
|
||||
@ -68,7 +70,11 @@ build_fpga () {
|
||||
if [ "$SKIP_FPGA_REBUILD" = true ] && [ -f output_files/SummerCart64.sof ]; then
|
||||
quartus_cpf -c SummerCart64.cof
|
||||
else
|
||||
if [ "$DEBUG_ENABLED" = true ]; then
|
||||
quartus_sh --set VERILOG_MACRO="DEBUG" ./SummerCart64.qpf
|
||||
fi
|
||||
quartus_sh --flow compile ./SummerCart64.qpf
|
||||
quartus_sh --set -remove VERILOG_MACRO="DEBUG" ./SummerCart64.qpf
|
||||
fi
|
||||
popd > /dev/null
|
||||
|
||||
@ -105,7 +111,7 @@ build_release () {
|
||||
|
||||
print_usage () {
|
||||
echo "builder script for SummerCart64"
|
||||
echo "usage: ./build.sh [cic] [n64] [riscv] [fpga] [update] [release] [-c] [-s] [--help]"
|
||||
echo "usage: ./build.sh [cic] [n64] [riscv] [fpga] [update] [release] [-c] [-s] [-d] [--help]"
|
||||
echo "parameters:"
|
||||
echo " cic - assemble UltraCIC-III software"
|
||||
echo " n64 - compile N64 bootloader software"
|
||||
@ -117,6 +123,8 @@ print_usage () {
|
||||
echo " - clean software compilation result directories before build"
|
||||
echo " -s | --skip-fpga-rebuild"
|
||||
echo " - do not recompile whole FPGA design if it's already done, just update software binaries"
|
||||
echo " -d | --debug"
|
||||
echo " - enable debug features"
|
||||
echo " --help - print this guide"
|
||||
}
|
||||
|
||||
@ -160,6 +168,9 @@ while test $# -gt 0; do
|
||||
-s|--skip-fpga-rebuild)
|
||||
SKIP_FPGA_REBUILD=true
|
||||
;;
|
||||
-d|--debug)
|
||||
DEBUG_ENABLED=true
|
||||
;;
|
||||
--help)
|
||||
print_usage
|
||||
exit 0
|
||||
@ -174,6 +185,7 @@ while test $# -gt 0; do
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$DEBUG_ENABLED" = true ]; then USER_FLAGS+=" -DDEBUG"; fi
|
||||
if [ "$TRIGGER_CIC" = true ]; then build_cic; fi
|
||||
if [ "$TRIGGER_N64" = true ]; then build_n64; fi
|
||||
if [ "$TRIGGER_RISCV" = true ]; then build_riscv; fi
|
||||
|
@ -3,10 +3,10 @@
|
||||
GIT_SHA=$(git rev-parse --short HEAD)
|
||||
GIT_TAG=$(git describe --tags --exact-match 2> /dev/null)
|
||||
|
||||
if [ ! -z "$GIT_TAG" ]; then
|
||||
__SC64_VERSION="git tag: $GIT_TAG"
|
||||
if [ ! -z $GIT_TAG ]; then
|
||||
__SC64_VERSION=$(printf "%.7q\ %.7q" $GIT_SHA $GIT_TAG)
|
||||
else
|
||||
__SC64_VERSION="git sha: $GIT_SHA"
|
||||
__SC64_VERSION=$(printf "%.7q\ develop" $GIT_SHA)
|
||||
fi
|
||||
|
||||
docker run \
|
||||
|
@ -33,7 +33,12 @@ package sc64;
|
||||
parameter bit [31:0] SC64_VER = 32'h53437632;
|
||||
parameter int CLOCK_FREQUENCY = 32'd100_000_000;
|
||||
parameter bit [31:0] CPU_RESET_VECTOR = {4'(ID_CPU_FLASH), 28'h0035800};
|
||||
parameter bit CPU_HAS_UART = 1'b0;
|
||||
parameter int UART_BAUD_RATE = 32'd1_000_000;
|
||||
|
||||
`ifdef DEBUG
|
||||
parameter bit CPU_HAS_UART = 1'b1;
|
||||
`else
|
||||
parameter bit CPU_HAS_UART = 1'b0;
|
||||
`endif
|
||||
|
||||
endpackage
|
||||
|
1
sw/n64/.gitignore
vendored
1
sw/n64/.gitignore
vendored
@ -1,2 +1 @@
|
||||
/build
|
||||
*.z64
|
||||
|
@ -6,13 +6,14 @@ OBJDUMP = $(TOOLCHAIN)objdump
|
||||
SIZE = $(TOOLCHAIN)size
|
||||
|
||||
FLAGS = -march=vr4300 -mtune=vr4300 -falign-functions=32 $(USER_FLAGS)
|
||||
CFLAGS = -Os -Wall -ffunction-sections -fdata-sections -ffreestanding -MMD -MP
|
||||
CFLAGS = -Os -Wall -ffunction-sections -fdata-sections -ffreestanding -G 0 -MMD -MP
|
||||
ASFLAGS = -Wa,-I$(N64_INST)/mips64-elf/lib
|
||||
LDFLAGS = -lc -nostartfiles -Wl,--gc-sections
|
||||
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = build
|
||||
|
||||
SRC_FILES = startup.S main.c sc64.c boot.c crc32.c
|
||||
SRC_FILES = startup.S main.c sys.c sc64.c syscalls.c crc32.c
|
||||
|
||||
SRCS = $(addprefix $(SRC_DIR)/, $(SRC_FILES))
|
||||
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(patsubst %,%.o,$(SRCS))))
|
||||
@ -23,7 +24,7 @@ VPATH = $(SRC_DIR)
|
||||
$(@info $(shell mkdir -p ./$(BUILD_DIR) &> /dev/null))
|
||||
|
||||
$(BUILD_DIR)/%.S.o: %.S
|
||||
$(CC) -x assembler-with-cpp $(FLAGS) $(CFLAGS) -c $< -o $@
|
||||
$(CC) -x assembler-with-cpp $(FLAGS) $(ASFLAGS) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.c.o: %.c
|
||||
$(CC) $(FLAGS) $(CFLAGS) -c $< -o $@
|
||||
@ -34,8 +35,8 @@ $(BUILD_DIR)/n64boot.elf: $(OBJS) N64.ld
|
||||
|
||||
$(BUILD_DIR)/n64boot.bin: $(BUILD_DIR)/n64boot.elf
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
@truncate --size=90k $@
|
||||
@chksum64 $@ > /dev/null
|
||||
@truncate --size=90k $@
|
||||
|
||||
$(BUILD_DIR)/n64boot.hex: $(BUILD_DIR)/n64boot.bin
|
||||
@$(OBJCOPY) -I binary -O ihex $< $@
|
||||
|
@ -5,43 +5,43 @@ MEMORY {
|
||||
|
||||
ENTRY(entry_handler)
|
||||
|
||||
__stack_size = 64k;
|
||||
|
||||
SECTIONS {
|
||||
.flash : {
|
||||
KEEP(*(.text.bootcode));
|
||||
KEEP(*(.text.rom_header));
|
||||
KEEP(*(.text.ipl3));
|
||||
__ipl3_font = LOADADDR(.flash) + 0xB70;
|
||||
} > flash
|
||||
|
||||
.text : {
|
||||
*(.text.entry_handler)
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
*(.rdata .rodata .rodata.* .gnu.linkonce.r.*)
|
||||
} > rdram AT > flash
|
||||
|
||||
.data : {
|
||||
. = ALIGN(8);
|
||||
_sdata = .;
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
. = ALIGN(8);
|
||||
_ssdata = .;
|
||||
_gp = . + 0x8000;
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
*(.lit8)
|
||||
*(.lit4)
|
||||
. = ALIGN(4);
|
||||
} > rdram AT > flash
|
||||
|
||||
.bss : {
|
||||
. = ALIGN(8);
|
||||
_sbss = .;
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon .scommon.*)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(8);
|
||||
_ebss = .;
|
||||
. = ALIGN(4);
|
||||
} > rdram
|
||||
|
||||
_sheap = .;
|
||||
. = ORIGIN(rdram) + LENGTH(rdram) - __stack_size;
|
||||
_eheap = .;
|
||||
|
||||
. += __stack_size;
|
||||
_sp = .;
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.MIPS.*)
|
||||
}
|
||||
|
||||
_gp = MIN(_ssdata + 0x8000, MAX(_sdata + 0x8000, _ebss - 0x8000));
|
||||
_sp = ORIGIN(rdram) + LENGTH(rdram);
|
||||
}
|
||||
|
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
#include "boot.h"
|
||||
#include "crc32.h"
|
||||
#include "n64_regs.h"
|
||||
// #include "sc64.h"
|
||||
#include "sc64.h"
|
||||
|
||||
|
||||
static const struct crc32_to_cic_seed {
|
||||
@ -26,9 +26,15 @@ static cart_header_t global_cart_header __attribute__((aligned(16)));
|
||||
|
||||
cart_header_t *boot_load_cart_header(void) {
|
||||
cart_header_t *cart_header_pointer = &global_cart_header;
|
||||
|
||||
uint32_t *src = (uint32_t *)(CART_BASE);
|
||||
uint32_t *dst = (uint32_t *) cart_header_pointer;
|
||||
|
||||
platform_pi_dma_read(cart_header_pointer, CART_BASE, sizeof(cart_header_t));
|
||||
platform_cache_invalidate(cart_header_pointer, sizeof(cart_header_t));
|
||||
for (int i = 0; i < sizeof(cart_header_t); i += 4) {
|
||||
*dst++ = pio_read(src++);
|
||||
// while (PI->status & 0x03);
|
||||
// ((uint32_t *)cart_header_pointer)[i] = (((uint32_t *)(CART_BASE))[i]);
|
||||
}
|
||||
|
||||
return cart_header_pointer;
|
||||
}
|
||||
@ -74,7 +80,7 @@ tv_type_t boot_get_tv_type(cart_header_t *cart_header) {
|
||||
}
|
||||
}
|
||||
|
||||
void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type) {
|
||||
__attribute__((noreturn)) void bootX(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type) {
|
||||
uint32_t is_x105_boot = (cic_seed == crc32_to_cic_seed[5].cic_seed);
|
||||
uint32_t is_ddipl_boot = (
|
||||
(cic_seed == crc32_to_cic_seed[7].cic_seed) ||
|
||||
@ -140,11 +146,7 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type) {
|
||||
gpr_regs[CPU_REG_S7] = BOOT_SEED_OS_VERSION(cic_seed);
|
||||
gpr_regs[CPU_REG_SP] = CPU_ADDRESS_IN_REG(SP_MEM->imem[ARRAY_ITEMS(SP_MEM->imem) - 4]);
|
||||
gpr_regs[CPU_REG_RA] = CPU_ADDRESS_IN_REG(SP_MEM->imem[(os_tv_type == TV_PAL) ? 341 : 340]);
|
||||
|
||||
// sc64_print_debug((uint32_t) gpr_regs[CPU_REG_T3], (uint32_t) gpr_regs[CPU_REG_S3], (uint32_t) gpr_regs[CPU_REG_S4]);
|
||||
// sc64_print_debug((uint32_t) gpr_regs[CPU_REG_S5], (uint32_t) gpr_regs[CPU_REG_S6], (uint32_t) gpr_regs[CPU_REG_S7]);
|
||||
// sc64_print_debug((uint32_t) gpr_regs[CPU_REG_SP], (uint32_t) gpr_regs[CPU_REG_RA], 0);
|
||||
|
||||
// return;
|
||||
__asm__ (
|
||||
".set noat \n\t"
|
||||
".set noreorder \n\t"
|
||||
@ -175,7 +177,7 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type) {
|
||||
"nop \n\t"
|
||||
"ctc1 $t0, $31 \n\t"
|
||||
"nop \n\t"
|
||||
"add $ra, $zero, %[gpr_regs] \n\t"
|
||||
"move $ra, %[gpr_regs] \n\t"
|
||||
"ld $at, 0x08($ra) \n\t"
|
||||
"ld $v0, 0x10($ra) \n\t"
|
||||
"ld $v1, 0x18($ra) \n\t"
|
||||
@ -213,6 +215,4 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type) {
|
||||
: [gpr_regs] "r" (gpr_regs)
|
||||
: "t0", "ra"
|
||||
);
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
@ -39,6 +39,12 @@ struct os_boot_config_s {
|
||||
|
||||
typedef struct os_boot_config_s os_boot_config_t;
|
||||
|
||||
typedef enum {
|
||||
TV_PAL = 0,
|
||||
TV_NTSC = 1,
|
||||
TV_MPAL = 2,
|
||||
} tv_type_t;
|
||||
|
||||
|
||||
#define OS_BOOT_CONFIG_BASE (0xA0000300)
|
||||
#define OS_BOOT_CONFIG ((os_boot_config_t *) OS_BOOT_CONFIG_BASE)
|
||||
@ -57,7 +63,7 @@ typedef struct os_boot_config_s os_boot_config_t;
|
||||
cart_header_t *boot_load_cart_header(void);
|
||||
uint16_t boot_get_cic_seed(cart_header_t *cart_header);
|
||||
tv_type_t boot_get_tv_type(cart_header_t *cart_header);
|
||||
void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type);
|
||||
void bootX(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "crc32.h"
|
||||
|
||||
|
||||
static const uint32_t crc_table[256] = {
|
||||
static const uint32_t crc32_table[256] = {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
@ -43,7 +43,7 @@ uint32_t crc32_calculate(void *buffer, size_t length) {
|
||||
uint8_t *byte_pointer = (uint8_t *) buffer;
|
||||
|
||||
while (length--) {
|
||||
crc32 = (crc32 >> 8) ^ crc_table[(crc32 & 0xFF) ^ (*byte_pointer++)];
|
||||
crc32 = (crc32 >> 8) ^ crc32_table[(crc32 & 0xFF) ^ (*byte_pointer++)];
|
||||
}
|
||||
|
||||
return ~crc32;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define CRC32_H__
|
||||
|
||||
|
||||
#include "platform.h"
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
uint32_t crc32_calculate(void *buffer, size_t length);
|
||||
|
@ -1,19 +1,41 @@
|
||||
#include "sc64.h"
|
||||
#include "boot.h"
|
||||
|
||||
|
||||
int main(void) {
|
||||
OS_BOOT_CONFIG->tv_type = TV_NTSC;
|
||||
void main(void) {
|
||||
sc64_init();
|
||||
|
||||
while (!sc64_check_presence());
|
||||
rom_header_t header;
|
||||
|
||||
sc64_wait_cpu_ready();
|
||||
io32_t *src = (io32_t *) (ROM_HEADER_CART);
|
||||
uint32_t *dst = (uint32_t *) (&header);
|
||||
|
||||
sc64_set_config(CFG_ID_SDRAM_SWITCH, true);
|
||||
for (int i = 0; i < sizeof(rom_header_t); i += 4) {
|
||||
*dst++ = pi_io_read(src++);
|
||||
}
|
||||
|
||||
cart_header_t *cart_header = boot_load_cart_header();
|
||||
uint16_t cic_seed = boot_get_cic_seed(cart_header);
|
||||
tv_type_t tv_type = boot_get_tv_type(cart_header);
|
||||
LOG_I("Booting ROM:\r\n");
|
||||
LOG_I(" PI Config: 0x%08lX\r\n", header.pi_config);
|
||||
LOG_I(" Clock rate: 0x%08lX\r\n", header.clock_rate);
|
||||
LOG_I(" Load address: 0x%08lX\r\n", header.load_addr);
|
||||
LOG_I(" SDK vesrion: %d.%d%c\r\n", header.sdk_version.major / 10, header.sdk_version.major % 10, header.sdk_version.minor);
|
||||
LOG_I(" 1MB CRC: 0x%08lX, 0x%08lX\r\n", header.crc[0], header.crc[1]);
|
||||
LOG_I(" Name: %.20s\r\n", header.name);
|
||||
LOG_I(" ID: %.4s\r\n", header.id);
|
||||
LOG_I(" Mask ROM version: %d\r\n", header.version);
|
||||
LOG_I("\r\n");
|
||||
|
||||
boot(cart_header, cic_seed, tv_type);
|
||||
info_t info;
|
||||
|
||||
sc64_get_info(&info);
|
||||
|
||||
LOG_I("SC64 settings:\r\n");
|
||||
LOG_I(" DD enabled: %d\r\n", info.dd_enabled);
|
||||
LOG_I(" Save type: %d\r\n", info.save_type);
|
||||
LOG_I(" CIC seed: 0x%02X\r\n", info.cic_seed);
|
||||
LOG_I(" TV type: %d\r\n", info.tv_type);
|
||||
LOG_I(" Save offset: 0x%08lX\r\n", (uint32_t) info.save_offset);
|
||||
LOG_I(" DD offset: 0x%08lX\r\n", (uint32_t) info.dd_offset);
|
||||
LOG_I(" Boot mode: %d\r\n", info.boot_mode);
|
||||
LOG_I(" Bootloader ver: %s\r\n", info.bootloader_version);
|
||||
LOG_I("\r\n");
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
#ifndef PLATFORM_H__
|
||||
#define PLATFORM_H__
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libdragon.h>
|
||||
|
||||
|
||||
#define BOOTLOADER_VERSION_MAJOR (1)
|
||||
#define BOOTLOADER_VERSION_MINOR (0)
|
||||
|
||||
#define __IO volatile
|
||||
|
||||
typedef uint32_t reg_t;
|
||||
|
||||
#define platform_cache_writeback(rdram, length) data_cache_hit_writeback_invalidate(rdram, length)
|
||||
#define platform_cache_invalidate(rdram, length) data_cache_hit_invalidate(rdram, length)
|
||||
#define platform_pi_io_write(pi, value) io_write((uint32_t) (pi), value)
|
||||
#define platform_pi_io_read(pi) io_read((uint32_t) (pi))
|
||||
#define platform_pi_dma_write(rdram, pi, length) dma_write(rdram, (uint32_t) (pi), length)
|
||||
#define platform_pi_dma_read(rdram, pi, length) dma_read(rdram, (uint32_t) (pi), length)
|
||||
|
||||
|
||||
#endif
|
@ -1,48 +1,127 @@
|
||||
#include <string.h>
|
||||
#include "sc64.h"
|
||||
|
||||
|
||||
typedef struct sc64_cart_registers {
|
||||
__IO reg_t SR_CMD;
|
||||
__IO reg_t DATA[2];
|
||||
__IO reg_t VERSION;
|
||||
} sc64_cfg_registers_t;
|
||||
|
||||
#define SC64_CFG_BASE (0x1FFF0000)
|
||||
#define SC64_CFG ((__IO sc64_cfg_registers_t *) SC64_CFG_BASE)
|
||||
|
||||
|
||||
|
||||
bool sc64_check_presence(void) {
|
||||
uint32_t version = platform_pi_io_read(&SC64_CFG->VERSION);
|
||||
return (version == 0x53437632);
|
||||
uint32_t version = pi_io_read(&SC64->VERSION);
|
||||
return (version == SC64_VERSION_2);
|
||||
}
|
||||
|
||||
void sc64_wait_cpu_ready(void) {
|
||||
uint32_t sr;
|
||||
do {
|
||||
sr = platform_pi_io_read(&SC64_CFG->SR_CMD);
|
||||
} while (!(sr & SC64_CFG_SCR_CPU_READY));
|
||||
sr = pi_io_read(&SC64->SR_CMD);
|
||||
} while (!(sr & SC64_SR_CPU_READY));
|
||||
}
|
||||
|
||||
void sc64_wait_cpu_busy(void) {
|
||||
bool sc64_wait_cpu_busy(void) {
|
||||
uint32_t sr;
|
||||
do {
|
||||
sr = platform_pi_io_read(&SC64_CFG->SR_CMD);
|
||||
} while (sr & SC64_CFG_SCR_CPU_BUSY);
|
||||
sr = pi_io_read(&SC64->SR_CMD);
|
||||
} while (sr & SC64_SR_CPU_BUSY);
|
||||
return sr & SC64_SR_CMD_ERROR;
|
||||
}
|
||||
|
||||
void sc64_perform_cmd(uint8_t cmd, uint32_t *args) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
platform_pi_io_write(&SC64_CFG->DATA[i], args[i]);
|
||||
}
|
||||
platform_pi_io_write(&SC64_CFG->SR_CMD, (uint32_t) cmd);
|
||||
sc64_wait_cpu_busy();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
args[i] = platform_pi_io_read(&SC64_CFG->DATA[i]);
|
||||
bool sc64_perform_cmd(uint8_t cmd, uint32_t *args, uint32_t *result) {
|
||||
pi_io_write(&SC64->DATA[0], args[0]);
|
||||
pi_io_write(&SC64->DATA[1], args[1]);
|
||||
pi_io_write(&SC64->SR_CMD, (uint32_t) cmd);
|
||||
bool error = sc64_wait_cpu_busy();
|
||||
if (result != NULL) {
|
||||
result[0] = pi_io_read(&SC64->DATA[0]);
|
||||
result[1] = pi_io_read(&SC64->DATA[1]);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void sc64_set_config(uint32_t type, uint32_t value) {
|
||||
uint32_t args[2] = { type, value };
|
||||
sc64_perform_cmd(SC64_CMD_CONFIG, args);
|
||||
uint32_t sc64_get_config(cfg_id_t id) {
|
||||
uint32_t args[2] = { id, 0 };
|
||||
uint32_t result[2];
|
||||
sc64_perform_cmd(SC64_CMD_QUERY, args, result);
|
||||
return result[1];
|
||||
}
|
||||
|
||||
void sc64_set_config(cfg_id_t id, uint32_t value) {
|
||||
uint32_t args[2] = { id, value };
|
||||
sc64_perform_cmd(SC64_CMD_CONFIG, args, NULL);
|
||||
}
|
||||
|
||||
void sc64_get_info(info_t *info) {
|
||||
io32_t *src = UNCACHED(SC64_BL_VERSION_BASE);
|
||||
uint32_t *dst = (uint32_t *) info->bootloader_version;
|
||||
|
||||
sc64_set_config(CFG_ID_SDRAM_SWITCH, false);
|
||||
|
||||
for (int i = 0; i < sizeof(info->bootloader_version); i += sizeof(uint32_t)) {
|
||||
*dst++ = pi_io_read(src++);
|
||||
}
|
||||
|
||||
sc64_set_config(CFG_ID_SDRAM_SWITCH, true);
|
||||
|
||||
info->dd_enabled = (bool) sc64_get_config(CFG_ID_DD_ENABLE);
|
||||
info->save_type = (save_type_t) sc64_get_config(CFG_ID_SAVE_TYPE);
|
||||
info->cic_seed = (uint8_t) sc64_get_config(CFG_ID_CIC_SEED);
|
||||
info->tv_type = (tv_type_t) sc64_get_config(CFG_ID_TV_TYPE);
|
||||
info->save_offset = (io32_t *) sc64_get_config(CFG_ID_SAVE_OFFEST);
|
||||
info->dd_offset = (io32_t *) sc64_get_config(CFG_ID_DD_OFFEST);
|
||||
info->boot_mode = (boot_mode_t) sc64_get_config(CFG_ID_BOOT_MODE);
|
||||
}
|
||||
|
||||
void sc64_wait_usb_tx_ready(void) {
|
||||
uint32_t args[2] = { 0, 0 };
|
||||
uint32_t result[2];
|
||||
do {
|
||||
sc64_perform_cmd(SC64_CMD_DEBUG_TX_READY, args, result);
|
||||
} while (!result[0]);
|
||||
}
|
||||
|
||||
void sc64_usb_tx_data(io32_t *address, uint32_t length) {
|
||||
uint32_t args[2] = { (uint32_t) (address), length };
|
||||
sc64_perform_cmd(SC64_CMD_DEBUG_TX_DATA, args, NULL);
|
||||
}
|
||||
|
||||
void sc64_debug_write(uint8_t type, const void *data, uint32_t len) {
|
||||
char *dma = "DMA@";
|
||||
char *cmp = "CMPH";
|
||||
|
||||
io32_t *sdram = UNCACHED(SC64_DEBUG_WRITE_ADDRESS);
|
||||
|
||||
io32_t *src = (io32_t *) (data);
|
||||
io32_t *dst = sdram;
|
||||
|
||||
uint32_t copy_length = ALIGN(len, 4);
|
||||
uint32_t transfer_length = 4 + 4 + copy_length + 4;
|
||||
|
||||
bool writable = sc64_get_config(CFG_ID_SDRAM_WRITABLE);
|
||||
|
||||
sc64_wait_usb_tx_ready();
|
||||
|
||||
if (!writable) {
|
||||
sc64_set_config(CFG_ID_SDRAM_WRITABLE, true);
|
||||
}
|
||||
|
||||
pi_io_write(dst++, *((uint32_t *) (dma)));
|
||||
pi_io_write(dst++, (type << 24) | len);
|
||||
|
||||
for (uint32_t i = 0; i < copy_length; i += 4) {
|
||||
pi_io_write(dst++, *src++);
|
||||
}
|
||||
|
||||
pi_io_write(dst++, *((uint32_t *) (cmp)));
|
||||
|
||||
if (!writable) {
|
||||
sc64_set_config(CFG_ID_SDRAM_WRITABLE, false);
|
||||
}
|
||||
|
||||
sc64_usb_tx_data(sdram, transfer_length);
|
||||
}
|
||||
|
||||
void sc64_debug_print(const char *text) {
|
||||
sc64_debug_write(SC64_DEBUG_TYPE_TEXT, text, strlen(text));
|
||||
}
|
||||
|
||||
void sc64_init(void) {
|
||||
while (!sc64_check_presence());
|
||||
sc64_wait_cpu_ready();
|
||||
sc64_set_config(CFG_ID_SDRAM_SWITCH, true);
|
||||
}
|
||||
|
@ -2,16 +2,55 @@
|
||||
#define SC64_H__
|
||||
|
||||
|
||||
#include "platform.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
#define SC64_CFG_SCR_CPU_READY (1 << 31)
|
||||
#define SC64_CFG_SCR_CPU_BUSY (1 << 30)
|
||||
#ifdef DEBUG
|
||||
#include <assert.h>
|
||||
#define LOG_I(args...) {iprintf("\033[32m" args);}
|
||||
#define LOG_E(args...) {iprintf("\033[31m" args);}
|
||||
#else
|
||||
#define LOG_I(args...)
|
||||
#define LOG_E(args...)
|
||||
#define assert(expr)
|
||||
#endif
|
||||
|
||||
#define SC64_CMD_CONFIG 'C'
|
||||
#define SC64_CMD_QUERY 'Q'
|
||||
|
||||
enum cfg_id {
|
||||
extern char *header_text_info;
|
||||
|
||||
#define SC64_BL_VERSION_BASE (PHYSICAL((io32_t *) (header_text_info)))
|
||||
|
||||
|
||||
typedef struct {
|
||||
io32_t SR_CMD;
|
||||
io32_t DATA[2];
|
||||
io32_t VERSION;
|
||||
} sc64_regs_t;
|
||||
|
||||
#define SC64_BASE (0x1FFF0000)
|
||||
#define SC64 ((sc64_regs_t *) SC64_BASE)
|
||||
|
||||
#define SC64_SR_CMD_ERROR (1 << 28)
|
||||
#define SC64_SR_CPU_BUSY (1 << 30)
|
||||
#define SC64_SR_CPU_READY (1 << 31)
|
||||
|
||||
#define SC64_CMD_CONFIG ('C')
|
||||
#define SC64_CMD_QUERY ('Q')
|
||||
#define SC64_CMD_DEBUG_TX_DATA ('D')
|
||||
#define SC64_CMD_DEBUG_TX_READY ('S')
|
||||
|
||||
#define SC64_VERSION_2 (0x53437632)
|
||||
|
||||
#define SC64_DEBUG_WRITE_ADDRESS (0x13BD8000UL)
|
||||
#define SC64_DEBUG_READ_ADDRESS (0x13BD0000UL)
|
||||
#define SC64_DEBUG_MAX_SIZE (32 * 1024)
|
||||
|
||||
#define SC64_DEBUG_TYPE_TEXT (0x01)
|
||||
|
||||
|
||||
typedef enum {
|
||||
CFG_ID_SCR,
|
||||
CFG_ID_SDRAM_SWITCH,
|
||||
CFG_ID_SDRAM_WRITABLE,
|
||||
@ -21,33 +60,61 @@ enum cfg_id {
|
||||
CFG_ID_TV_TYPE,
|
||||
CFG_ID_SAVE_OFFEST,
|
||||
CFG_ID_DD_OFFEST,
|
||||
CFG_ID_SKIP_BOOTLOADER,
|
||||
};
|
||||
CFG_ID_BOOT_MODE,
|
||||
CFG_ID_FLASH_SIZE,
|
||||
CFG_ID_FLASH_READ,
|
||||
CFG_ID_FLASH_PROGRAM,
|
||||
CFG_ID_RECONFIGURE,
|
||||
} cfg_id_t;
|
||||
|
||||
typedef enum {
|
||||
SAVE_TYPE_NONE = 0,
|
||||
SAVE_TYPE_EEPROM_4K = 1,
|
||||
SAVE_TYPE_EEPROM_16K = 2,
|
||||
SAVE_TYPE_SRAM = 3,
|
||||
SAVE_TYPE_FLASHRAM = 4,
|
||||
SAVE_TYPE_SRAM_BANKED = 5,
|
||||
SAVE_TYPE_FLASHRAM_PKST2 = 6,
|
||||
} save_type_t;
|
||||
|
||||
typedef struct sc64_config {
|
||||
union {
|
||||
uint32_t ___raw_data[2];
|
||||
struct {
|
||||
uint8_t ___unused_1[2];
|
||||
uint8_t save_type;
|
||||
uint8_t ___unused_2: 1;
|
||||
uint8_t dd_enable: 1;
|
||||
uint8_t sdram_writable: 1;
|
||||
uint8_t sdram_switch: 1;
|
||||
uint8_t ___unused_3;
|
||||
uint8_t tv_type;
|
||||
uint16_t cic_type;
|
||||
};
|
||||
};
|
||||
} sc64_config_t;
|
||||
typedef enum {
|
||||
TV_TYPE_PAL = 0,
|
||||
TV_TYPE_NTSC = 1,
|
||||
TV_TYPE_MPAL = 2,
|
||||
TV_TYPE_UNKNOWN = 3,
|
||||
} tv_type_t;
|
||||
|
||||
typedef enum {
|
||||
BOOT_MODE_MENU = 0,
|
||||
BOOT_MODE_ROM = 1,
|
||||
BOOT_MODE_DD = 2,
|
||||
BOOT_MODE_DIRECT = 3,
|
||||
} boot_mode_t;
|
||||
|
||||
typedef struct {
|
||||
bool dd_enabled;
|
||||
save_type_t save_type;
|
||||
uint8_t cic_seed;
|
||||
tv_type_t tv_type;
|
||||
io32_t *save_offset;
|
||||
io32_t *dd_offset;
|
||||
boot_mode_t boot_mode;
|
||||
char bootloader_version[32];
|
||||
} info_t;
|
||||
|
||||
|
||||
bool sc64_check_presence(void);
|
||||
void sc64_wait_cpu_ready(void);
|
||||
void sc64_wait_cpu_busy(void);
|
||||
void sc64_perform_cmd(uint8_t cmd, uint32_t *args);
|
||||
void sc64_set_config(uint32_t type, uint32_t value);
|
||||
bool sc64_wait_cpu_busy(void);
|
||||
bool sc64_perform_cmd(uint8_t cmd, uint32_t *args, uint32_t *result);
|
||||
uint32_t sc64_get_config(cfg_id_t id);
|
||||
void sc64_set_config(cfg_id_t id, uint32_t value);
|
||||
void sc64_get_info(info_t *info);
|
||||
void sc64_wait_usb_tx_ready(void);
|
||||
void sc64_usb_tx_data(io32_t *address, uint32_t length);
|
||||
void sc64_debug_write(uint8_t type, const void *data, uint32_t len);
|
||||
void sc64_debug_print(const char *text);
|
||||
void sc64_init(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define XSTR(s) STR(s)
|
||||
#define VERSION XSTR(__SC64_VERSION)
|
||||
|
||||
.section .text.bootcode
|
||||
|
||||
.section .text.rom_header
|
||||
header_pi_config:
|
||||
.word 0x80371240
|
||||
|
||||
@ -12,60 +13,38 @@ header_clock_rate:
|
||||
header_load_addr:
|
||||
.word entry_handler
|
||||
|
||||
header_release_addr:
|
||||
header_sdk_version:
|
||||
.word 0x00000000
|
||||
|
||||
header_crc:
|
||||
.fill 2, 4, 0
|
||||
|
||||
.org 0x18, 0x00
|
||||
|
||||
.org 0x20, 0x00
|
||||
header_text_info:
|
||||
.ascii "byMFinPL"
|
||||
.ascii "SummerLoader64 "
|
||||
.global header_text_info
|
||||
.ascii "SummerLoader64 "
|
||||
.ascii VERSION
|
||||
.org 0x40, 0x00
|
||||
|
||||
.org 0x40, 0x20
|
||||
|
||||
.section .text.ipl3
|
||||
ipl3:
|
||||
.incbin "blob/ipl3.bin"
|
||||
.incbin "header", 0x40
|
||||
|
||||
|
||||
.section .text.entry_handler
|
||||
.set noreorder
|
||||
entry_handler:
|
||||
.global entry_handler
|
||||
|
||||
li $a0, 0x08
|
||||
sw $a0, 0xBFC007FC
|
||||
|
||||
la $gp, _gp
|
||||
la $sp, _sp
|
||||
|
||||
init_bss:
|
||||
la $a0, _sbss
|
||||
la $a1, _ebss
|
||||
bge $a0, $a1, 2f
|
||||
nop
|
||||
1:
|
||||
sd $zero, 0($a0)
|
||||
addi $a0, $a0, 8
|
||||
blt $a0, $a1, 1b
|
||||
nop
|
||||
2:
|
||||
|
||||
init_bss_cache:
|
||||
la $a0, _sbss
|
||||
la $a1, _ebss
|
||||
bge $a0, $a1, 2f
|
||||
nop
|
||||
1:
|
||||
cache 0x15, 0($a0)
|
||||
addi $a0, $a0, 16
|
||||
blt $a0, $a1, 1b
|
||||
nop
|
||||
2:
|
||||
|
||||
run:
|
||||
j main
|
||||
nop
|
||||
la $t0, init
|
||||
jalr $t0
|
||||
|
||||
la $t0, main
|
||||
jalr $t0
|
||||
|
||||
loop:
|
||||
j loop
|
||||
|
57
sw/n64/src/sys.c
Normal file
57
sw/n64/src/sys.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
static uint32_t c0_get_count(void) {
|
||||
uint32_t x;
|
||||
asm volatile("mfc0 %0,$9" : "=r" (x));
|
||||
return x;
|
||||
}
|
||||
|
||||
void wait_ms(uint32_t ms) {
|
||||
uint32_t start = c0_get_count();
|
||||
while (c0_get_count() - start < (ms * ((CPU_FREQUENCY / 2) / 1000)));
|
||||
}
|
||||
|
||||
uint32_t io_read(io32_t *address) {
|
||||
asm volatile ("" : : : "memory");
|
||||
uint32_t value = *UNCACHED(address);
|
||||
asm volatile ("" : : : "memory");
|
||||
return value;
|
||||
}
|
||||
|
||||
void io_write(io32_t *address, uint32_t value) {
|
||||
asm volatile ("" : : : "memory");
|
||||
*UNCACHED(address) = value;
|
||||
asm volatile ("" : : : "memory");
|
||||
}
|
||||
|
||||
uint32_t pi_busy(void) {
|
||||
return (io_read(&PI->SR) & (PI_SR_IO_BUSY | PI_SR_DMA_BUSY));
|
||||
}
|
||||
|
||||
uint32_t pi_io_read(io32_t *address) {
|
||||
return io_read(address);
|
||||
}
|
||||
|
||||
void pi_io_write(io32_t *address, uint32_t value) {
|
||||
io_write(address, value);
|
||||
while (pi_busy());
|
||||
}
|
||||
|
||||
uint32_t si_busy(void) {
|
||||
return (io_read(&SI->SR) & (SI_SR_IO_BUSY | SI_SR_DMA_BUSY));
|
||||
}
|
||||
|
||||
uint32_t si_io_read(io32_t *address) {
|
||||
return io_read(address);
|
||||
}
|
||||
|
||||
void si_io_write(io32_t *address, uint32_t value) {
|
||||
io_write(address, value);
|
||||
while (si_busy());
|
||||
}
|
||||
|
||||
void init(void) {
|
||||
uint32_t pifram = si_io_read((io32_t *) (&PIFRAM[0x3C]));
|
||||
si_io_write((io32_t *) (&PIFRAM[0x3C]), pifram | 0x08);
|
||||
}
|
123
sw/n64/src/sys.h
Normal file
123
sw/n64/src/sys.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef SYS_H__
|
||||
#define SYS_H__
|
||||
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
typedef volatile uint8_t io8_t;
|
||||
typedef volatile uint32_t io32_t;
|
||||
|
||||
|
||||
#define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1))
|
||||
|
||||
#define PHYSICAL(address) ((io32_t *) (((io32_t) (address)) & 0x1FFFFFFFUL))
|
||||
#define CACHED(address) ((io32_t *) ((((io32_t) (address)) & 0x1FFFFFFFUL) | 0x80000000UL))
|
||||
#define UNCACHED(address) ((io32_t *) ((((io32_t) (address)) & 0x1FFFFFFFUL) | 0xA0000000UL))
|
||||
|
||||
#define CPU_FREQUENCY (93750000UL)
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t tv_type;
|
||||
uint32_t rom_type;
|
||||
uint32_t rom_base;
|
||||
uint32_t reset_type;
|
||||
uint32_t cic_id;
|
||||
uint32_t version;
|
||||
uint32_t mem_size;
|
||||
uint8_t app_nmi_buffer[64];
|
||||
uint32_t __reserved_1[37];
|
||||
uint32_t mem_size_6105;
|
||||
} boot_info_t;
|
||||
|
||||
#define BOOT_INFO_BASE (0x00000300UL)
|
||||
#define BOOT_INFO ((boot_info_t *) BOOT_INFO_BASE)
|
||||
|
||||
|
||||
typedef struct {
|
||||
io32_t MADDR;
|
||||
io32_t PADDR;
|
||||
io32_t RDMA;
|
||||
io32_t WDMA;
|
||||
io32_t SR;
|
||||
struct {
|
||||
io32_t LAT;
|
||||
io32_t PWD;
|
||||
io32_t PGS;
|
||||
io32_t RLS;
|
||||
} DOM[2];
|
||||
} pi_regs_t;
|
||||
|
||||
#define PI_BASE (0x04600000UL)
|
||||
#define PI ((pi_regs_t *) PI_BASE)
|
||||
|
||||
#define PI_SR_DMA_BUSY (1 << 0)
|
||||
#define PI_SR_IO_BUSY (1 << 1)
|
||||
#define PI_SR_DMA_ERROR (1 << 2)
|
||||
#define PI_SR_RESET_CONTROLLER (1 << 0)
|
||||
#define PI_SR_CLEAR_INTERRUPT (1 << 1)
|
||||
|
||||
|
||||
typedef struct {
|
||||
io32_t MADDR;
|
||||
io32_t RDMA;
|
||||
io32_t __reserved_1;
|
||||
io32_t __reserved_2;
|
||||
io32_t WDMA;
|
||||
io32_t __reserved_3;
|
||||
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 SI_SR_CLEAR_INTERRUPT (0)
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t pi_config;
|
||||
uint32_t clock_rate;
|
||||
uint32_t load_addr;
|
||||
struct {
|
||||
uint16_t __reserved_1;
|
||||
uint8_t major;
|
||||
char minor;
|
||||
} sdk_version;
|
||||
uint32_t crc[2];
|
||||
uint32_t __reserved_1[2];
|
||||
char name[20];
|
||||
uint8_t ___reserved_2[7];
|
||||
char id[4];
|
||||
uint8_t version;
|
||||
uint32_t ipl3[1008];
|
||||
} rom_header_t;
|
||||
|
||||
#define ROM_HEADER_DDIPL_BASE (0x06000000UL)
|
||||
#define ROM_HEADER_DDIPL ((rom_header_t *) ROM_HEADER_DDIPL_BASE)
|
||||
#define ROM_HEADER_CART_BASE (0x10000000UL)
|
||||
#define ROM_HEADER_CART ((rom_header_t *) ROM_HEADER_CART_BASE)
|
||||
|
||||
|
||||
#define PIFRAM_BASE (0x1FC007C0UL)
|
||||
#define PIFRAM ((io8_t *) PIFRAM_BASE)
|
||||
|
||||
|
||||
|
||||
void wait_ms(uint32_t ms);
|
||||
uint32_t io_read(io32_t *address);
|
||||
void io_write(io32_t *address, uint32_t value);
|
||||
uint32_t pi_busy(void);
|
||||
uint32_t pi_io_read(io32_t *address);
|
||||
void pi_io_write(io32_t *address, uint32_t value);
|
||||
uint32_t si_busy(void);
|
||||
uint32_t si_io_read(io32_t *address);
|
||||
void si_io_write(io32_t *address, uint32_t value);
|
||||
|
||||
|
||||
#endif
|
55
sw/n64/src/syscalls.c
Normal file
55
sw/n64/src/syscalls.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "sc64.h"
|
||||
|
||||
|
||||
int _close_r(struct _reent *prt, int fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fstat_r(struct _reent *prt, int fd, struct stat *pstat) {
|
||||
pstat->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _isatty_r(struct _reent *prt, int fd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
off_t _lseek_r(struct _reent *prt, int fd, off_t pos, int whence) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t _read_r(struct _reent *prt, int fd, void *buf, size_t cnt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
caddr_t _sbrk_r(struct _reent *prt, ptrdiff_t incr) {
|
||||
extern char _sheap;
|
||||
extern char _eheap;
|
||||
|
||||
static char *curr_heap_end = &_sheap;
|
||||
char *prev_heap_end;
|
||||
|
||||
prev_heap_end = curr_heap_end;
|
||||
curr_heap_end += incr;
|
||||
|
||||
if (curr_heap_end > &_eheap) {
|
||||
errno = ENOMEM;
|
||||
return (caddr_t) -1;
|
||||
}
|
||||
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
|
||||
ssize_t _write_r(struct _reent *prt, int fd, const void *buf, size_t cnt) {
|
||||
sc64_debug_write(SC64_DEBUG_TYPE_TEXT, buf, cnt);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
|
||||
LOG_E("\r\nassertion \"%s\" failed: file \"%s\", line %d%s%s\r\n", failedexpr, file, line, func ? ", function: " : "", func ? func : "");
|
||||
while (1);
|
||||
}
|
109
sw/pc/sc64.py
109
sw/pc/sc64.py
@ -27,9 +27,11 @@ class SC64:
|
||||
__CFG_ID_TV_TYPE = 6
|
||||
__CFG_ID_SAVE_OFFEST = 7
|
||||
__CFG_ID_DD_OFFEST = 8
|
||||
__CFG_ID_SKIP_BOOTLOADER = 9
|
||||
__CFG_ID_FLASH_OPERATION = 10
|
||||
__CFG_ID_RECONFIGURE = 11
|
||||
__CFG_ID_BOOT_MODE = 9
|
||||
__CFG_ID_FLASH_SIZE = 10
|
||||
__CFG_ID_FLASH_READ = 11
|
||||
__CFG_ID_FLASH_PROGRAM = 12
|
||||
__CFG_ID_RECONFIGURE = 13
|
||||
|
||||
__SC64_VERSION_V2 = 0x53437632
|
||||
|
||||
@ -40,6 +42,8 @@ class SC64:
|
||||
__MIN_ROM_LENGTH = 0x101000
|
||||
__DDIPL_ROM_LENGTH = 0x400000
|
||||
|
||||
__DEBUG_ID_TEXT = 0x01
|
||||
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__serial = None
|
||||
@ -88,7 +92,14 @@ class SC64:
|
||||
def __write(self, data: bytes) -> None:
|
||||
self.__serial.write(self.__escape(data))
|
||||
|
||||
|
||||
|
||||
def __read_long(self, length: int) -> bytes:
|
||||
data = bytearray()
|
||||
while (len(data) < length):
|
||||
data += self.__read(length - len(data))
|
||||
return bytes(data)
|
||||
|
||||
|
||||
def __write_dummy(self, length: int) -> None:
|
||||
self.__write(bytes(length))
|
||||
|
||||
@ -148,8 +159,8 @@ class SC64:
|
||||
raise SC64Exception(f"Unknown hardware version: {hex(version)}")
|
||||
|
||||
|
||||
def __query_config(self, id: int, arg: int = 0) -> int:
|
||||
self.__write_cmd("Q", id, arg)
|
||||
def __query_config(self, id: int) -> int:
|
||||
self.__write_cmd("Q", id, 0)
|
||||
value = self.__read_int()
|
||||
self.__read_cmd_status("Q")
|
||||
return value
|
||||
@ -211,7 +222,8 @@ class SC64:
|
||||
|
||||
|
||||
def backup_firmware(self, file: str) -> None:
|
||||
length = self.__query_config(self.__CFG_ID_FLASH_OPERATION, self.__UPDATE_OFFSET)
|
||||
length = self.__query_config(self.__CFG_ID_FLASH_SIZE)
|
||||
self.__change_config(self.__CFG_ID_FLASH_READ, self.__UPDATE_OFFSET)
|
||||
self.__read_file_from_sdram(file, self.__UPDATE_OFFSET, length)
|
||||
|
||||
|
||||
@ -219,14 +231,28 @@ class SC64:
|
||||
self.__write_file_to_sdram(file, self.__UPDATE_OFFSET)
|
||||
saved_timeout = self.__serial.timeout
|
||||
self.__serial.timeout = 20.0
|
||||
self.__change_config(self.__CFG_ID_FLASH_OPERATION, self.__UPDATE_OFFSET)
|
||||
self.__change_config(self.__CFG_ID_FLASH_PROGRAM, self.__UPDATE_OFFSET)
|
||||
self.__serial.timeout = saved_timeout
|
||||
self.__reconfigure()
|
||||
self.__find_sc64()
|
||||
|
||||
|
||||
def set_skip_bootloader(self, enable: bool) -> None:
|
||||
self.__change_config(self.__CFG_ID_SKIP_BOOTLOADER, 1 if enable else 0)
|
||||
def set_boot_mode(self, mode: int) -> None:
|
||||
if (mode >= 0 and mode <= 3):
|
||||
self.__change_config(self.__CFG_ID_BOOT_MODE, mode)
|
||||
else:
|
||||
raise SC64Exception("Boot mode outside of supported values")
|
||||
|
||||
|
||||
def get_boot_mode_label(self, mode: int) -> None:
|
||||
if (mode < 0 or mode > 3):
|
||||
return "Unknown"
|
||||
return {
|
||||
0: "Load menu from SD card",
|
||||
1: "Load ROM from SDRAM through bootloader",
|
||||
2: "Load DDIPL from SDRAM",
|
||||
3: "Load ROM from SDRAM directly without bootloader"
|
||||
}[mode]
|
||||
|
||||
|
||||
def set_tv_type(self, type: int = None) -> None:
|
||||
@ -321,6 +347,34 @@ class SC64:
|
||||
self.__write_file_to_sdram(file, dd_ipl_offset, min_length=self.__DDIPL_ROM_LENGTH)
|
||||
|
||||
|
||||
def debug_loop(self) -> None:
|
||||
print("\r\nDebug server started\r\n")
|
||||
|
||||
self.__serial.timeout = 0.01
|
||||
|
||||
while (True):
|
||||
start_indicator = self.__read_long(4)
|
||||
if (start_indicator == b"DMA@"):
|
||||
header = self.__read_long(4)
|
||||
id = int(header[0])
|
||||
length = int.from_bytes(header[1:4], byteorder="big")
|
||||
align = self.__align(length, 4) - length
|
||||
data = self.__read_long(length)
|
||||
|
||||
if (id == self.__DEBUG_ID_TEXT):
|
||||
print(data.decode(encoding="ascii", errors="backslashreplace"), end="")
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
print(f"Got unknown id: {id}, length: {length}")
|
||||
|
||||
self.__read_long(align)
|
||||
end_indicator = self.__read_long(4)
|
||||
if (end_indicator != b"CMPH"):
|
||||
print(f"Got unknown end indicator: {end_indicator.decode(encoding='ascii', errors='backslashreplace')}")
|
||||
else:
|
||||
print(f"Got unknown start indicator: {start_indicator.decode(encoding='ascii', errors='backslashreplace')}")
|
||||
|
||||
|
||||
|
||||
class SC64ProgressBar:
|
||||
__LABEL_LENGTH = 30
|
||||
@ -381,17 +435,18 @@ class SC64ProgressBar:
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="SummerCart64 one stop control center")
|
||||
parser.add_argument("-b", default=False, action="store_true", required=False, help="skip internal bootloader")
|
||||
parser.add_argument("-t", default="3", required=False, help="set TV type (0 - 2)")
|
||||
parser.add_argument("-c", default="0xFFFF", required=False, help="set CIC seed")
|
||||
parser.add_argument("-s", default="0", required=False, help="set save type (0 - 6)")
|
||||
parser.add_argument("-b", metavar="boot_mode", default="1", required=False, help="set boot mode (0 - 3)")
|
||||
parser.add_argument("-t", metavar="tv_type", default="3", required=False, help="set TV type (0 - 2)")
|
||||
parser.add_argument("-c", metavar="cic_seed", default="0xFFFF", required=False, help="set CIC seed")
|
||||
parser.add_argument("-s", metavar="save_type", default="0", required=False, help="set save type (0 - 6)")
|
||||
parser.add_argument("-d", default=False, action="store_true", required=False, help="enable 64DD emulation")
|
||||
parser.add_argument("-r", default=False, action="store_true", required=False, help="perform reading operation instead of writing")
|
||||
parser.add_argument("-l", default="0x101000", required=False, help="specify ROM length to read")
|
||||
parser.add_argument("-u", default=None, required=False, help="path to update file")
|
||||
parser.add_argument("-e", default=None, required=False, help="path to save file")
|
||||
parser.add_argument("-i", default=None, required=False, help="path to DDIPL file")
|
||||
parser.add_argument("rom", default=None, help="path to ROM file", nargs="?")
|
||||
parser.add_argument("-l", metavar="length", default="0x101000", required=False, help="specify ROM length to read")
|
||||
parser.add_argument("-u", metavar="update_path", default=None, required=False, help="path to update file")
|
||||
parser.add_argument("-e", metavar="save_path", default=None, required=False, help="path to save file")
|
||||
parser.add_argument("-i", metavar="ddipl_path", default=None, required=False, help="path to DDIPL file")
|
||||
parser.add_argument("-q", default=None, action="store_true", required=False, help="start debug server")
|
||||
parser.add_argument("rom", metavar="rom_path", default=None, help="path to ROM file", nargs="?")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -402,7 +457,7 @@ if __name__ == "__main__":
|
||||
try:
|
||||
sc64 = SC64()
|
||||
|
||||
skip_bootloader = args.b
|
||||
boot_mode = int(args.b)
|
||||
save_type = int(args.s)
|
||||
tv_type = int(args.t)
|
||||
cic_seed = int(args.c, 0)
|
||||
@ -413,6 +468,7 @@ if __name__ == "__main__":
|
||||
save_file = args.e
|
||||
dd_ipl_file = args.i
|
||||
rom_file = args.rom
|
||||
debug_server = args.q
|
||||
|
||||
firmware_backup_file = "sc64firmware.bin.bak"
|
||||
|
||||
@ -430,12 +486,12 @@ if __name__ == "__main__":
|
||||
os.remove(firmware_backup_file)
|
||||
|
||||
if (not is_read):
|
||||
print(f"Setting boot mode to [{sc64.get_boot_mode_label(boot_mode)}]")
|
||||
sc64.set_boot_mode(boot_mode)
|
||||
|
||||
print(f"Setting save type to [{sc64.get_save_type_label(save_type)}]")
|
||||
sc64.set_save_type(save_type)
|
||||
|
||||
print(f"Setting skip internal bootloader to [{'True' if skip_bootloader else 'False'}]")
|
||||
sc64.set_skip_bootloader(skip_bootloader)
|
||||
|
||||
print(f"Setting TV type to [{sc64.get_tv_type_label(tv_type)}]")
|
||||
sc64.set_tv_type(tv_type)
|
||||
|
||||
@ -466,6 +522,13 @@ if __name__ == "__main__":
|
||||
else:
|
||||
sc64.upload_save(save_file)
|
||||
|
||||
if (debug_server):
|
||||
sc64.debug_loop()
|
||||
|
||||
except SC64Exception as e:
|
||||
print(f"Error: {e}")
|
||||
parser.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
sys.stdout.write("\033[0m")
|
||||
|
@ -26,8 +26,10 @@ enum cfg_id {
|
||||
CFG_ID_TV_TYPE,
|
||||
CFG_ID_SAVE_OFFEST,
|
||||
CFG_ID_DD_OFFEST,
|
||||
CFG_ID_SKIP_BOOTLOADER,
|
||||
CFG_ID_FLASH_OPERATION,
|
||||
CFG_ID_BOOT_MODE,
|
||||
CFG_ID_FLASH_SIZE,
|
||||
CFG_ID_FLASH_READ,
|
||||
CFG_ID_FLASH_PROGRAM,
|
||||
CFG_ID_RECONFIGURE,
|
||||
};
|
||||
|
||||
@ -41,11 +43,19 @@ enum save_type {
|
||||
SAVE_TYPE_FLASHRAM_PKST2 = 6,
|
||||
};
|
||||
|
||||
enum boot_mode {
|
||||
BOOT_MODE_MENU = 0,
|
||||
BOOT_MODE_ROM = 1,
|
||||
BOOT_MODE_DD = 2,
|
||||
BOOT_MODE_DIRECT = 3,
|
||||
};
|
||||
|
||||
|
||||
struct process {
|
||||
enum save_type save_type;
|
||||
uint16_t cic_seed;
|
||||
uint8_t tv_type;
|
||||
enum boot_mode boot_mode;
|
||||
};
|
||||
|
||||
static struct process p;
|
||||
@ -136,10 +146,14 @@ void cfg_update (uint32_t *args) {
|
||||
case CFG_ID_DD_OFFEST:
|
||||
CFG->DD_OFFSET = args[1];
|
||||
break;
|
||||
case CFG_ID_SKIP_BOOTLOADER:
|
||||
change_scr_bits(CFG_SCR_SKIP_BOOTLOADER, args[1]);
|
||||
case CFG_ID_BOOT_MODE:
|
||||
p.boot_mode = args[1];
|
||||
change_scr_bits(CFG_SCR_SKIP_BOOTLOADER, args[1] == BOOT_MODE_DIRECT);
|
||||
break;
|
||||
case CFG_ID_FLASH_OPERATION:
|
||||
case CFG_ID_FLASH_READ:
|
||||
flash_read(args[1]);
|
||||
break;
|
||||
case CFG_ID_FLASH_PROGRAM:
|
||||
flash_program(args[1]);
|
||||
break;
|
||||
case CFG_ID_RECONFIGURE:
|
||||
@ -182,11 +196,11 @@ void cfg_query (uint32_t *args) {
|
||||
case CFG_ID_DD_OFFEST:
|
||||
args[1] = CFG->DD_OFFSET;
|
||||
break;
|
||||
case CFG_ID_SKIP_BOOTLOADER:
|
||||
args[1] = CFG->SCR & CFG_SCR_SKIP_BOOTLOADER;
|
||||
case CFG_ID_BOOT_MODE:
|
||||
args[1] = p.boot_mode;
|
||||
break;
|
||||
case CFG_ID_FLASH_OPERATION:
|
||||
args[1] = flash_read(args[1]);
|
||||
case CFG_ID_FLASH_SIZE:
|
||||
args[1] = flash_size();
|
||||
break;
|
||||
case CFG_ID_RECONFIGURE:
|
||||
args[1] = CFG->RECONFIGURE;
|
||||
@ -203,6 +217,7 @@ void cfg_init (void) {
|
||||
|
||||
p.cic_seed = 0xFFFF;
|
||||
p.tv_type = 0x03;
|
||||
p.boot_mode = BOOT_MODE_MENU;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
#include "flash.h"
|
||||
|
||||
|
||||
uint32_t flash_read (uint32_t sdram_offset) {
|
||||
uint32_t flash_size (void) {
|
||||
return FLASH_SIZE;
|
||||
}
|
||||
|
||||
void flash_read (uint32_t sdram_offset) {
|
||||
io32_t *flash = (io32_t *) (FLASH_BASE);
|
||||
io32_t *sdram = (io32_t *) (SDRAM_BASE + sdram_offset);
|
||||
|
||||
for (size_t i = 0; i < FLASH_SIZE; i += 4) {
|
||||
*sdram++ = *flash++;
|
||||
}
|
||||
|
||||
return FLASH_SIZE;
|
||||
}
|
||||
|
||||
void flash_program (uint32_t sdram_offset) {
|
||||
|
@ -5,7 +5,8 @@
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
uint32_t flash_read (uint32_t sdram_offset);
|
||||
uint32_t flash_size(void);
|
||||
void flash_read (uint32_t sdram_offset);
|
||||
void flash_program (uint32_t sdram_offset);
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define XSTR(s) STR(s)
|
||||
#define VERSION XSTR(__SC64_VERSION)
|
||||
|
||||
|
||||
.section .text.reset_handler
|
||||
reset_handler:
|
||||
.global reset_handler
|
||||
@ -13,16 +14,15 @@ reset_handler:
|
||||
|
||||
la sp, __stack_pointer$
|
||||
|
||||
j init_text
|
||||
|
||||
.org 0x18, 0x00
|
||||
la ra, init_text
|
||||
jalr zero, 0(ra)
|
||||
|
||||
.org 0x20, 0x00
|
||||
header_text_info:
|
||||
.ascii "byMFinPL"
|
||||
.ascii "SummerGovernor64"
|
||||
.global header_text_info
|
||||
.ascii "SummerGovernor64 "
|
||||
.ascii VERSION
|
||||
|
||||
.org 0x40, 0x20
|
||||
.org 0x40, 0x00
|
||||
|
||||
init_text:
|
||||
la a0, _sitext
|
||||
|
@ -189,4 +189,7 @@ typedef volatile struct joybus_regs {
|
||||
#define JOYBUS_SCR_TX_LENGTH_BIT (16)
|
||||
|
||||
|
||||
void reset_handler(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user