libsc64 start

This commit is contained in:
Polprzewodnikowy 2021-03-11 00:10:32 +01:00
parent d7c642f898
commit f7fef4a6ef
31 changed files with 1090 additions and 40 deletions

View File

@ -19,7 +19,7 @@
#
# Quartus Prime
# Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition
# Date created = 00:41:07 March 01, 2021
# Date created = 23:48:45 March 10, 2021
#
# -------------------------------------------------------------------------- #
#

View File

@ -23,7 +23,7 @@ module cart_control (
output reg o_eeprom_enable,
output reg o_eeprom_16k_mode,
output reg o_n64_reset_btn,
inout [7:0] io_gpio,
input i_debug_ready,
@ -57,7 +57,7 @@ module cart_control (
localparam [3:0] REG_USB_DMA_ADDR = 4'd5;
localparam [3:0] REG_USB_DMA_LEN = 4'd6;
localparam [3:0] REG_DDIPL_ADDR = 4'd7;
localparam [3:0] REG_SRAM_ADDR = 4'd8;
localparam [3:0] REG_SAVE_ADDR = 4'd8;
localparam [10:0] MEM_USB_FIFO_BASE = 11'h400;
@ -77,6 +77,11 @@ module cart_control (
reg [15:0] r_bootloader;
reg r_skip_bootloader;
reg r_sram_768k_mode;
reg [7:0] r_gpio_o;
reg [7:0] r_gpio_i;
reg [7:0] r_gpio_dir;
reg [7:0] r_gpio_od;
// Bus controller
@ -104,7 +109,6 @@ module cart_control (
o_eeprom_pi_enable <= 1'b0;
o_eeprom_enable <= 1'b0;
o_eeprom_16k_mode <= 1'b0;
o_n64_reset_btn <= 1'b1;
o_ddipl_address <= 24'hEF_8000;
o_save_address <= 24'hFF_8000;
o_debug_dma_bank <= 4'd1;
@ -112,22 +116,27 @@ module cart_control (
o_debug_dma_length <= 20'd0;
r_bootloader <= 16'h0000;
r_skip_bootloader <= 1'b0;
r_sram_768k_mode <= 1'b0;
r_gpio_o <= 8'h00;
r_gpio_dir <= 8'h00;
r_gpio_od <= 8'h00;
end else begin
if (i_request && i_write && !o_busy) begin
case (i_address[3:0])
REG_SCR: begin
{
r_skip_bootloader,
o_flashram_enable,
o_sram_enable,
o_sd_enable,
o_flashram_enable,
r_sram_768k_mode,
o_sram_enable,
o_eeprom_pi_enable,
o_eeprom_16k_mode,
o_eeprom_enable,
o_ddipl_enable,
o_rom_switch,
o_sdram_writable
} <= {i_data[10:9], i_data[7:0]};
o_sdram_writable,
o_rom_switch
} <= i_data[10:0];
end
REG_BOOT: begin
@ -135,7 +144,7 @@ module cart_control (
end
REG_GPIO: begin
o_n64_reset_btn <= ~i_data[0];
{r_gpio_od, r_gpio_dir, r_gpio_o} <= {i_data[31:16], i_data[7:0]};
end
REG_USB_SCR: begin
@ -154,7 +163,7 @@ module cart_control (
o_ddipl_address <= i_data[25:2];
end
REG_SRAM_ADDR: begin
REG_SAVE_ADDR: begin
o_save_address <= i_data[25:2];
end
@ -165,7 +174,6 @@ module cart_control (
if (!r_reset_ff2 || !r_nmi_ff2) begin
o_sdram_writable <= 1'b0;
o_rom_switch <= r_skip_bootloader;
o_n64_reset_btn <= 1'b1;
o_debug_fifo_flush <= 1'b1;
end
end
@ -185,16 +193,16 @@ module cart_control (
REG_SCR: begin
o_data[10:0] <= {
r_skip_bootloader,
o_flashram_enable,
1'b0,
o_sram_enable,
o_sd_enable,
o_flashram_enable,
r_sram_768k_mode,
o_sram_enable,
o_eeprom_pi_enable,
o_eeprom_16k_mode,
o_eeprom_enable,
o_ddipl_enable,
o_rom_switch,
o_sdram_writable
o_sdram_writable,
o_rom_switch
};
end
@ -207,7 +215,7 @@ module cart_control (
end
REG_GPIO: begin
o_data[2:0] <= {r_nmi_ff2, r_reset_ff2, ~o_n64_reset_btn};
o_data[31:0] <= {r_gpio_od, r_gpio_dir, io_gpio, r_gpio_o};
end
REG_USB_SCR: begin
@ -218,7 +226,7 @@ module cart_control (
o_data[25:0] <= {o_ddipl_address, 2'b00};
end
REG_SRAM_ADDR: begin
REG_SAVE_ADDR: begin
o_data[25:0] <= {o_save_address, 2'b00};
end
@ -231,4 +239,17 @@ module cart_control (
end
end
// GPIO logic
always @(*) begin
for (integer i = 0; i < 8; i = i + 1) begin
if (r_gpio_dir[i] && (!r_gpio_od[i] || (r_gpio_od[i] && !r_gpio_o[i]))) begin
io_gpio[i] = r_gpio_o[i];
end else begin
io_gpio[i] = 1'bZ;
end
end
end
endmodule

View File

@ -54,19 +54,19 @@ module n64_bank_decoder (
o_prefetch <= 1'b0;
end
16'b0001111000000001: begin // EEPROM
if (i_eeprom_pi_enable) begin
o_bank <= `BANK_EEPROM;
end
end
16'b0001111000000010: begin // SD
16'b0001111000000001: begin // SD
if (i_sd_enable) begin
o_bank <= `BANK_SD;
o_prefetch <= 1'b0;
end
end
16'b0001111000000011: begin // EEPROM
if (i_eeprom_pi_enable) begin
o_bank <= `BANK_EEPROM;
end
end
default: begin end
endcase
end

View File

@ -51,11 +51,7 @@ module top (
// Temporary signal names
wire w_n64_reset_btn;
assign {o_rtc_scl, io_rtc_sda} = 2'bZZ;
assign io_pmod[3] = w_n64_reset_btn ? 1'bZ : 1'b0;
assign {io_pmod[7:4], io_pmod[2:0]} = 7'bZZZZZZZ;
// PLL clock generator
@ -345,7 +341,7 @@ module top (
.o_eeprom_enable(w_eeprom_enable),
.o_eeprom_16k_mode(w_eeprom_16k_mode),
.o_n64_reset_btn(w_n64_reset_btn),
.io_gpio(io_pmod),
.i_debug_ready(1'b1), // TODO: Detect USB cable insertion

View File

@ -22,7 +22,7 @@ SOURCE_DIR = src
BUILD_DIR = build
SRC_DIRS = $(SOURCE_DIR) $(sort $(dir $(wildcard $(SOURCE_DIR)/*/.)))
INC_DIRS = $(addprefix -I, . $(SRC_DIRS))
INC_DIRS = $(addprefix -I, . $(SRC_DIRS)) -I./libsc64/inc
SRC_FILES = $(wildcard $(patsubst %, %/*.c, . $(SRC_DIRS)))
IMG_FILES = $(wildcard $(patsubst %, %/*.png, . $(SRC_DIRS)))
OBJ_FILES = $(addprefix $(BUILD_DIR)/, $(notdir $(IMG_FILES:.png=.o) $(SRC_FILES:.c=.o)))
@ -32,7 +32,7 @@ VPATH = $(SRC_DIRS)
COMMONFLAGS = -march=vr4300 -mtune=vr4300
ASFLAGS = $(COMMONFLAGS)
CFLAGS = $(COMMONFLAGS) -std=gnu99 -Os -Wall -I$(ROOTDIR)/mips64-elf/include $(INC_DIRS)
LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -ldragon -lc -lm -ldragonsys -Tn64.ld
LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -ldragon -lc -lm -ldragonsys -Tn64.ld -L./libsc64/lib -lsc64_libdragon
N64_FLAGS = -l $(ROM_SIZE) -h $(HEADER_PATH)/$(HEADER_NAME) -o $(BUILD_DIR)/$(PROG_NAME).z64
N64_FLAGS_PADDED = -l 1028k -h $(HEADER_PATH)/$(HEADER_NAME) -o $(BUILD_DIR)/$(PROG_NAME)_padded.z64

View File

@ -1,10 +1,10 @@
#!/bin/bash
LIBDRAGON_DOCKER_VERSION=latest
build_in_docker() {
docker run -t \
--mount type=bind,src=`realpath $(pwd)`,target="/src" \
--mount type=bind,src=`realpath "$(pwd)/../libsc64"`,target="/src/libsc64" \
$1 /bin/bash -c "cd /src && make clean && make -f $2 all"
}
docker \
run \
-t \
--mount type=bind,src=`realpath "$(dirname $0)"`,target="/libdragon" \
anacierdem/libdragon:$LIBDRAGON_DOCKER_VERSION \
/bin/bash -c "make clean && make all"
build_in_docker "anacierdem/libdragon:latest" "Makefile"

2
sw/libsc64/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/lib
/output

View File

@ -0,0 +1,37 @@
SRC_DIRS = src
INC_DIRS = inc
OUTPUT_DIR = lib
BUILD_DIR = output/$(LIB_BUILD_DIR)
SRC_FILES = boot.c control.c gpio.c helpers.c init.c io_dma.c save.c sd.c usb.c
CFLAGS += -ffunction-sections -fdata-sections -Os -Wall -MMD -MP $(patsubst %, -I%, $(INC_DIRS))
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(SRC_FILES:.c=.o)))
DEPS = $(OBJS:.o=.d)
VPATH = $(SRC_DIRS)
all: create_build_dirs $(OUTPUT_DIR)/$(LIB_NAME).a
create_build_dirs: $(OUTPUT_DIR) $(BUILD_DIR)
$(OUTPUT_DIR):
mkdir -p ./$(OUTPUT_DIR)
$(BUILD_DIR):
mkdir -p ./$(BUILD_DIR)
$(BUILD_DIR)/%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(OUTPUT_DIR)/$(LIB_NAME).a: $(OBJS)
$(AR) -rcs -o $@ $(OBJS)
clean:
rm -rf ./$(BUILD_DIR) 2> /dev/null
rm -rf ./$(OUTPUT_DIR) 2> /dev/null
.PHONY: all clean create_build_dirs
-include $(DEPS)

View File

@ -0,0 +1,11 @@
TOOLCHAIN = $(N64_INST)/bin/mips64-elf-
CC = $(TOOLCHAIN)gcc
AR = $(TOOLCHAIN)ar
LIB_NAME = libsc64_libdragon
LIB_BUILD_DIR = libdragon
CFLAGS += -march=vr4300 -mtune=vr4300 -DLIBDRAGON
include Makefile.common

View File

@ -0,0 +1,9 @@
include $(ROOT)/usr/include/make/PRdefs
LIB_NAME = libsc64_libultra
LIB_BUILD_DIR = libultra
CFLAGS += -I$(ROOT)/usr/include/nustd -DLIBULTRA
include Makefile.common

11
sw/libsc64/build.sh Normal file
View File

@ -0,0 +1,11 @@
#!/bin/bash
build_in_docker() {
docker run -t \
--mount type=bind,src=`realpath $(pwd)`,target="/src" \
$1 /bin/bash -c "cd /src && make -f $2 all"
}
build_in_docker "anacierdem/libdragon:latest" "Makefile.libdragon"
build_in_docker "polprzewodnikowy/n64sdkmod:latest" "Makefile.libultra"

31
sw/libsc64/inc/boot.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef SC64_BOOT_H__
#define SC64_BOOT_H__
#include <stdbool.h>
#include <stdint.h>
typedef union sc64_boot_config_s {
uint32_t _packed_value;
struct {
uint16_t _padding: 16;
bool skip_menu: 1;
bool cic_seed_override: 1;
bool tv_type_override: 1;
bool ddipl_override: 1;
bool rom_loaded: 1;
uint8_t tv_type: 2;
uint8_t os_version: 1;
uint8_t cic_seed: 8;
};
} sc64_boot_config_t;
void sc64_boot_config_set(sc64_boot_config_t *boot_config);
void sc64_boot_config_get(sc64_boot_config_t *boot_config);
void sc64_boot_skip_bootloader(bool is_enabled);
#endif

20
sw/libsc64/inc/control.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef SC64_CONTROL_H__
#define SC64_CONTROL_H__
#include <stdbool.h>
#include <stdint.h>
void sc64_control_sdram_writable(bool is_enabled);
void sc64_control_embedded_flash_access(bool is_enabled);
uint32_t sc64_control_version_get(void);
void sc64_control_ddipl_access(bool is_enabled);
void sc64_control_ddipl_address_set(uint32_t address);
uint32_t sc64_control_ddipl_address_get(void);
#endif

26
sw/libsc64/inc/gpio.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef SC64_GPIO_H__
#define SC64_GPIO_H__
#include <stdint.h>
typedef enum sc64_gpio_mode_e {
MODE_INPUT,
MODE_OUTPUT,
MODE_OPEN_DRAIN,
} sc64_gpio_mode_t;
void sc64_gpio_init(void);
void sc64_gpio_mode_set(uint8_t num, sc64_gpio_mode_t mode);
void sc64_gpio_output_write(uint8_t value);
void sc64_gpio_output_set(uint8_t mask);
void sc64_gpio_output_clear(uint8_t mask);
uint8_t sc64_gpio_input_get(void);
#endif

15
sw/libsc64/inc/helpers.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef SC64_HELPERS_H__
#define SC64_HELPERS_H__
#include <stdbool.h>
#include <stdint.h>
void sc64_helpers_reg_write(volatile uint32_t *pi_address, uint32_t mask, bool mask_mode);
void sc64_helpers_reg_set(volatile uint32_t *pi_address, uint32_t mask);
void sc64_helpers_reg_clear(volatile uint32_t *pi_address, uint32_t mask);
#endif

8
sw/libsc64/inc/init.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef SC64_INIT_H__
#define SC64_INIT_H__
void sc64_init(void);
#endif

18
sw/libsc64/inc/io_dma.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef SC64_IO_DMA_H__
#define SC64_IO_DMA_H__
#include <stdint.h>
#include <stdlib.h>
void sc64_io_dma_init(void);
void sc64_io_write(volatile uint32_t *pi_address, uint32_t value);
uint32_t sc64_io_read(volatile uint32_t *pi_address);
void sc64_dma_write(void *ram_address, volatile uint32_t *pi_address, size_t length);
void sc64_dma_read(void *ram_address, volatile uint32_t *pi_address, size_t length);
#endif

15
sw/libsc64/inc/libsc64.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef LIBSC64_H__
#define LIBSC64_H__
#include "boot.h"
#include "control.h"
#include "gpio.h"
#include "io_dma.h"
#include "init.h"
#include "save.h"
#include "sd.h"
#include "usb.h"
#endif

178
sw/libsc64/inc/registers.h Normal file
View File

@ -0,0 +1,178 @@
#ifndef SC64_REGISTERS_H__
#define SC64_REGISTERS_H__
#include <stdint.h>
// Bank definitions
#define SC64_BANK_SDRAM (1)
#define SC64_BANK_EEPROM (3)
// Cart Interface Registers
typedef struct sc64_cart_registers {
volatile uint32_t SCR; // Cart status and control
volatile uint32_t BOOT; // Boot behavior control
volatile uint32_t VERSION; // Cart firmware version
volatile uint32_t GPIO; // GPIO control
volatile uint32_t USB_SCR; // USB interface status and control
volatile uint32_t USB_DMA_ADDR; // USB address for DMA to PC
volatile uint32_t USB_DMA_LEN; // USB transfer length for DMA to PC
volatile uint32_t DDIPL_ADDR; // 64 Disk Drive IPL location in SDRAM
volatile uint32_t SAVE_ADDR; // SRAM/FlashRAM save emulation location in SDRAM
volatile uint32_t _unused[1015];
volatile uint32_t USB_FIFO[1024]; // USB data from PC read FIFO memory
} sc64_cart_registers_t;
#define SC64_CART_BASE (0x1E000000)
#define SC64_CART ((volatile sc64_cart_registers_t *) SC64_CART_BASE)
// SCR
#define SC64_CART_SCR_SKIP_BOOTLOADER (1 << 10)
#define SC64_CART_SCR_SD_ENABLE (1 << 9)
#define SC64_CART_SCR_FLASHRAM_ENABLE (1 << 8)
#define SC64_CART_SCR_SRAM_768K_MODE (1 << 7)
#define SC64_CART_SCR_SRAM_ENABLE (1 << 6)
#define SC64_CART_SCR_EEPROM_PI_ENABLE (1 << 5)
#define SC64_CART_SCR_EEPROM_16K_MODE (1 << 4)
#define SC64_CART_SCR_EEPROM_ENABLE (1 << 3)
#define SC64_CART_SCR_DDIPL_ENABLE (1 << 2)
#define SC64_CART_SCR_SDRAM_WRITABLE (1 << 1)
#define SC64_CART_SCR_ROM_SWITCH (1 << 0)
// GPIO
#define SC64_CART_GPIO_OFFSET_OUTPUT (0)
#define SC64_CART_GPIO_OFFSET_INPUT (8)
#define SC64_CART_GPIO_OFFSET_DIR (16)
#define SC64_CART_GPIO_OFFSET_OPEN_DRAIN (24)
// USB_SCR
#define SC64_CART_USB_SCR_FIFO_ITEMS(s) (((s) >> 3) & 0x7FF)
#define SC64_CART_USB_SCR_READY (1 << 1)
#define SC64_CART_USB_SCR_DMA_BUSY (1 << 0)
#define SC64_CART_USB_SCR_FIFO_FLUSH (1 << 2)
#define SC64_CART_USB_SCR_DMA_START (1 << 0)
// USB_DMA_ADDR
#define SC64_CART_USB_DMA_ADDR(a) ((SC64_BANK_SDRAM << 28) | ((a) & 0x3FFFFFC))
// USB_DMA_LEN
#define SC64_CART_USB_DMA_LEN(l) (((l) - 1) & 0xFFFFF)
// SD Card Interface Registers
typedef struct sc64_sd_registers_s {
volatile uint32_t SCR; // Clock control and bus width selection
volatile uint32_t ARG; // SD command argument
volatile uint32_t CMD; // SD command index and flags
volatile uint32_t RSP; // SD command response
volatile uint32_t DAT; // SD data path control
volatile uint32_t DMA_SCR; // DMA status and configuration
volatile uint32_t DMA_ADDR; // DMA current address
volatile uint32_t DMA_LEN; // DMA remaining length
volatile uint32_t _unused[120];
volatile uint32_t FIFO[128]; // SD data path FIFO buffer
} sc64_sd_registers_t;
#define SC64_SD_BASE (0x1E010000)
#define SC64_SD ((volatile sc64_sd_registers_t *) SC64_SD_BASE)
// SCR
#define SC64_SD_SCR_DAT_WIDTH (1 << 2)
#define SC64_SD_SCR_CLK_MASK (0x3 << 0)
#define SC64_SD_SCR_CLK_STOP (0 << 0)
#define SC64_SD_SCR_CLK_400_KHZ (1 << 0)
#define SC64_SD_SCR_CLK_25_MHZ (2 << 0)
#define SC64_SD_SCR_CLK_50_MHZ (3 << 0)
// CMD
#define SC64_SD_CMD_RESPONSE_CRC_ERROR (1 << 8)
#define SC64_SD_CMD_TIMEOUT (1 << 7)
#define SC64_SD_CMD_BUSY (1 << 6)
#define SC64_SD_CMD_INDEX_GET(cmd) ((cmd) & 0x3F)
#define SC64_SD_CMD_SKIP_RESPONSE (1 << 8)
#define SC64_SD_CMD_LONG_RESPONSE (1 << 7)
#define SC64_SD_CMD_START (1 << 6)
#define SC64_SD_CMD_INDEX(i) ((i) & 0x3F)
// DAT
#define SC64_SD_DAT_WRITE_OK (1 << 28)
#define SC64_SD_DAT_WRITE_ERROR (1 << 27)
#define SC64_SD_DAT_WRITE_BUSY (1 << 26)
#define SC64_SD_DAT_TX_FIFO_ITEMS_GET(dat) (((dat) >> 17) & 0x1FF)
#define SC64_SD_DAT_TX_FIFO_BYTES_GET(dat) (SC64_SD_DAT_TX_FIFO_ITEMS_GET(dat) * 4)
#define SC64_SD_DAT_TX_FIFO_FULL (1 << 16)
#define SC64_SD_DAT_TX_FIFO_EMPTY (1 << 15)
#define SC64_SD_DAT_TX_FIFO_UNDERRUN (1 << 14)
#define SC64_SD_DAT_RX_FIFO_ITEMS_GET(dat) (((dat) >> 5) & 0x1FF)
#define SC64_SD_DAT_RX_FIFO_BYTES_GET(dat) (SC64_SD_DAT_RX_FIFO_ITEMS_GET(dat) * 4)
#define SC64_SD_DAT_RX_FIFO_FULL (1 << 4)
#define SC64_SD_DAT_RX_FIFO_EMPTY (1 << 3)
#define SC64_SD_DAT_RX_FIFO_OVERRUN (1 << 2)
#define SC64_SD_DAT_CRC_ERROR (1 << 1)
#define SC64_SD_DAT_BUSY (1 << 0)
#define SC64_SD_DAT_TX_FIFO_FLUSH (1 << 19)
#define SC64_SD_DAT_RX_FIFO_FLUSH (1 << 18)
#define SC64_SD_DAT_NUM_BLOCKS(nb) ((((nb) - 1) & 0xFF) << 10)
#define SC64_SD_DAT_BLOCK_SIZE(bs) (((((bs) / 4) - 1) & 0x7F) << 3)
#define SC64_SD_DAT_DIRECTION (1 << 2)
#define SC64_SD_DAT_STOP (1 << 1)
#define SC64_SD_DAT_START (1 << 0)
#define SC64_SD_DAT_FIFO_SIZE_BYTES (1024)
#define SC64_SD_DAT_NUM_BLOCKS_MAX (256)
#define SC64_SD_DAT_BLOCK_SIZE_MAX (512)
// DMA_SCR
#define SC64_SD_DMA_SCR_BUSY (1 << 0)
#define SC64_SD_DMA_SCR_DIRECTION (1 << 2)
#define SC64_SD_DMA_SCR_STOP (1 << 1)
#define SC64_SD_DMA_SCR_START (1 << 0)
// DMA_ADDR
#define SC64_SD_DMA_ADDR_GET(addr) ((addr) & 0x3FFFFFC)
#define SC64_SD_DMA_BANK_GET(addr) (((addr) >> 28) & 0xF)
#define SC64_SD_DMA_BANK_ADDR(b, a) ((((b) & 0xF) << 28) | ((a) & 0x3FFFFFC))
// DMA_LEN
#define SC64_SD_DMA_LEN_GET(len) (((len) & 0x7FFF) * 4)
#define SC64_SD_DMA_LEN(l) ((((l) / 4) - 1) & 0x7FFF)
#define SC64_SD_DMA_LEN_MAX (0x20000)
// EEPROM Block RAM
#define SC64_EEPROM_BASE (0x1E030000)
#define SC64_EEPROM ((volatile uint8_t *) SC64_EEPROM_BASE)
#define SC64_EEPROM_SIZE ((16 * 1024) / 8)
#endif

31
sw/libsc64/inc/save.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef SC64_SAVE_H__
#define SC64_SAVE_H__
#include <stdbool.h>
#include <stdint.h>
typedef enum sc64_save_type_e {
SC64_SAVE_DISABLED,
SC64_SAVE_EEPROM_4K,
SC64_SAVE_EEPROM_16K,
SC64_SAVE_SRAM_256K,
SC64_SAVE_SRAM_768K,
SC64_SAVE_FLASHRAM_1M,
} sc64_save_type_t;
void sc64_save_type_set(sc64_save_type_t save_type);
sc64_save_type_t sc64_save_type_get(void);
void sc64_save_address_set(uint32_t address);
uint32_t sc64_save_address_get(void);
void sc64_save_eeprom_pi_access(bool is_enabled);
void sc64_save_write(void *ram_address);
void sc64_save_read(void *ram_address);
#endif

34
sw/libsc64/inc/sd.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef SC64_SD_H__
#define SC64_SD_H__
#include <stdbool.h>
#include <stdint.h>
void sc64_sd_access(bool is_enabled);
// typedef enum sc64_sd_err_e {
// E_OK,
// E_TIMEOUT,
// E_CRC_ERROR,
// E_BAD_INDEX,
// E_PAR_ERROR,
// E_FIFO_ERROR,
// E_WRITE_ERROR,
// E_NO_INIT,
// } sc64_sd_err_t;
// bool sc64_sd_init(void);
// void sc64_sd_deinit(void);
// bool sc64_sd_status_get(void);
// sc64_sd_err_t sc64_sd_sectors_read(uint32_t starting_sector, size_t count, uint8_t *buffer);
// sc64_sd_err_t sc64_sd_sectors_write(uint32_t starting_sector, size_t count, uint8_t *buffer);
// sc64_sd_err_t sc64_sd_sectors_read_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address);
// // sc64_sd_err_t sc64_sd_sectors_write_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address);
// sc64_sd_err_t sc64_sd_dat_busy_wait(void);
#endif

8
sw/libsc64/inc/usb.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef SC64_USB_H__
#define SC64_USB_H__
#endif

17
sw/libsc64/src/boot.c Normal file
View File

@ -0,0 +1,17 @@
#include "boot.h"
#include "helpers.h"
#include "io_dma.h"
#include "registers.h"
void sc64_boot_skip_bootloader(bool is_enabled) {
sc64_helpers_reg_write(&SC64_CART->SCR, SC64_CART_SCR_SKIP_BOOTLOADER, is_enabled);
}
void sc64_boot_config_set(sc64_boot_config_t *boot_config) {
sc64_io_write(&SC64_CART->BOOT, boot_config->_packed_value);
}
void sc64_boot_config_get(sc64_boot_config_t *boot_config) {
boot_config->_packed_value = sc64_io_read(&SC64_CART->BOOT);
}

29
sw/libsc64/src/control.c Normal file
View File

@ -0,0 +1,29 @@
#include "control.h"
#include "helpers.h"
#include "io_dma.h"
#include "registers.h"
void sc64_control_sdram_writable(bool is_enabled) {
sc64_helpers_reg_write(&SC64_CART->SCR, SC64_CART_SCR_SDRAM_WRITABLE, is_enabled);
}
void sc64_control_embedded_flash_access(bool is_enabled) {
sc64_helpers_reg_write(&SC64_CART->SCR, SC64_CART_SCR_ROM_SWITCH, !is_enabled);
}
uint32_t sc64_control_version_get(void) {
return sc64_io_read(&SC64_CART->VERSION);
}
void sc64_control_ddipl_access(bool is_enabled) {
sc64_helpers_reg_write(&SC64_CART->SCR, SC64_CART_SCR_DDIPL_ENABLE, is_enabled);
}
void sc64_control_ddipl_address_set(uint32_t address) {
sc64_io_write(&SC64_CART->DDIPL_ADDR, address);
}
uint32_t sc64_control_ddipl_address_get(void) {
return sc64_io_read(&SC64_CART->DDIPL_ADDR);
}

63
sw/libsc64/src/gpio.c Normal file
View File

@ -0,0 +1,63 @@
#include "gpio.h"
#include "io_dma.h"
#include "registers.h"
static uint32_t gpio_state;
void sc64_gpio_init(void) {
gpio_state = 0;
sc64_io_write(&SC64_CART->GPIO, gpio_state);
}
void sc64_gpio_mode_set(uint8_t num, sc64_gpio_mode_t mode) {
if (num >= 8) {
return;
}
gpio_state &= ~(
((1 << num) << SC64_CART_GPIO_OFFSET_OPEN_DRAIN) |
((1 << num) << SC64_CART_GPIO_OFFSET_DIR)
);
switch (mode) {
case MODE_OUTPUT:
gpio_state |= ((1 << num) << SC64_CART_GPIO_OFFSET_DIR);
break;
case MODE_OPEN_DRAIN:
gpio_state |= (
((1 << num) << SC64_CART_GPIO_OFFSET_OPEN_DRAIN) |
((1 << num) << SC64_CART_GPIO_OFFSET_DIR)
);
break;
default:
break;
}
sc64_io_write(&SC64_CART->GPIO, gpio_state);
}
void sc64_gpio_output_write(uint8_t value) {
gpio_state &= ~(0xFF << SC64_CART_GPIO_OFFSET_OUTPUT);
gpio_state |= (value << SC64_CART_GPIO_OFFSET_OUTPUT);
sc64_io_write(&SC64_CART->GPIO, gpio_state);
}
void sc64_gpio_output_set(uint8_t mask) {
gpio_state |= (mask << SC64_CART_GPIO_OFFSET_OUTPUT);
sc64_io_write(&SC64_CART->GPIO, gpio_state);
}
void sc64_gpio_output_clear(uint8_t mask) {
gpio_state &= ~(mask << SC64_CART_GPIO_OFFSET_OUTPUT);
sc64_io_write(&SC64_CART->GPIO, gpio_state);
}
uint8_t sc64_gpio_input_get(void) {
return (uint8_t) ((sc64_io_read(&SC64_CART->GPIO) >> SC64_CART_GPIO_OFFSET_INPUT) & 0xFF);
}

24
sw/libsc64/src/helpers.c Normal file
View File

@ -0,0 +1,24 @@
#include "helpers.h"
#include "io_dma.h"
#include "registers.h"
void sc64_helpers_reg_write(volatile uint32_t *pi_address, uint32_t mask, bool mask_mode) {
uint32_t reg = sc64_io_read(pi_address);
if (mask_mode) {
reg |= mask;
} else {
reg &= ~mask;
}
sc64_io_write(pi_address, reg);
}
void sc64_helpers_reg_set(volatile uint32_t *pi_address, uint32_t mask) {
sc64_helpers_reg_write(pi_address, mask, true);
}
void sc64_helpers_reg_clear(volatile uint32_t *pi_address, uint32_t mask) {
sc64_helpers_reg_write(pi_address, mask, false);
}

8
sw/libsc64/src/init.c Normal file
View File

@ -0,0 +1,8 @@
#include "gpio.h"
#include "io_dma.h"
void sc64_init(void) {
sc64_io_dma_init();
sc64_gpio_init();
}

69
sw/libsc64/src/io_dma.c Normal file
View File

@ -0,0 +1,69 @@
#include "io_dma.h"
#ifndef LIBDRAGON
#ifndef LIBULTRA
#error "Please specify used library with -DLIBDRAGON or -DLIBULTRA"
#endif
#endif
#ifdef LIBDRAGON
#include <libdragon.h>
#endif
#ifdef LIBULTRA
#include <ultra64.h>
static OSMesg pi_message;
static OSIoMesg pi_io_message;
static OSMesgQueue pi_message_queue;
#endif
void sc64_io_dma_init(void) {
#ifdef LIBULTRA
osCreateMesgQueue(&pi_message_queue, &pi_message, 1);
#endif
}
void sc64_io_write(volatile uint32_t *pi_address, uint32_t value) {
#ifdef LIBDRAGON
io_write((uint32_t) pi_address, value);
#elif LIBULTRA
osPiWriteIo((u32) pi_address, value);
#endif
}
uint32_t sc64_io_read(volatile uint32_t *pi_address) {
#ifdef LIBDRAGON
return io_read((uint32_t) pi_address);
#elif LIBULTRA
u32 value;
osPiReadIo((u32) pi_address, &value);
return value;
#endif
}
void sc64_dma_write(void *ram_address, volatile uint32_t *pi_address, size_t length) {
#ifdef LIBDRAGON
data_cache_hit_writeback_invalidate(ram_address, length);
dma_write(ram_address, (uint32_t) pi_address, length);
#elif LIBULTRA
osWritebackDCache(ram_address, length);
osPiStartDma(&pi_io_message, OS_MESG_PRI_NORMAL, OS_WRITE, (u32) pi_address, ram_address, length, &pi_message_queue);
osRecvMesg(&pi_message_queue, NULL, OS_MESG_BLOCK);
#endif
}
void sc64_dma_read(void *ram_address, volatile uint32_t *pi_address, size_t length) {
#ifdef LIBDRAGON
dma_read(ram_address, (uint32_t) pi_address, length);
data_cache_hit_writeback_invalidate(ram_address, length);
#elif LIBULTRA
osPiStartDma(&pi_io_message, OS_MESG_PRI_NORMAL, OS_READ, (u32) pi_address, ram_address, length, &pi_message_queue);
osRecvMesg(&pi_message_queue, NULL, OS_MESG_BLOCK);
osInvalDCache(ram_address, length);
#endif
}

157
sw/libsc64/src/save.c Normal file
View File

@ -0,0 +1,157 @@
#include "control.h"
#include "helpers.h"
#include "io_dma.h"
#include "registers.h"
#include "save.h"
static bool sc64_save_address_length_get(uint32_t *pi_address, size_t *length, bool *is_eeprom) {
sc64_save_type_t save_type = sc64_save_type_get();
*is_eeprom = false;
switch (save_type) {
case SC64_SAVE_EEPROM_4K:
*pi_address = SC64_EEPROM_BASE;
*length = 512;
*is_eeprom = true;
break;
case SC64_SAVE_EEPROM_16K:
*pi_address = SC64_EEPROM_BASE;
*length = 2048;
*is_eeprom = true;
break;
case SC64_SAVE_SRAM_256K:
*pi_address = sc64_save_address_get();
*length = (32 * 1024);
break;
case SC64_SAVE_SRAM_768K:
*pi_address = sc64_save_address_get();
*length = (96 * 1024);
break;
case SC64_SAVE_FLASHRAM_1M:
*pi_address = sc64_save_address_get();
*length = (128 * 1024);
break;
default:
return false;
}
return true;
}
void sc64_save_type_set(sc64_save_type_t save_type) {
uint32_t scr;
scr = sc64_io_read(&SC64_CART->SCR);
scr &= ~(
SC64_CART_SCR_FLASHRAM_ENABLE |
SC64_CART_SCR_SRAM_768K_MODE |
SC64_CART_SCR_SRAM_ENABLE |
SC64_CART_SCR_EEPROM_16K_MODE |
SC64_CART_SCR_EEPROM_ENABLE
);
switch (save_type)
{
case SC64_SAVE_EEPROM_4K:
scr |= SC64_CART_SCR_EEPROM_ENABLE;
break;
case SC64_SAVE_EEPROM_16K:
scr |= SC64_CART_SCR_EEPROM_ENABLE | SC64_CART_SCR_EEPROM_16K_MODE;
break;
case SC64_SAVE_SRAM_256K:
scr |= SC64_CART_SCR_SRAM_ENABLE;
break;
case SC64_SAVE_SRAM_768K:
scr |= SC64_CART_SCR_SRAM_ENABLE | SC64_CART_SCR_SRAM_768K_MODE;
break;
case SC64_SAVE_FLASHRAM_1M:
scr |= SC64_CART_SCR_FLASHRAM_ENABLE;
break;
default:
break;
}
sc64_io_write(&SC64_CART->SCR, scr);
}
sc64_save_type_t sc64_save_type_get(void) {
uint32_t scr;
scr = sc64_io_read(&SC64_CART->SCR);
if (scr & SC64_CART_SCR_FLASHRAM_ENABLE) {
return SC64_SAVE_FLASHRAM_1M;
} else if (scr & SC64_CART_SCR_SRAM_ENABLE) {
return (scr & SC64_CART_SCR_SRAM_768K_MODE) ? SC64_SAVE_SRAM_768K : SC64_SAVE_SRAM_256K;
} else if (scr & SC64_CART_SCR_EEPROM_ENABLE) {
return (scr & SC64_CART_SCR_EEPROM_16K_MODE) ? SC64_SAVE_EEPROM_16K : SC64_SAVE_EEPROM_4K;
}
return SC64_SAVE_DISABLED;
}
void sc64_save_address_set(uint32_t address) {
sc64_io_write(&SC64_CART->SAVE_ADDR, address);
}
uint32_t sc64_save_address_get(void) {
return sc64_io_read(&SC64_CART->SAVE_ADDR);
}
void sc64_save_eeprom_pi_access(bool is_enabled) {
sc64_helpers_reg_write(&SC64_CART->SCR, SC64_CART_SCR_EEPROM_PI_ENABLE, is_enabled);
}
void sc64_save_write(void *ram_address) {
uint32_t pi_address;
size_t length;
bool is_eeprom;
uint32_t scr;
bool eeprom_pi_access;
bool sdram_writable;
if (sc64_save_address_length_get(&pi_address, &length, &is_eeprom)) {
scr = sc64_io_read(&SC64_CART->SCR);
eeprom_pi_access = scr & SC64_CART_SCR_EEPROM_PI_ENABLE;
sdram_writable = scr & SC64_CART_SCR_SDRAM_WRITABLE;
if (is_eeprom && !eeprom_pi_access) {
sc64_save_eeprom_pi_access(true);
} else if (!sdram_writable) {
sc64_control_sdram_writable(true);
}
sc64_dma_write(ram_address, (volatile uint32_t *) pi_address, length);
if (is_eeprom && !eeprom_pi_access) {
sc64_save_eeprom_pi_access(false);
} else if (!sdram_writable) {
sc64_control_sdram_writable(false);
}
}
}
void sc64_save_read(void *ram_address) {
uint32_t pi_address;
size_t length;
bool is_eeprom;
bool eeprom_pi_access;
if (sc64_save_address_length_get(&pi_address, &length, &is_eeprom)) {
eeprom_pi_access = sc64_io_read(&SC64_CART->SCR) & SC64_CART_SCR_EEPROM_PI_ENABLE;
if (is_eeprom && !eeprom_pi_access) {
sc64_save_eeprom_pi_access(true);
}
sc64_dma_read(ram_address, (volatile uint32_t *) pi_address, length);
if (is_eeprom && !eeprom_pi_access) {
sc64_save_eeprom_pi_access(false);
}
}
}

211
sw/libsc64/src/sd.c Normal file
View File

@ -0,0 +1,211 @@
#include "helpers.h"
#include "registers.h"
#include "sd.h"
void sc64_sd_access(bool is_enabled) {
sc64_helpers_reg_write(&SC64_CART->SCR, SC64_CART_SCR_SD_ENABLE, is_enabled);
}
// #include "registers.h"
// #include "sd.h"
// #include "io_dma.h"
// #define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8)
// #define CMD8_ARG_CHECK_PATTERN_AA (0xAA << 0)
// #define ACMD41_ARG_HCS (1 << 30)
// #define R3_CCS (1 << 30)
// #define R3_BUSY (1 << 31)
// #define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8)
// #define R7_CHECK_PATTERN_AA (0xAA << 0)
// #define SD_BLOCK_SIZE (512)
// typedef enum sc64_sd_cmd_flags_e {
// NO_FLAGS = 0,
// ACMD = (1 << 0),
// SKIP_RESPONSE = (1 << 1),
// LONG_RESPONSE = (1 << 2),
// IGNORE_CRC = (1 << 3),
// IGNORE_INDEX = (1 << 4),
// } sc64_sd_cmd_flags_t;
// static bool sd_card_initialized = false;
// static bool sd_card_type_block = false;
// static bool sd_card_selected = false;
// static uint32_t sd_card_rca = 0;
// static uint8_t sd_buffer[64] __attribute__((aligned(16)));
// static void sc64_sd_clock_set(uint32_t clock) {
// uint32_t scr = sc64_io_read(&SC64_SD->SCR);
// sc64_io_write(&SC64_SD->SCR, (scr & (~SC64_SD_SCR_CLK_MASK)) | (clock & SC64_SD_SCR_CLK_MASK));
// }
// static void sc64_sd_dat_4bit_set(bool is_4bit) {
// uint32_t scr = sc64_io_read(&SC64_SD->SCR);
// scr &= ~SC64_SD_SCR_DAT_WIDTH;
// if (is_4bit) {
// scr |= SC64_SD_SCR_DAT_WIDTH;
// }
// sc64_io_write(&SC64_SD->SCR, scr);
// }
// static void sc64_sd_peripheral_reset(void) {
// while (sc64_io_read(&SC64_SD->CMD) & SC64_SD_CMD_BUSY);
// sc64_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP);
// sc64_io_write(&SC64_SD->DAT, SC64_SD_DAT_TX_FIFO_FLUSH | SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP);
// sc64_io_write(&SC64_SD->SCR, 0);
// }
// static void sc64_sd_peripheral_init(void) {
// sc64_control_sd_enable();
// sc64_sd_peripheral_reset();
// }
// static void sc64_sd_peripheral_deinit(void) {
// if (sc64_control_sd_is_enabled()) {
// sc64_sd_peripheral_reset();
// }
// sc64_control_sd_disable();
// }
// static bool sc64_sd_cmd_send(uint8_t index, uint32_t arg, sc64_sd_cmd_flags_t flags, uint32_t *response) {
// uint32_t reg;
// if (flags & ACMD) {
// if (!sc64_sd_cmd_send(55, sd_card_rca, NO_FLAGS, response)) {
// return false;
// }
// }
// sc64_io_write(&SC64_SD->ARG, arg);
// reg = SC64_SD_CMD_START | SC64_SD_CMD_INDEX(index);
// if (flags & SKIP_RESPONSE) {
// reg |= SC64_SD_CMD_SKIP_RESPONSE;
// }
// if (flags & LONG_RESPONSE) {
// reg |= SC64_SD_CMD_LONG_RESPONSE;
// }
// sc64_io_write(&SC64_SD->CMD, reg);
// do {
// reg = sc64_io_read(&SC64_SD->CMD);
// } while (reg & SC64_SD_CMD_BUSY);
// *response = sc64_io_read(&SC64_SD->RSP);
// return (
// (reg & SC64_SD_CMD_TIMEOUT) |
// ((!(flags & SKIP_RESPONSE)) && (
// ((!(flags & IGNORE_CRC)) && (reg & SC64_SD_CMD_RESPONSE_CRC_ERROR)) |
// ((!(flags & IGNORE_INDEX)) && (SC64_SD_CMD_INDEX_GET(reg) != index))
// ))
// );
// }
// bool sc64_sd_init(void) {
// bool success;
// uint32_t response;
// uint32_t argument;
// if (sd_card_initialized) {
// return true;
// }
// sc64_sd_peripheral_init();
// do {
// sc64_sd_cmd_send(0, 0, SKIP_RESPONSE, &response);
// argument = CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN_AA;
// success = sc64_sd_cmd_send(8, argument, NO_FLAGS, &response);
// if (success && (response != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN_AA))) {
// break;
// }
// argument = (success ? ACMD41_ARG_HCS : 0) | 0x00FF8000;
// for (int i = 0; i < 4000; i++) {
// success = sc64_sd_cmd_send(41, argument, ACMD | IGNORE_CRC | IGNORE_INDEX, &response);
// if (!success || (response & R3_BUSY)) {
// break;
// }
// }
// if (!success || ((response & 0x00FF8000) == 0)) {
// break;
// }
// sd_card_type_block = (response & R3_CCS) ? true : false;
// success = sc64_sd_cmd_send(2, 0, LONG_RESPONSE | IGNORE_INDEX, &response);
// if (!success) {
// break;
// }
// success = sc64_sd_cmd_send(3, 0, NO_FLAGS, &response);
// if (!success) {
// break;
// }
// sd_card_rca = response & 0xFFFF0000;
// success = sc64_sd_cmd_send(7, sd_card_rca, NO_FLAGS, &response);
// if (!success) {
// break;
// }
// sd_card_selected = true;
// success = sc64_sd_cmd_send(6, 2, ACMD, &response);
// if (!success) {
// break;
// }
// sc64_sd_clock_set(SC64_SD_SCR_CLK_25_MHZ);
// sc64_sd_dat_4bit_set(true);
// sc64_sd_dat_prepare(1, 64, DAT_DIR_RX);
// success = sc64_sd_cmd_send(6, 0x00000001, NO_FLAGS, &response);
// if (!success) {
// sc64_sd_dat_abort();
// break;
// }
// success = sc64_sd_dat_read(64, sd_buffer);
// if (!success) {
// break;
// }
// if (sd_buffer[13] & 0x02) {
// sc64_sd_dat_prepare(1, 64, DAT_DIR_RX);
// success = sc64_sd_cmd_send(6, 0x80000001, NO_FLAGS, &response);
// if (!success) {
// sc64_sd_dat_abort();
// break;
// }
// success = sc64_sd_dat_read(64, sd_buffer);
// if (!success) {
// break;
// }
// sc64_sd_clock_set(SC64_SD_SCR_CLK_50_MHZ);
// }
// sd_card_initialized = true;
// return true;
// } while(0);
// sc64_sd_deinit();
// return false;
// }

1
sw/libsc64/src/usb.c Normal file
View File

@ -0,0 +1 @@
#include "usb.h"