mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2025-02-16 12:19:11 +01:00
huge controller sw cleanup
This commit is contained in:
parent
ef205d218a
commit
545d906a68
@ -71,8 +71,8 @@
|
||||
<parameter name="SECTOR_ACCESS_MODE">Read only,Read only,Hidden,Read only,Read only</parameter>
|
||||
<parameter name="autoInitializationFileName">$${FILENAME}_onchip_flash_0</parameter>
|
||||
<parameter name="initFlashContent" value="true" />
|
||||
<parameter name="initializationFileName">../sw/n64/bootloader/build/SummerLoader64.hex</parameter>
|
||||
<parameter name="initializationFileNameForSim">../sw/n64/bootloader/build/SummerLoader64.hex</parameter>
|
||||
<parameter name="initializationFileName">../sw/n64/build/SummerLoader64.hex</parameter>
|
||||
<parameter name="initializationFileNameForSim">../sw/n64/build/SummerLoader64.hex</parameter>
|
||||
<parameter name="useNonDefaultInitFile" value="true" />
|
||||
</module>
|
||||
<interconnectRequirement for="$system" name="qsys_mm.clockCrossingAdapter" value="HANDSHAKE" />
|
||||
|
@ -9,13 +9,11 @@ int main(void) {
|
||||
|
||||
sc64_wait_cpu_ready();
|
||||
|
||||
sc64_set_config(SC64_CONFIG_SDRAM_SWITCH, true);
|
||||
sc64_set_config(CFG_ID_SDRAM_SWITCH, true);
|
||||
|
||||
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);
|
||||
|
||||
// sc64_print_debug(cic_seed << 16 | (tv_type & 0x03), cart_header->pi_conf, cart_header->boot_addr);
|
||||
|
||||
boot(cart_header, cic_seed, tv_type);
|
||||
}
|
||||
|
@ -46,15 +46,3 @@ void sc64_set_config(uint32_t type, uint32_t value) {
|
||||
uint32_t args[2] = { type, value };
|
||||
sc64_perform_cmd(SC64_CMD_CONFIG, args);
|
||||
}
|
||||
|
||||
void sc64_get_config(sc64_config_t *config) {
|
||||
uint32_t args[2] = { SC64_CONFIG_NOP, 0 };
|
||||
sc64_perform_cmd(SC64_CMD_CONFIG, args);
|
||||
config->___raw_data[0] = args[0];
|
||||
config->___raw_data[1] = args[1];
|
||||
}
|
||||
|
||||
void sc64_print_debug(uint32_t a1, uint32_t a2, uint32_t a3) {
|
||||
// uint32_t args[3] = { a1, a2, a3 };
|
||||
// sc64_perform_cmd(SC64_CMD_DEBUG, args);
|
||||
}
|
||||
|
@ -9,15 +9,19 @@
|
||||
#define SC64_CFG_SCR_CPU_BUSY (1 << 30)
|
||||
|
||||
#define SC64_CMD_CONFIG 'C'
|
||||
#define SC64_CMD_DEBUG 'D'
|
||||
#define SC64_CMD_QUERY 'Q'
|
||||
|
||||
#define SC64_CONFIG_SDRAM_SWITCH 0
|
||||
#define SC64_CONFIG_SDRAM_WRITABLE 1
|
||||
#define SC64_CONFIG_DD_ENABLE 2
|
||||
#define SC64_CONFIG_SAVE_TYPE 3
|
||||
#define SC64_CONFIG_CIC_TYPE 4
|
||||
#define SC64_CONFIG_TV_TYPE 5
|
||||
#define SC64_CONFIG_NOP 0xFFFFFFFF
|
||||
enum cfg_id {
|
||||
CFG_ID_SCR,
|
||||
CFG_ID_SDRAM_SWITCH,
|
||||
CFG_ID_SDRAM_WRITABLE,
|
||||
CFG_ID_DD_ENABLE,
|
||||
CFG_ID_SAVE_TYPE,
|
||||
CFG_ID_CIC_SEED,
|
||||
CFG_ID_TV_TYPE,
|
||||
CFG_ID_SAVE_OFFEST,
|
||||
CFG_ID_DD_OFFEST,
|
||||
};
|
||||
|
||||
|
||||
typedef struct sc64_config {
|
||||
@ -43,8 +47,6 @@ 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);
|
||||
void sc64_get_config(sc64_config_t *config);
|
||||
void sc64_print_debug(uint32_t a1, uint32_t a2, uint32_t a3);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -7,8 +7,8 @@ import sys
|
||||
class SC64:
|
||||
__SDRAM_SIZE = 64 * 1024 * 1024
|
||||
|
||||
__CONFIG_QUERY_SAVE_TYPE = 1
|
||||
__CONFIG_QUERY_SAVE_OFFSET = 4
|
||||
__CONFIG_QUERY_SAVE_TYPE = 4
|
||||
__CONFIG_QUERY_SAVE_OFFSET = 7
|
||||
|
||||
def __init__(self, port):
|
||||
self.__serial = serial.Serial(port)
|
||||
|
@ -29,6 +29,8 @@ $(BUILD_DIR)/controller.rom: $(BUILD_DIR)/uc.elf
|
||||
$(OBJCOPY) -R .bootloader $(BUILD_DIR)/uc.elf $(BUILD_DIR)/controller.elf
|
||||
$(OBJCOPY) -O binary --set-section-flags .bss=alloc,contents $(BUILD_DIR)/controller.elf $(BUILD_DIR)/controller.bin
|
||||
python3 tools/bin2rom.py $@ < $(BUILD_DIR)/controller.bin
|
||||
@echo 'Size of controller modules:'
|
||||
@$(SIZE) -B -t --common $(OBJS)
|
||||
@echo 'Size of controller:'
|
||||
@$(SIZE) -B build/controller.elf
|
||||
|
||||
|
@ -9,7 +9,6 @@ ENTRY(reset_handler)
|
||||
|
||||
SECTIONS {
|
||||
.text : {
|
||||
PROVIDE(__app_entry_point = .);
|
||||
*(.text.app_handler)
|
||||
*(.text.unlikely .text.unlikely.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
|
202
sw/riscv/src/cfg.c
Normal file
202
sw/riscv/src/cfg.c
Normal file
@ -0,0 +1,202 @@
|
||||
#include "cfg.h"
|
||||
#include "joybus.h"
|
||||
|
||||
|
||||
#define SAVE_SIZE_EEPROM_4K (512)
|
||||
#define SAVE_SIZE_EEPROM_16K (2048)
|
||||
#define SAVE_SIZE_SRAM (32 * 1024)
|
||||
#define SAVE_SIZE_FLASHRAM (128 * 1024)
|
||||
#define SAVE_SIZE_SRAM_BANKED (3 * 32 * 1024)
|
||||
|
||||
#define SAVE_OFFSET_PKST2 (0x01608000UL)
|
||||
|
||||
#define DEFAULT_SAVE_OFFSET (0x03FE0000UL)
|
||||
#define DEFAULT_DD_OFFSET (0x03BE0000UL)
|
||||
|
||||
|
||||
enum cfg_id {
|
||||
CFG_ID_SCR,
|
||||
CFG_ID_SDRAM_SWITCH,
|
||||
CFG_ID_SDRAM_WRITABLE,
|
||||
CFG_ID_DD_ENABLE,
|
||||
CFG_ID_SAVE_TYPE,
|
||||
CFG_ID_CIC_SEED,
|
||||
CFG_ID_TV_TYPE,
|
||||
CFG_ID_SAVE_OFFEST,
|
||||
CFG_ID_DD_OFFEST,
|
||||
};
|
||||
|
||||
enum save_type {
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
struct process {
|
||||
enum save_type save_type;
|
||||
uint16_t cic_seed;
|
||||
uint8_t tv_type;
|
||||
};
|
||||
|
||||
static struct process p;
|
||||
|
||||
|
||||
static void scr_set_bit (uint32_t mask) {
|
||||
CFG->SCR |= mask;
|
||||
}
|
||||
|
||||
static void scr_clr_bit (uint32_t mask) {
|
||||
CFG->SCR &= ~(mask);
|
||||
}
|
||||
|
||||
static void set_save_type (enum save_type save_type) {
|
||||
uint32_t save_offset = DEFAULT_SAVE_OFFSET;
|
||||
|
||||
scr_clr_bit(CFG_SCR_FLASHRAM_EN | CFG_SCR_SRAM_BANKED | CFG_SCR_SRAM_EN);
|
||||
joybus_set_eeprom(EEPROM_NONE);
|
||||
|
||||
switch (save_type) {
|
||||
case SAVE_TYPE_NONE:
|
||||
break;
|
||||
case SAVE_TYPE_EEPROM_4K:
|
||||
save_offset = SDRAM_SIZE - SAVE_SIZE_EEPROM_4K;
|
||||
joybus_set_eeprom(EEPROM_4K);
|
||||
break;
|
||||
case SAVE_TYPE_EEPROM_16K:
|
||||
save_offset = SDRAM_SIZE - SAVE_SIZE_EEPROM_16K;
|
||||
joybus_set_eeprom(EEPROM_16K);
|
||||
break;
|
||||
case SAVE_TYPE_SRAM:
|
||||
save_offset = SDRAM_SIZE - SAVE_SIZE_SRAM;
|
||||
CFG->SCR |= CFG_SCR_SRAM_EN;
|
||||
break;
|
||||
case SAVE_TYPE_FLASHRAM:
|
||||
save_offset = SDRAM_SIZE - SAVE_SIZE_FLASHRAM;
|
||||
CFG->SCR |= CFG_SCR_FLASHRAM_EN;
|
||||
break;
|
||||
case SAVE_TYPE_SRAM_BANKED:
|
||||
save_offset = SDRAM_SIZE - SAVE_SIZE_SRAM_BANKED;
|
||||
CFG->SCR |= CFG_SCR_SRAM_BANKED | CFG_SCR_SRAM_EN;
|
||||
break;
|
||||
case SAVE_TYPE_FLASHRAM_PKST2:
|
||||
save_offset = SAVE_OFFSET_PKST2;
|
||||
CFG->SCR |= CFG_SCR_FLASHRAM_EN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
p.save_type = save_type;
|
||||
|
||||
CFG->SAVE_OFFSET = save_offset;
|
||||
}
|
||||
|
||||
|
||||
void cfg_update (uint32_t *args) {
|
||||
switch (args[0]) {
|
||||
case CFG_ID_SCR:
|
||||
CFG->SCR = args[1];
|
||||
break;
|
||||
case CFG_ID_SDRAM_SWITCH:
|
||||
(args[1] ? scr_set_bit : scr_clr_bit)(CFG_SCR_SDRAM_SWITCH);
|
||||
break;
|
||||
case CFG_ID_SDRAM_WRITABLE:
|
||||
(args[1] ? scr_set_bit : scr_clr_bit)(CFG_SCR_SDRAM_WRITABLE);
|
||||
break;
|
||||
case CFG_ID_DD_ENABLE:
|
||||
(args[1] ? scr_set_bit : scr_clr_bit)(CFG_SCR_DD_EN);
|
||||
break;
|
||||
case CFG_ID_SAVE_TYPE:
|
||||
set_save_type((enum save_type)(args[1]));
|
||||
break;
|
||||
case CFG_ID_CIC_SEED:
|
||||
p.cic_seed = (uint16_t)(args[1] & 0xFFFF);
|
||||
break;
|
||||
case CFG_ID_TV_TYPE:
|
||||
p.tv_type = (uint8_t)(args[1] & 0x03);
|
||||
break;
|
||||
case CFG_ID_SAVE_OFFEST:
|
||||
CFG->SAVE_OFFSET = args[1];
|
||||
break;
|
||||
case CFG_ID_DD_OFFEST:
|
||||
CFG->DD_OFFSET = args[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cfg_query (uint32_t *args) {
|
||||
switch (args[0]) {
|
||||
case CFG_ID_SCR:
|
||||
args[1] = CFG->SCR;
|
||||
break;
|
||||
case CFG_ID_SDRAM_SWITCH:
|
||||
args[1] = CFG->SCR & CFG_SCR_SDRAM_SWITCH;
|
||||
break;
|
||||
case CFG_ID_SDRAM_WRITABLE:
|
||||
args[1] = CFG->SCR & CFG_SCR_SDRAM_WRITABLE;
|
||||
break;
|
||||
case CFG_ID_DD_ENABLE:
|
||||
args[1] = CFG->SCR & CFG_SCR_DD_EN;
|
||||
break;
|
||||
case CFG_ID_SAVE_TYPE:
|
||||
args[1] = (uint32_t)(p.save_type);
|
||||
break;
|
||||
case CFG_ID_CIC_SEED:
|
||||
args[1] = (uint32_t)(p.cic_seed);
|
||||
break;
|
||||
case CFG_ID_TV_TYPE:
|
||||
args[1] = (uint32_t)(p.tv_type);
|
||||
break;
|
||||
case CFG_ID_SAVE_OFFEST:
|
||||
args[1] = CFG->SAVE_OFFSET;
|
||||
break;
|
||||
case CFG_ID_DD_OFFEST:
|
||||
args[1] = CFG->DD_OFFSET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cfg_init (void) {
|
||||
set_save_type(SAVE_TYPE_NONE);
|
||||
CFG->DD_OFFSET = DEFAULT_DD_OFFSET;
|
||||
CFG->SCR = CFG_SCR_CPU_READY | CFG_SCR_SDRAM_SWITCH;
|
||||
p.cic_seed = 0xFFFF;
|
||||
p.tv_type = 0x03;
|
||||
}
|
||||
|
||||
|
||||
void process_cfg (void) {
|
||||
uint32_t args[2];
|
||||
|
||||
if (CFG->SCR & CFG_SCR_CPU_BUSY) {
|
||||
scr_clr_bit(CFG_SCR_CMD_ERROR);
|
||||
|
||||
args[0] = CFG->DATA[0];
|
||||
args[1] = CFG->DATA[1];
|
||||
|
||||
switch (CFG->CMD) {
|
||||
case 'C':
|
||||
cfg_update(args);
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
cfg_query(args);
|
||||
break;
|
||||
|
||||
default:
|
||||
scr_set_bit(CFG_SCR_CMD_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
CFG->DATA[0] = args[0];
|
||||
CFG->DATA[1] = args[1];
|
||||
|
||||
scr_clr_bit(CFG_SCR_CPU_BUSY);
|
||||
}
|
||||
}
|
14
sw/riscv/src/cfg.h
Normal file
14
sw/riscv/src/cfg.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef CFG_H__
|
||||
#define CFG_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
void cfg_update (uint32_t *args);
|
||||
void cfg_query (uint32_t *args);
|
||||
void cfg_init (void);
|
||||
void process_cfg (void);
|
||||
|
||||
|
||||
#endif
|
@ -1,550 +0,0 @@
|
||||
#include "sys.h"
|
||||
#include "driver.h"
|
||||
#include "controller.h"
|
||||
|
||||
|
||||
static e_cfg_save_type_t save_type = CFG_SAVE_TYPE_NONE;
|
||||
static uint16_t cic_seed = 0xFFFF;
|
||||
static uint8_t tv_type = 0xFF;
|
||||
|
||||
static bool eeprom_enabled = false;
|
||||
|
||||
static bool rtc_running = true;
|
||||
static uint8_t rtc_wp_bits = SI_RTC_WP_MASK;
|
||||
static uint8_t current_time[7];
|
||||
static uint8_t new_time[7];
|
||||
static bool new_time_pending = false;
|
||||
|
||||
static bool n64_to_pc_pending = false;
|
||||
static uint32_t n64_to_pc_address;
|
||||
static uint32_t n64_to_pc_length;
|
||||
|
||||
static bool pc_to_n64_ready = false;
|
||||
static uint32_t pc_to_n64_arg;
|
||||
static uint32_t pc_to_n64_address;
|
||||
static uint32_t pc_to_n64_length;
|
||||
|
||||
|
||||
void process_usb (void);
|
||||
void process_cfg (void);
|
||||
void process_flashram (void);
|
||||
void process_si (void);
|
||||
void process_rtc (void);
|
||||
void process_uart (void);
|
||||
|
||||
|
||||
bool debug_decide (uint32_t *args);
|
||||
void config_update (uint32_t *args);
|
||||
void config_query (uint32_t *args);
|
||||
|
||||
|
||||
void main (void) {
|
||||
GPIO->ODR = 0x00;
|
||||
GPIO->OER = (1 << 0);
|
||||
|
||||
dma_abort();
|
||||
usb_flush_rx();
|
||||
usb_flush_tx();
|
||||
si_reset();
|
||||
i2c_stop();
|
||||
|
||||
cfg_set_sdram_switch(true);
|
||||
cfg_set_save_type(CFG_SAVE_TYPE_NONE);
|
||||
cfg_set_dd_offset(CFG_DEFAULT_DD_OFFSET);
|
||||
cfg_set_cpu_ready(true);
|
||||
|
||||
print("App ready!\r\n");
|
||||
|
||||
while (1) {
|
||||
process_usb();
|
||||
process_cfg();
|
||||
process_flashram();
|
||||
process_si();
|
||||
process_rtc();
|
||||
process_uart();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_usb (void) {
|
||||
static e_usb_state_t state = USB_STATE_IDLE;
|
||||
static uint8_t cmd;
|
||||
static uint32_t args[2];
|
||||
static bool error = false;
|
||||
static bool processing = false;
|
||||
static uint8_t current_word = 0;
|
||||
|
||||
switch (state) {
|
||||
case USB_STATE_IDLE:
|
||||
if (usb_rx_word(&args[0])) {
|
||||
if ((args[0] & 0xFFFFFF00) == USB_CMD_TOKEN) {
|
||||
cmd = args[0] & 0xFF;
|
||||
error = false;
|
||||
processing = false;
|
||||
current_word = 0;
|
||||
state = USB_STATE_ARGS;
|
||||
} else {
|
||||
cmd = '!';
|
||||
error = true;
|
||||
state = USB_STATE_RESPONSE;
|
||||
}
|
||||
} else if (n64_to_pc_pending) {
|
||||
if (!dma_busy()) {
|
||||
dma_start(n64_to_pc_address, n64_to_pc_length, DMA_ID_USB, DMA_DIR_FROM_SDRAM);
|
||||
state = USB_STATE_N64_TO_PC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_STATE_ARGS:
|
||||
if (usb_rx_word(&args[current_word])) {
|
||||
current_word += 1;
|
||||
if (current_word == 2) {
|
||||
state = USB_STATE_DATA;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_STATE_DATA:
|
||||
switch (cmd) {
|
||||
case 'C':
|
||||
config_update(args);
|
||||
state = USB_STATE_RESPONSE;
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
if (!processing) {
|
||||
config_query(args);
|
||||
processing = true;
|
||||
} else if (usb_tx_word(args[1])) {
|
||||
state = USB_STATE_RESPONSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
case 'W':
|
||||
if (!dma_busy()) {
|
||||
if (!processing) {
|
||||
e_dma_id_t id = args[1] >> 30;
|
||||
e_dma_dir_t dir = cmd == 'W' ? DMA_DIR_TO_SDRAM : DMA_DIR_FROM_SDRAM;
|
||||
dma_start(args[0], args[1], id, dir);
|
||||
processing = true;
|
||||
} else {
|
||||
state = USB_STATE_RESPONSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
cfg_set_usb_waiting(true);
|
||||
pc_to_n64_arg = args[0];
|
||||
pc_to_n64_length = args[1];
|
||||
state = USB_STATE_PC_TO_N64;
|
||||
break;
|
||||
|
||||
default:
|
||||
error = true;
|
||||
state = USB_STATE_RESPONSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_STATE_RESPONSE:
|
||||
if (usb_tx_word(error ? USB_ERR_TOKEN : (USB_CMP_TOKEN | cmd))) {
|
||||
state = USB_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_STATE_N64_TO_PC:
|
||||
if (!dma_busy()) {
|
||||
n64_to_pc_pending = false;
|
||||
state = USB_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_STATE_PC_TO_N64:
|
||||
if (!dma_busy()) {
|
||||
if (!processing) {
|
||||
if (pc_to_n64_ready) {
|
||||
dma_start(pc_to_n64_address, pc_to_n64_length, DMA_ID_USB, DMA_DIR_TO_SDRAM);
|
||||
processing = true;
|
||||
}
|
||||
} else {
|
||||
pc_to_n64_ready = false;
|
||||
processing = false;
|
||||
state = USB_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
state = USB_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void process_cfg (void) {
|
||||
uint8_t cmd;
|
||||
uint32_t args[2];
|
||||
bool error;
|
||||
|
||||
if (cfg_get_command(&cmd, args)) {
|
||||
switch (cmd) {
|
||||
case 'C':
|
||||
config_update(args);
|
||||
cfg_set_response(args, false);
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
config_query(args);
|
||||
cfg_set_response(args, false);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
error = debug_decide(args);
|
||||
cfg_set_response(args, error);
|
||||
break;
|
||||
|
||||
default:
|
||||
cfg_set_response(args, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_flashram (void) {
|
||||
e_flashram_op_t op = flashram_get_pending_operation();
|
||||
|
||||
if (op != FLASHRAM_OP_NONE) {
|
||||
uint32_t length = flashram_get_operation_length(op);
|
||||
uint32_t page = flashram_get_page();
|
||||
uint32_t offset = cfg_get_save_offset() + (page * FLASHRAM_PAGE_SIZE);
|
||||
volatile uint32_t *src = flashram_get_page_buffer();
|
||||
volatile uint32_t *dst = (uint32_t *) (SDRAM_BASE + offset);
|
||||
|
||||
for (uint32_t i = 0; i < (length / 4); i++) {
|
||||
if (op == FLASHRAM_OP_WRITE_PAGE) {
|
||||
dst[i] &= src[i];
|
||||
} else {
|
||||
dst[i] = FLASHRAM_ERASE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
flashram_set_operation_done();
|
||||
}
|
||||
}
|
||||
|
||||
void process_si (void) {
|
||||
uint8_t rx_data[10];
|
||||
uint8_t tx_data[12];
|
||||
uint32_t *save_data;
|
||||
uint32_t *data_offset;
|
||||
|
||||
if (si_rx_ready()) {
|
||||
if (si_rx_stop_bit()) {
|
||||
si_rx(rx_data);
|
||||
|
||||
for (size_t i = 0; i < sizeof(tx_data); i++) {
|
||||
tx_data[i] = 0x00;
|
||||
}
|
||||
|
||||
if (eeprom_enabled) {
|
||||
save_data = (uint32_t *) (SDRAM_BASE + cfg_get_save_offset() + (rx_data[1] * 8));
|
||||
switch (rx_data[0]) {
|
||||
case SI_CMD_EEPROM_STATUS:
|
||||
tx_data[1] = save_type == CFG_SAVE_TYPE_EEPROM_4K ? SI_EEPROM_ID_4K : SI_EEPROM_ID_16K;
|
||||
si_tx(tx_data, 3);
|
||||
break;
|
||||
|
||||
case SI_CMD_EEPROM_READ:
|
||||
data_offset = (uint32_t *) (&tx_data[0]);
|
||||
data_offset[0] = swapb(save_data[0]);
|
||||
data_offset[1] = swapb(save_data[1]);
|
||||
si_tx(tx_data, 8);
|
||||
break;
|
||||
|
||||
case SI_CMD_EEPROM_WRITE:
|
||||
data_offset = (uint32_t *) (&rx_data[2]);
|
||||
save_data[0] = swapb(data_offset[0]);
|
||||
save_data[1] = swapb(data_offset[1]);
|
||||
si_tx(tx_data, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (rx_data[0]) {
|
||||
case SI_CMD_RTC_STATUS:
|
||||
tx_data[1] = SI_RTC_ID;
|
||||
tx_data[2] = SI_RTC_STATUS(rtc_running);
|
||||
si_tx(tx_data, 3);
|
||||
break;
|
||||
|
||||
case SI_CMD_RTC_READ:
|
||||
if (rx_data[1] == 0) {
|
||||
tx_data[0] = rtc_wp_bits;
|
||||
if (!rtc_running) {
|
||||
tx_data[1] = SI_RTC_ST_MASK;
|
||||
}
|
||||
} else if (rx_data[1] == 2) {
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
tx_data[i] = current_time[i];
|
||||
}
|
||||
tx_data[7] = SI_RTC_CENTURY_20XX;
|
||||
}
|
||||
tx_data[8] = SI_RTC_STATUS(rtc_running);
|
||||
si_tx(tx_data, 9);
|
||||
break;
|
||||
|
||||
case SI_CMD_RTC_WRITE:
|
||||
if (rx_data[1] == 0) {
|
||||
rtc_wp_bits = rx_data[2] & SI_RTC_WP_MASK;
|
||||
rtc_running = (!(rx_data[3] & SI_RTC_ST_MASK));
|
||||
} else if (rx_data[1] == 2) {
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
new_time[i] = rx_data[i + 2];
|
||||
}
|
||||
new_time_pending = !rtc_running;
|
||||
}
|
||||
tx_data[0] = SI_RTC_STATUS(rtc_running);
|
||||
si_tx(tx_data, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
si_rx_reset();
|
||||
}
|
||||
}
|
||||
|
||||
void process_rtc (void) {
|
||||
static e_rtc_state_t state = RTC_STATE_READ;
|
||||
static e_rtc_state_t next_state = RTC_STATE_READ;
|
||||
static uint8_t phase = 0;
|
||||
static uint8_t sub_phase = 0;
|
||||
static uint8_t rtc_current_time[7];
|
||||
static uint8_t rtc_new_time[7];
|
||||
|
||||
if (new_time_pending) {
|
||||
new_time_pending = false;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
current_time[i] = new_time[i];
|
||||
}
|
||||
|
||||
rtc_convert_from_n64(new_time, rtc_new_time);
|
||||
|
||||
rtc_new_time[RTC_RTCSEC] |= RTC_RTCSEC_ST;
|
||||
rtc_new_time[RTC_RTCWKDAY] |= RTC_RTCWKDAY_VBAT;
|
||||
|
||||
next_state = RTC_STATE_WRITE;
|
||||
}
|
||||
|
||||
// TODO: Rewrite this mess
|
||||
if (!i2c_busy()) {
|
||||
if (state == RTC_STATE_READ) {
|
||||
switch (phase) {
|
||||
case 0: phase++; i2c_start(); break;
|
||||
case 1: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 2: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
|
||||
case 3: phase++; i2c_start(); break;
|
||||
case 4: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
|
||||
case 5:
|
||||
if (sub_phase > 0) {
|
||||
rtc_current_time[sub_phase - 1] = i2c_get_data();
|
||||
}
|
||||
if (sub_phase < 7) {
|
||||
i2c_begin_trx(0xFF, true);
|
||||
}
|
||||
if (sub_phase == 7) {
|
||||
phase++;
|
||||
sub_phase = 0;
|
||||
if (next_state != RTC_STATE_WRITE) {
|
||||
rtc_convert_to_n64(rtc_current_time, current_time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
sub_phase++;
|
||||
break;
|
||||
case 6: phase = 0; i2c_stop(); state = next_state; break;
|
||||
}
|
||||
} else if (state == RTC_STATE_WRITE) {
|
||||
switch (phase) {
|
||||
case 0: phase++; break;
|
||||
|
||||
case 1: phase++; i2c_start(); break;
|
||||
case 2: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 3: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
|
||||
case 4: phase++; i2c_begin_trx(0x00, false); break;
|
||||
case 5: phase++; i2c_stop(); break;
|
||||
|
||||
case 6: phase++; i2c_start(); break;
|
||||
case 7: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 8: phase++; i2c_begin_trx(RTC_RTCWKDAY, false); break;
|
||||
case 9: phase++; i2c_start(); break;
|
||||
case 10: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
|
||||
case 11: phase++; i2c_begin_trx(0xFF, false); break;
|
||||
case 12: phase = (i2c_get_data() & RTC_RTCWKDAY_OSCRUN) ? 6 : 13; i2c_stop(); break;
|
||||
|
||||
case 13: phase++; i2c_start(); break;
|
||||
case 14: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 15: phase++; i2c_begin_trx(RTC_RTCMIN, false); break;
|
||||
case 16:
|
||||
if (sub_phase < 6) {
|
||||
i2c_begin_trx(rtc_new_time[RTC_RTCMIN + sub_phase], false);
|
||||
sub_phase++;
|
||||
} else {
|
||||
phase++;
|
||||
sub_phase = 0;
|
||||
i2c_stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case 17: phase++; i2c_start(); break;
|
||||
case 18: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 19: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
|
||||
case 20: phase++; i2c_begin_trx(rtc_new_time[RTC_RTCSEC], false); break;
|
||||
case 21: phase++; i2c_stop(); break;
|
||||
|
||||
case 22: phase++; i2c_start(); break;
|
||||
case 23: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 24: phase++; i2c_begin_trx(RTC_RTCWKDAY, false); break;
|
||||
case 25: phase++; i2c_start(); break;
|
||||
case 26: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
|
||||
case 27: phase++; i2c_begin_trx(0xFF, false); break;
|
||||
case 28:
|
||||
if (i2c_get_data() & RTC_RTCWKDAY_OSCRUN) {
|
||||
phase = 0;
|
||||
state = RTC_STATE_READ;
|
||||
next_state = RTC_STATE_READ;
|
||||
} else {
|
||||
phase = 22;
|
||||
}
|
||||
i2c_stop();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
state = RTC_STATE_READ;
|
||||
phase = 0;
|
||||
sub_phase = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_uart (void) {
|
||||
if (UART->SCR & USB_SCR_RXNE) {
|
||||
char cmd = UART->DR;
|
||||
|
||||
switch (cmd) {
|
||||
case '/':
|
||||
print("Bootloader reset...\r\n");
|
||||
reset_handler();
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
print("App reset...\r\n");
|
||||
app_handler();
|
||||
break;
|
||||
|
||||
case 't':
|
||||
print("Current time: ");
|
||||
for (int i = 0; i < 7; i++) {
|
||||
print_02hex(current_time[i]);
|
||||
print(" ");
|
||||
}
|
||||
print("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool debug_decide (uint32_t *args) {
|
||||
switch (args[0]) {
|
||||
case DEBUG_WRITE_ADDRESS:
|
||||
if (!n64_to_pc_pending) {
|
||||
n64_to_pc_address = args[1];
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DEBUG_WRITE_LENGTH_START:
|
||||
if (!n64_to_pc_pending) {
|
||||
n64_to_pc_length = args[1];
|
||||
n64_to_pc_pending = true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DEBUG_WRITE_STATUS:
|
||||
args[1] = n64_to_pc_pending;
|
||||
break;
|
||||
case DEBUG_READ_ARG:
|
||||
args[1] = pc_to_n64_arg;
|
||||
break;
|
||||
case DEBUG_READ_LENGTH:
|
||||
args[1] = pc_to_n64_length;
|
||||
break;
|
||||
case DEBUG_READ_ADDRESS_START:
|
||||
if (!pc_to_n64_ready) {
|
||||
pc_to_n64_ready = true;
|
||||
pc_to_n64_address = args[1];
|
||||
cfg_set_usb_waiting(false);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void config_update (uint32_t *args) {
|
||||
switch (args[0]) {
|
||||
case CONFIG_UPDATE_SDRAM_SWITCH:
|
||||
cfg_set_sdram_switch(args[1]);
|
||||
break;
|
||||
case CONFIG_UPDATE_SDRAM_WRITABLE:
|
||||
cfg_set_sdram_writable(args[1]);
|
||||
break;
|
||||
case CONFIG_UPDATE_DD_ENABLE:
|
||||
cfg_set_dd_enable(args[1]);
|
||||
break;
|
||||
case CONFIG_UPDATE_SAVE_TYPE:
|
||||
save_type = args[1] & 0x07;
|
||||
eeprom_enabled = (
|
||||
save_type == CFG_SAVE_TYPE_EEPROM_4K ||
|
||||
save_type == CFG_SAVE_TYPE_EEPROM_16K
|
||||
);
|
||||
cfg_set_save_type(save_type);
|
||||
break;
|
||||
case CONFIG_UPDATE_CIC_SEED:
|
||||
cic_seed = args[1] & 0xFFFF;
|
||||
break;
|
||||
case CONFIG_UPDATE_TV_TYPE:
|
||||
tv_type = args[1] & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void config_query (uint32_t *args) {
|
||||
switch (args[0]) {
|
||||
case CONFIG_QUERY_STATUS:
|
||||
args[1] = cfg_get_status();
|
||||
break;
|
||||
case CONFIG_QUERY_SAVE_TYPE:
|
||||
args[1] = save_type;
|
||||
break;
|
||||
case CONFIG_QUERY_CIC_SEED:
|
||||
args[1] = cic_seed;
|
||||
break;
|
||||
case CONFIG_QUERY_TV_TYPE:
|
||||
args[1] = tv_type;
|
||||
break;
|
||||
case CONFIG_QUERY_SAVE_OFFSET:
|
||||
args[1] = cfg_get_save_offset();
|
||||
break;
|
||||
case CONFIG_QUERY_DD_OFFSET:
|
||||
args[1] = cfg_get_dd_offset();
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
#ifndef CONTROLLER_H__
|
||||
#define CONTROLLER_H__
|
||||
|
||||
|
||||
#define USB_CMD_TOKEN (0x434D4400)
|
||||
#define USB_CMP_TOKEN (0x434D5000)
|
||||
#define USB_ERR_TOKEN (0x45525200)
|
||||
|
||||
|
||||
typedef enum {
|
||||
USB_STATE_IDLE,
|
||||
USB_STATE_ARGS,
|
||||
USB_STATE_DATA,
|
||||
USB_STATE_RESPONSE,
|
||||
USB_STATE_N64_TO_PC,
|
||||
USB_STATE_PC_TO_N64,
|
||||
} e_usb_state_t;
|
||||
|
||||
typedef enum {
|
||||
RTC_STATE_READ,
|
||||
RTC_STATE_WRITE,
|
||||
} e_rtc_state_t;
|
||||
|
||||
typedef enum {
|
||||
DEBUG_WRITE_ADDRESS,
|
||||
DEBUG_WRITE_LENGTH_START,
|
||||
DEBUG_WRITE_STATUS,
|
||||
DEBUG_READ_ARG,
|
||||
DEBUG_READ_LENGTH,
|
||||
DEBUG_READ_ADDRESS_START,
|
||||
} e_debug_t;
|
||||
|
||||
typedef enum {
|
||||
CONFIG_UPDATE_SDRAM_SWITCH,
|
||||
CONFIG_UPDATE_SDRAM_WRITABLE,
|
||||
CONFIG_UPDATE_DD_ENABLE,
|
||||
CONFIG_UPDATE_SAVE_TYPE,
|
||||
CONFIG_UPDATE_CIC_SEED,
|
||||
CONFIG_UPDATE_TV_TYPE
|
||||
} e_config_update_t;
|
||||
|
||||
typedef enum {
|
||||
CONFIG_QUERY_STATUS,
|
||||
CONFIG_QUERY_SAVE_TYPE,
|
||||
CONFIG_QUERY_CIC_SEED,
|
||||
CONFIG_QUERY_TV_TYPE,
|
||||
CONFIG_QUERY_SAVE_OFFSET,
|
||||
CONFIG_QUERY_DD_OFFSET,
|
||||
} e_config_query_t;
|
||||
|
||||
|
||||
#endif
|
26
sw/riscv/src/dma.c
Normal file
26
sw/riscv/src/dma.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include "dma.h"
|
||||
|
||||
|
||||
bool dma_busy (void) {
|
||||
return DMA->SCR & DMA_SCR_BUSY;
|
||||
}
|
||||
|
||||
void dma_start (uint32_t memory_address, size_t length, enum dma_id id, enum dma_dir dir) {
|
||||
DMA->MADDR = memory_address;
|
||||
DMA->ID_LEN = ((id & 0x03) << 30) | (length & 0x3FFFFFFF);
|
||||
DMA->SCR = ((dir == DMA_DIR_TO_SDRAM) ? DMA_SCR_DIR : 0) | DMA_SCR_START;
|
||||
}
|
||||
|
||||
void dma_stop (void) {
|
||||
DMA->SCR = DMA_SCR_STOP;
|
||||
}
|
||||
|
||||
|
||||
void dma_init (void) {
|
||||
dma_stop();
|
||||
}
|
||||
|
||||
|
||||
void process_dma (void) {
|
||||
|
||||
}
|
26
sw/riscv/src/dma.h
Normal file
26
sw/riscv/src/dma.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef DMA_H__
|
||||
#define DMA_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
enum dma_dir {
|
||||
DMA_DIR_TO_SDRAM,
|
||||
DMA_DIR_FROM_SDRAM,
|
||||
};
|
||||
|
||||
enum dma_id {
|
||||
DMA_ID_USB = 0,
|
||||
DMA_ID_SD = 1,
|
||||
};
|
||||
|
||||
|
||||
bool dma_busy (void);
|
||||
void dma_start (uint32_t memory_address, size_t length, enum dma_id id, enum dma_dir dir);
|
||||
void dma_stop (void);
|
||||
void dma_init (void);
|
||||
void process_dma (void);
|
||||
|
||||
|
||||
#endif
|
@ -1,402 +0,0 @@
|
||||
#include "driver.h"
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
// DMA
|
||||
|
||||
bool dma_start (uint32_t address, uint32_t length, e_dma_id_t id, e_dma_dir_t dir) {
|
||||
if (DMA->SCR & DMA_SCR_BUSY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DMA->MADDR = address;
|
||||
DMA->ID_LEN = ((id & 0x03) << 30) | (length & 0x3FFFFFFF);
|
||||
DMA->SCR = ((dir == DMA_DIR_TO_SDRAM) ? DMA_SCR_DIR : 0) | DMA_SCR_START;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dma_abort (void) {
|
||||
DMA->SCR = DMA_SCR_STOP;
|
||||
}
|
||||
|
||||
bool dma_busy (void) {
|
||||
return DMA->SCR & DMA_SCR_BUSY;
|
||||
}
|
||||
|
||||
|
||||
// FLASHRAM
|
||||
|
||||
e_flashram_op_t flashram_get_pending_operation (void) {
|
||||
uint32_t scr = FLASHRAM->SCR;
|
||||
|
||||
if (!(scr & FLASHRAM_OPERATION_PENDING)) {
|
||||
return FLASHRAM_OP_NONE;
|
||||
}
|
||||
|
||||
if (scr & FLASHRAM_WRITE_OR_ERASE) {
|
||||
if (scr & FLASHRAM_SECTOR_OR_ALL) {
|
||||
return FLASHRAM_OP_ERASE_ALL;
|
||||
} else {
|
||||
return FLASHRAM_OP_ERASE_SECTOR;
|
||||
}
|
||||
} else {
|
||||
return FLASHRAM_OP_WRITE_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t flashram_get_operation_length (e_flashram_op_t op) {
|
||||
switch (op) {
|
||||
case FLASHRAM_OP_ERASE_ALL: return FLASHRAM_SIZE;
|
||||
case FLASHRAM_OP_ERASE_SECTOR: return FLASHRAM_SECTOR_SIZE;
|
||||
case FLASHRAM_OP_WRITE_PAGE: return FLASHRAM_PAGE_SIZE;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void flashram_set_operation_done (void) {
|
||||
FLASHRAM->SCR = FLASHRAM_OPERATION_DONE;
|
||||
}
|
||||
|
||||
uint32_t flashram_get_page (void) {
|
||||
return (FLASHRAM->SCR >> FLASHRAM_PAGE_BIT);
|
||||
}
|
||||
|
||||
volatile uint32_t * flashram_get_page_buffer (void) {
|
||||
return FLASHRAM->BUFFER;
|
||||
}
|
||||
|
||||
|
||||
// USB
|
||||
|
||||
bool usb_rx_byte (uint8_t *data) {
|
||||
if (!(USB->SCR & USB_SCR_RXNE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = USB->DR;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool usb_rx_word (uint32_t *data) {
|
||||
static uint8_t current_byte = 0;
|
||||
static uint32_t buffer = 0;
|
||||
uint8_t tmp;
|
||||
|
||||
while (usb_rx_byte(&tmp)) {
|
||||
buffer = (buffer << 8) | tmp;
|
||||
current_byte += 1;
|
||||
if (current_byte == 4) {
|
||||
current_byte = 0;
|
||||
*data = buffer;
|
||||
buffer = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool usb_tx_byte (uint8_t data) {
|
||||
if (!(USB->SCR & USB_SCR_TXE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
USB->DR = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool usb_tx_word (uint32_t data) {
|
||||
static uint8_t current_byte = 0;
|
||||
while (usb_tx_byte(data >> ((3 - current_byte) * 8))) {
|
||||
current_byte += 1;
|
||||
if (current_byte == 4) {
|
||||
current_byte = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void usb_flush_rx (void) {
|
||||
USB->SCR = USB_SCR_FLUSH_RX;
|
||||
}
|
||||
|
||||
void usb_flush_tx (void) {
|
||||
USB->SCR = USB_SCR_FLUSH_TX;
|
||||
}
|
||||
|
||||
|
||||
// CFG
|
||||
|
||||
uint32_t cfg_get_status (void) {
|
||||
return CFG->SCR;
|
||||
}
|
||||
|
||||
void cfg_set_cpu_ready (bool enabled) {
|
||||
if (enabled) {
|
||||
CFG->SCR |= CFG_SCR_CPU_READY;
|
||||
} else {
|
||||
CFG->SCR &= ~CFG_SCR_CPU_READY;
|
||||
}
|
||||
}
|
||||
|
||||
void cfg_set_sdram_switch (bool enabled) {
|
||||
if (enabled) {
|
||||
CFG->SCR |= CFG_SCR_SDRAM_SWITCH;
|
||||
} else {
|
||||
CFG->SCR &= ~CFG_SCR_SDRAM_SWITCH;
|
||||
}
|
||||
}
|
||||
|
||||
void cfg_set_sdram_writable (bool enabled) {
|
||||
if (enabled) {
|
||||
CFG->SCR |= CFG_SCR_SDRAM_WRITABLE;
|
||||
} else {
|
||||
CFG->SCR &= ~CFG_SCR_SDRAM_WRITABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void cfg_set_dd_enable (bool enabled) {
|
||||
if (enabled) {
|
||||
CFG->SCR |= CFG_SCR_DD_EN;
|
||||
} else {
|
||||
CFG->SCR &= ~CFG_SCR_DD_EN;
|
||||
}
|
||||
}
|
||||
|
||||
void cfg_set_usb_waiting (bool enabled) {
|
||||
if (enabled) {
|
||||
CFG->SCR |= CFG_SCR_USB_WAITING;
|
||||
} else {
|
||||
CFG->SCR &= ~CFG_SCR_USB_WAITING;
|
||||
}
|
||||
}
|
||||
|
||||
void cfg_set_save_type (e_cfg_save_type_t save_type) {
|
||||
uint32_t save_offset = 0;
|
||||
|
||||
CFG->SCR &= ~(CFG_SCR_FLASHRAM_EN | CFG_SCR_SRAM_BANKED | CFG_SCR_SRAM_EN);
|
||||
|
||||
switch (save_type) {
|
||||
case CFG_SAVE_TYPE_NONE:
|
||||
break;
|
||||
case CFG_SAVE_TYPE_EEPROM_4K:
|
||||
save_offset = SDRAM_SIZE - CFG_SAVE_SIZE_EEPROM_4K;
|
||||
break;
|
||||
case CFG_SAVE_TYPE_EEPROM_16K:
|
||||
save_offset = SDRAM_SIZE - CFG_SAVE_SIZE_EEPROM_16K;
|
||||
break;
|
||||
case CFG_SAVE_TYPE_SRAM:
|
||||
save_offset = SDRAM_SIZE - CFG_SAVE_SIZE_SRAM;
|
||||
CFG->SCR |= CFG_SCR_SRAM_EN;
|
||||
break;
|
||||
case CFG_SAVE_TYPE_FLASHRAM:
|
||||
save_offset = SDRAM_SIZE - CFG_SAVE_SIZE_FLASHRAM;
|
||||
CFG->SCR |= CFG_SCR_FLASHRAM_EN;
|
||||
break;
|
||||
case CFG_SAVE_TYPE_SRAM_BANKED:
|
||||
save_offset = SDRAM_SIZE - CFG_SAVE_SIZE_SRAM_BANKED;
|
||||
CFG->SCR |= CFG_SCR_SRAM_BANKED | CFG_SCR_SRAM_EN;
|
||||
break;
|
||||
case CFG_SAVE_TYPE_FLASHRAM_PKST2:
|
||||
save_offset = CFG_SAVE_OFFSET_PKST2;
|
||||
CFG->SCR |= CFG_SCR_FLASHRAM_EN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CFG->SAVE_OFFSET = save_offset;
|
||||
}
|
||||
|
||||
void cfg_set_save_offset (uint32_t offset) {
|
||||
CFG->SAVE_OFFSET = offset;
|
||||
}
|
||||
|
||||
uint32_t cfg_get_save_offset (void) {
|
||||
return CFG->SAVE_OFFSET;
|
||||
}
|
||||
|
||||
void cfg_set_dd_offset (uint32_t offset) {
|
||||
CFG->DD_OFFSET = offset;
|
||||
}
|
||||
|
||||
uint32_t cfg_get_dd_offset (void) {
|
||||
return CFG->DD_OFFSET;
|
||||
}
|
||||
|
||||
bool cfg_get_command (uint8_t *cmd, uint32_t *args) {
|
||||
if (!(CFG->SCR & CFG_SCR_CPU_BUSY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*cmd = CFG->CMD;
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
args[i] = CFG->DATA[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cfg_set_response (uint32_t *args, bool error) {
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
CFG->DATA[i] = args[i];
|
||||
}
|
||||
if (error) {
|
||||
CFG->SCR |= CFG_SCR_CMD_ERROR;
|
||||
} else {
|
||||
CFG->SCR &= ~CFG_SCR_CMD_ERROR;
|
||||
}
|
||||
CFG->SCR &= ~(CFG_SCR_CPU_BUSY);
|
||||
}
|
||||
|
||||
|
||||
// SI
|
||||
|
||||
bool si_rx_ready (void) {
|
||||
return SI->SCR & SI_SCR_RX_READY;
|
||||
}
|
||||
|
||||
bool si_rx_stop_bit (void) {
|
||||
return SI->SCR & SI_SCR_RX_STOP_BIT;
|
||||
}
|
||||
|
||||
bool si_tx_busy (void) {
|
||||
return SI->SCR & SI_SCR_TX_BUSY;
|
||||
}
|
||||
|
||||
void si_rx_reset (void) {
|
||||
SI->SCR = SI_SCR_RX_RESET;
|
||||
}
|
||||
|
||||
void si_reset (void) {
|
||||
SI->SCR = SI_SCR_TX_RESET | SI_SCR_RX_RESET;
|
||||
}
|
||||
|
||||
void si_rx (uint8_t *data) {
|
||||
uint32_t rx_length = (SI->SCR & SI_SCR_RX_LENGTH_MASK) >> SI_SCR_RX_LENGTH_BIT;
|
||||
for (size_t i = 0; i < rx_length; i++) {
|
||||
data[i] = ((uint8_t *) SI->DATA)[(10 - rx_length) + i];
|
||||
}
|
||||
}
|
||||
|
||||
void si_tx (uint8_t *data, size_t length) {
|
||||
for (size_t i = 0; i < ((length + 3) / 4); i++) {
|
||||
SI->DATA[i] = ((uint32_t *) data)[i];
|
||||
}
|
||||
SI->DATA[length / 4] |= (0x80 << ((length % 4) * 8));
|
||||
SI->SCR = (((length * 8) + 1) << SI_SCR_TX_LENGTH_BIT) | SI_SCR_TX_START;
|
||||
}
|
||||
|
||||
|
||||
// I2C
|
||||
|
||||
bool i2c_busy (void) {
|
||||
return I2C->SCR & I2C_SCR_BUSY;
|
||||
}
|
||||
|
||||
bool i2c_ack (void) {
|
||||
return I2C->SCR & I2C_SCR_ACK;
|
||||
}
|
||||
|
||||
void i2c_start (void) {
|
||||
I2C->SCR = I2C_SCR_START;
|
||||
}
|
||||
|
||||
void i2c_stop (void) {
|
||||
I2C->SCR = I2C_SCR_STOP;
|
||||
}
|
||||
|
||||
void i2c_begin_trx (uint8_t data, bool mack) {
|
||||
I2C->SCR = mack ? I2C_SCR_MACK : 0;
|
||||
I2C->DR = data;
|
||||
}
|
||||
|
||||
uint8_t i2c_get_data (void) {
|
||||
return I2C->DR;
|
||||
}
|
||||
|
||||
|
||||
// RTC
|
||||
|
||||
static const uint8_t rtc_bit_mask[7] = {
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b00111111,
|
||||
0b00000111,
|
||||
0b00111111,
|
||||
0b00011111,
|
||||
0b11111111
|
||||
};
|
||||
|
||||
void rtc_sanitize_time_data (uint8_t *time_data) {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
time_data[i] &= rtc_bit_mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_convert_to_n64 (uint8_t *rtc_data, uint8_t *n64_data) {
|
||||
rtc_sanitize_time_data(rtc_data);
|
||||
n64_data[0] = rtc_data[RTC_RTCSEC];
|
||||
n64_data[1] = rtc_data[RTC_RTCMIN];
|
||||
n64_data[2] = rtc_data[RTC_RTCHOUR] | 0x80;
|
||||
n64_data[4] = rtc_data[RTC_RTCWKDAY] - 1;
|
||||
n64_data[3] = rtc_data[RTC_RTCDATE];
|
||||
n64_data[5] = rtc_data[RTC_RTCMTH];
|
||||
n64_data[6] = rtc_data[RTC_RTCYEAR];
|
||||
}
|
||||
|
||||
void rtc_convert_from_n64 (uint8_t *n64_data, uint8_t *rtc_data) {
|
||||
rtc_data[RTC_RTCSEC] = n64_data[0];
|
||||
rtc_data[RTC_RTCMIN] = n64_data[1];
|
||||
rtc_data[RTC_RTCHOUR] = n64_data[2];
|
||||
rtc_data[RTC_RTCWKDAY] = n64_data[4] + 1;
|
||||
rtc_data[RTC_RTCDATE] = n64_data[3];
|
||||
rtc_data[RTC_RTCMTH] = n64_data[5];
|
||||
rtc_data[RTC_RTCYEAR] = n64_data[6];
|
||||
rtc_sanitize_time_data(rtc_data);
|
||||
}
|
||||
|
||||
|
||||
// Misc
|
||||
|
||||
static const char hex_char_map[16] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
void print (const char *text) {
|
||||
while (*text != '\0') {
|
||||
while (!(UART->SCR & UART_SCR_TXE));
|
||||
UART->DR = *text++;
|
||||
}
|
||||
}
|
||||
|
||||
void print_02hex (uint8_t number) {
|
||||
char buffer[3];
|
||||
buffer[0] = hex_char_map[(number >> 4) & 0x0F];
|
||||
buffer[1] = hex_char_map[number & 0x0F];
|
||||
buffer[2] = '\0';
|
||||
print(buffer);
|
||||
}
|
||||
|
||||
void print_08hex (uint32_t number) {
|
||||
print_02hex((number >> 24) & 0xFF);
|
||||
print_02hex((number >> 16) & 0xFF);
|
||||
print_02hex((number >> 8) & 0xFF);
|
||||
print_02hex((number >> 0) & 0xFF);
|
||||
}
|
||||
|
||||
uint32_t swapb (uint32_t data) {
|
||||
return (
|
||||
(data << 24) |
|
||||
((data << 8) & 0x00FF0000) |
|
||||
((data >> 8) & 0x0000FF00) |
|
||||
(data >> 24)
|
||||
);
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
#ifndef DRIVER_H__
|
||||
#define DRIVER_H__
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
// DMA
|
||||
|
||||
typedef enum {
|
||||
DMA_DIR_TO_SDRAM,
|
||||
DMA_DIR_FROM_SDRAM,
|
||||
} e_dma_dir_t;
|
||||
|
||||
typedef enum {
|
||||
DMA_ID_USB = 0,
|
||||
DMA_ID_SD = 1,
|
||||
} e_dma_id_t;
|
||||
|
||||
bool dma_start (uint32_t address, uint32_t length, e_dma_id_t id, e_dma_dir_t dir);
|
||||
void dma_abort (void);
|
||||
bool dma_busy (void);
|
||||
|
||||
|
||||
// USB
|
||||
|
||||
bool usb_rx_byte (uint8_t *data);
|
||||
bool usb_rx_word (uint32_t *data);
|
||||
bool usb_tx_byte (uint8_t data);
|
||||
bool usb_tx_word (uint32_t data);
|
||||
void usb_flush_rx (void);
|
||||
void usb_flush_tx (void);
|
||||
|
||||
|
||||
// FLASHRAM
|
||||
|
||||
#define FLASHRAM_SIZE (128 * 1024)
|
||||
#define FLASHRAM_SECTOR_SIZE (16 * 1024)
|
||||
#define FLASHRAM_PAGE_SIZE (128)
|
||||
#define FLASHRAM_ERASE_VALUE (0xFFFFFFFF)
|
||||
|
||||
typedef enum {
|
||||
FLASHRAM_OP_NONE,
|
||||
FLASHRAM_OP_ERASE_ALL,
|
||||
FLASHRAM_OP_ERASE_SECTOR,
|
||||
FLASHRAM_OP_WRITE_PAGE
|
||||
} e_flashram_op_t;
|
||||
|
||||
e_flashram_op_t flashram_get_pending_operation (void);
|
||||
uint32_t flashram_get_operation_length (e_flashram_op_t op);
|
||||
void flashram_set_operation_done (void);
|
||||
uint32_t flashram_get_page (void);
|
||||
volatile uint32_t * flashram_get_page_buffer (void);
|
||||
|
||||
|
||||
// CFG
|
||||
|
||||
#define CFG_SAVE_SIZE_EEPROM_4K (512)
|
||||
#define CFG_SAVE_SIZE_EEPROM_16K (2048)
|
||||
#define CFG_SAVE_SIZE_SRAM (32 * 1024)
|
||||
#define CFG_SAVE_SIZE_FLASHRAM (128 * 1024)
|
||||
#define CFG_SAVE_SIZE_SRAM_BANKED (3 * 32 * 1024)
|
||||
|
||||
#define CFG_SAVE_OFFSET_PKST2 (0x01608000UL)
|
||||
|
||||
#define CFG_DEFAULT_DD_OFFSET (0x03BE0000UL)
|
||||
|
||||
typedef enum {
|
||||
CFG_SAVE_TYPE_NONE = 0,
|
||||
CFG_SAVE_TYPE_EEPROM_4K = 1,
|
||||
CFG_SAVE_TYPE_EEPROM_16K = 2,
|
||||
CFG_SAVE_TYPE_SRAM = 3,
|
||||
CFG_SAVE_TYPE_FLASHRAM = 4,
|
||||
CFG_SAVE_TYPE_SRAM_BANKED = 5,
|
||||
CFG_SAVE_TYPE_FLASHRAM_PKST2 = 6,
|
||||
} e_cfg_save_type_t;
|
||||
|
||||
uint32_t cfg_get_status (void);
|
||||
void cfg_set_cpu_ready (bool enabled);
|
||||
void cfg_set_sdram_switch (bool enabled);
|
||||
void cfg_set_sdram_writable (bool enabled);
|
||||
void cfg_set_usb_waiting (bool value);
|
||||
void cfg_set_dd_enable (bool enabled);
|
||||
void cfg_set_save_type (e_cfg_save_type_t save_type);
|
||||
void cfg_set_save_offset (uint32_t offset);
|
||||
uint32_t cfg_get_save_offset (void);
|
||||
void cfg_set_dd_offset (uint32_t offset);
|
||||
uint32_t cfg_get_dd_offset (void);
|
||||
bool cfg_get_command (uint8_t *cmd, uint32_t *args);
|
||||
void cfg_set_response (uint32_t *args, bool error);
|
||||
|
||||
|
||||
// SI
|
||||
|
||||
#define SI_CMD_EEPROM_STATUS (0x00)
|
||||
#define SI_CMD_EEPROM_READ (0x04)
|
||||
#define SI_CMD_EEPROM_WRITE (0x05)
|
||||
#define SI_CMD_RTC_STATUS (0x06)
|
||||
#define SI_CMD_RTC_READ (0x07)
|
||||
#define SI_CMD_RTC_WRITE (0x08)
|
||||
|
||||
#define SI_EEPROM_ID_4K (0x80)
|
||||
#define SI_EEPROM_ID_16K (0xC0)
|
||||
|
||||
#define SI_RTC_ID (0x10)
|
||||
|
||||
#define SI_RTC_STATUS_STOPPED (0x80)
|
||||
#define SI_RTC_STATUS_RUNNING (0x00)
|
||||
#define SI_RTC_STATUS(running) (running ? SI_RTC_STATUS_RUNNING : SI_RTC_STATUS_STOPPED)
|
||||
|
||||
#define SI_RTC_WP_MASK (0x03)
|
||||
#define SI_RTC_ST_MASK (0x04)
|
||||
#define SI_RTC_CENTURY_20XX (0x01)
|
||||
|
||||
bool si_rx_ready (void);
|
||||
bool si_rx_stop_bit (void);
|
||||
bool si_tx_busy (void);
|
||||
void si_rx_reset (void);
|
||||
void si_reset (void);
|
||||
void si_rx (uint8_t *data);
|
||||
void si_tx (uint8_t *data, size_t length);
|
||||
|
||||
|
||||
// I2C
|
||||
|
||||
bool i2c_busy (void);
|
||||
bool i2c_ack (void);
|
||||
void i2c_start (void);
|
||||
void i2c_stop (void);
|
||||
void i2c_begin_trx (uint8_t data, bool mack);
|
||||
uint8_t i2c_get_data (void);
|
||||
|
||||
|
||||
// RTC
|
||||
|
||||
#define RTC_ADDR (0xDE)
|
||||
|
||||
#define RTC_RTCSEC (0x00)
|
||||
#define RTC_RTCMIN (0x01)
|
||||
#define RTC_RTCHOUR (0x02)
|
||||
#define RTC_RTCWKDAY (0x03)
|
||||
#define RTC_RTCDATE (0x04)
|
||||
#define RTC_RTCMTH (0x05)
|
||||
#define RTC_RTCYEAR (0x06)
|
||||
|
||||
#define RTC_RTCSEC_ST (1 << 7)
|
||||
#define RTC_RTCWKDAY_OSCRUN (1 << 5)
|
||||
#define RTC_RTCWKDAY_VBAT (1 << 3)
|
||||
|
||||
void rtc_sanitize_time_data(uint8_t *time_data);
|
||||
void rtc_convert_to_n64 (uint8_t *rtc_data, uint8_t *n64_data);
|
||||
void rtc_convert_from_n64 (uint8_t *n64_data, uint8_t *rtc_data);
|
||||
|
||||
|
||||
// Misc
|
||||
|
||||
void print (const char *text);
|
||||
void print_02hex (uint8_t number);
|
||||
void print_08hex (uint32_t number);
|
||||
uint32_t swapb (uint32_t data);
|
||||
|
||||
|
||||
#endif
|
69
sw/riscv/src/flashram.c
Normal file
69
sw/riscv/src/flashram.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include "flashram.h"
|
||||
|
||||
|
||||
#define FLASHRAM_SIZE (128 * 1024)
|
||||
#define FLASHRAM_SECTOR_SIZE (16 * 1024)
|
||||
#define FLASHRAM_PAGE_SIZE (128)
|
||||
#define FLASHRAM_ERASE_VALUE (0xFFFFFFFF)
|
||||
|
||||
enum operation {
|
||||
OP_NONE,
|
||||
OP_ERASE_ALL,
|
||||
OP_ERASE_SECTOR,
|
||||
OP_WRITE_PAGE
|
||||
};
|
||||
|
||||
|
||||
static enum operation get_operation_type (void) {
|
||||
uint32_t scr = FLASHRAM->SCR;
|
||||
|
||||
if (!(scr & FLASHRAM_OPERATION_PENDING)) {
|
||||
return OP_NONE;
|
||||
}
|
||||
|
||||
if (scr & FLASHRAM_WRITE_OR_ERASE) {
|
||||
if (scr & FLASHRAM_SECTOR_OR_ALL) {
|
||||
return OP_ERASE_ALL;
|
||||
} else {
|
||||
return OP_ERASE_SECTOR;
|
||||
}
|
||||
} else {
|
||||
return OP_WRITE_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t get_operation_length (enum operation op) {
|
||||
switch (op) {
|
||||
case OP_ERASE_ALL: return FLASHRAM_SIZE;
|
||||
case OP_ERASE_SECTOR: return FLASHRAM_SECTOR_SIZE;
|
||||
case OP_WRITE_PAGE: return FLASHRAM_PAGE_SIZE;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void flashram_init (void) {
|
||||
FLASHRAM->SCR = FLASHRAM_OPERATION_DONE;
|
||||
}
|
||||
|
||||
|
||||
void process_flashram (void) {
|
||||
enum operation op = get_operation_type();
|
||||
size_t length;
|
||||
io32_t *save_data;
|
||||
|
||||
if (op != OP_NONE) {
|
||||
length = get_operation_length(op);
|
||||
save_data = (io32_t *)(SDRAM_BASE + CFG->SAVE_OFFSET + ((FLASHRAM->SCR >> FLASHRAM_PAGE_BIT) * FLASHRAM_PAGE_SIZE));
|
||||
|
||||
for (uint32_t i = 0; i < (length / 4); i++) {
|
||||
if (op == OP_WRITE_PAGE) {
|
||||
*save_data++ &= FLASHRAM->BUFFER[i];
|
||||
} else {
|
||||
*save_data++ = FLASHRAM_ERASE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
FLASHRAM->SCR = FLASHRAM_OPERATION_DONE;
|
||||
}
|
||||
}
|
12
sw/riscv/src/flashram.h
Normal file
12
sw/riscv/src/flashram.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef FLASHRAM_H__
|
||||
#define FLASHRAM_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
void flashram_init (void);
|
||||
void process_flashram (void);
|
||||
|
||||
|
||||
#endif
|
113
sw/riscv/src/i2c.c
Normal file
113
sw/riscv/src/i2c.c
Normal file
@ -0,0 +1,113 @@
|
||||
#include "i2c.h"
|
||||
|
||||
|
||||
enum phase {
|
||||
PHASE_START,
|
||||
PHASE_ADDRESS,
|
||||
PHASE_DATA,
|
||||
PHASE_STOP,
|
||||
};
|
||||
|
||||
struct process {
|
||||
enum phase phase;
|
||||
uint8_t address;
|
||||
uint8_t *data;
|
||||
uint8_t length;
|
||||
bool write;
|
||||
bool generate_stop;
|
||||
bool first_byte_transferred;
|
||||
bool busy;
|
||||
bool done;
|
||||
bool failed;
|
||||
};
|
||||
|
||||
static struct process p;
|
||||
|
||||
|
||||
bool i2c_busy (void) {
|
||||
return p.busy;
|
||||
}
|
||||
|
||||
bool i2c_done (void) {
|
||||
return p.done;
|
||||
}
|
||||
|
||||
bool i2c_failed (void) {
|
||||
return p.failed;
|
||||
}
|
||||
|
||||
void i2c_trx (uint8_t address, uint8_t *data, uint8_t length, bool write, bool generate_stop) {
|
||||
p.phase = PHASE_START;
|
||||
p.address = address;
|
||||
p.data = data;
|
||||
p.length = length;
|
||||
p.write = write;
|
||||
p.generate_stop = generate_stop;
|
||||
p.first_byte_transferred = false;
|
||||
p.busy = true;
|
||||
p.done = false;
|
||||
p.failed = false;
|
||||
}
|
||||
|
||||
|
||||
void i2c_init (void) {
|
||||
I2C->SCR = I2C_SCR_STOP;
|
||||
p.busy = false;
|
||||
p.done = false;
|
||||
p.failed = false;
|
||||
}
|
||||
|
||||
|
||||
void process_i2c (void) {
|
||||
if (p.busy && (!(I2C->SCR & I2C_SCR_BUSY))) {
|
||||
switch (p.phase) {
|
||||
case PHASE_START:
|
||||
I2C->SCR = I2C_SCR_START;
|
||||
p.phase = PHASE_ADDRESS;
|
||||
break;
|
||||
|
||||
case PHASE_ADDRESS:
|
||||
I2C->SCR = 0;
|
||||
I2C->DR = p.address | (p.write ? 0 : (1 << 0));
|
||||
p.phase = PHASE_DATA;
|
||||
break;
|
||||
|
||||
case PHASE_DATA:
|
||||
if (p.write) {
|
||||
p.failed |= (!(I2C->SCR & I2C_SCR_ACK));
|
||||
I2C->DR = *p.data++;
|
||||
if (p.length == 1) {
|
||||
if (p.generate_stop) {
|
||||
p.phase = PHASE_STOP;
|
||||
} else {
|
||||
p.busy = false;
|
||||
p.done = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (p.first_byte_transferred) {
|
||||
*(p.data++) = I2C->DR;
|
||||
}
|
||||
if (p.length >= 1) {
|
||||
I2C->SCR = (p.length > 1) ? I2C_SCR_MACK : 0;
|
||||
I2C->DR = 0xFF;
|
||||
p.first_byte_transferred = true;
|
||||
}
|
||||
if (p.length == 0) {
|
||||
p.phase = PHASE_STOP;
|
||||
}
|
||||
}
|
||||
p.length -= 1;
|
||||
break;
|
||||
|
||||
case PHASE_STOP:
|
||||
if (p.write) {
|
||||
p.failed |= (!(I2C->SCR & I2C_SCR_ACK));
|
||||
}
|
||||
I2C->SCR = I2C_SCR_STOP;
|
||||
p.busy = false;
|
||||
p.done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
16
sw/riscv/src/i2c.h
Normal file
16
sw/riscv/src/i2c.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef I2C_H__
|
||||
#define I2C_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
bool i2c_busy (void);
|
||||
bool i2c_done (void);
|
||||
bool i2c_failed (void);
|
||||
void i2c_trx (uint8_t address, uint8_t *data, uint8_t length, bool write, bool generate_stop);
|
||||
void i2c_init (void);
|
||||
void process_i2c (void);
|
||||
|
||||
|
||||
#endif
|
163
sw/riscv/src/joybus.c
Normal file
163
sw/riscv/src/joybus.c
Normal file
@ -0,0 +1,163 @@
|
||||
#include "joybus.h"
|
||||
#include "rtc.h"
|
||||
|
||||
|
||||
#define CMD_EEPROM_STATUS (0x00)
|
||||
#define CMD_EEPROM_READ (0x04)
|
||||
#define CMD_EEPROM_WRITE (0x05)
|
||||
#define CMD_RTC_STATUS (0x06)
|
||||
#define CMD_RTC_READ (0x07)
|
||||
#define CMD_RTC_WRITE (0x08)
|
||||
|
||||
#define EEPROM_ID_4K (0x80)
|
||||
#define EEPROM_ID_16K (0xC0)
|
||||
#define RTC_ID (0x10)
|
||||
|
||||
#define EEPROM_PAGE_SIZE (8)
|
||||
|
||||
#define RTC_STATUS_STOPPED (0x80)
|
||||
#define RTC_STATUS_RUNNING (0x00)
|
||||
#define RTC_STATUS(running) (running ? RTC_STATUS_RUNNING : RTC_STATUS_STOPPED)
|
||||
|
||||
#define RTC_WP_MASK (0x03)
|
||||
#define RTC_ST_MASK (0x04)
|
||||
#define RTC_CENTURY_20XX (0x01)
|
||||
|
||||
|
||||
static void rx (uint8_t *data) {
|
||||
uint32_t rx_length = (JOYBUS->SCR & JOYBUS_SCR_RX_LENGTH_MASK) >> JOYBUS_SCR_RX_LENGTH_BIT;
|
||||
for (size_t i = 0; i < rx_length; i++) {
|
||||
data[i] = ((uint8_t *) JOYBUS->DATA)[(10 - rx_length) + i];
|
||||
}
|
||||
}
|
||||
|
||||
static void tx (uint8_t *data, size_t length) {
|
||||
for (size_t i = 0; i < ((length + 3) / 4); i++) {
|
||||
JOYBUS->DATA[i] = ((uint32_t *) data)[i];
|
||||
}
|
||||
JOYBUS->DATA[length / 4] |= (0x80 << ((length % 4) * 8));
|
||||
JOYBUS->SCR = (((length * 8) + 1) << JOYBUS_SCR_TX_LENGTH_BIT) | JOYBUS_SCR_TX_START;
|
||||
}
|
||||
|
||||
static uint32_t swapb (uint32_t data) {
|
||||
return (
|
||||
(data << 24) |
|
||||
((data << 8) & 0x00FF0000) |
|
||||
((data >> 8) & 0x0000FF00) |
|
||||
(data >> 24)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
struct process {
|
||||
enum eeprom_type eeprom_type;
|
||||
bool rtc_running;
|
||||
uint8_t rtc_write_protect;
|
||||
};
|
||||
|
||||
static struct process p;
|
||||
|
||||
|
||||
void joybus_set_eeprom (enum eeprom_type eeprom_type) {
|
||||
p.eeprom_type = eeprom_type;
|
||||
}
|
||||
|
||||
|
||||
void joybus_init (void) {
|
||||
JOYBUS->SCR = JOYBUS_SCR_TX_RESET | JOYBUS_SCR_RX_RESET;
|
||||
p.eeprom_type = EEPROM_NONE;
|
||||
p.rtc_running = true;
|
||||
p.rtc_write_protect = RTC_WP_MASK;
|
||||
}
|
||||
|
||||
|
||||
void process_joybus (void) {
|
||||
uint8_t rx_data[10];
|
||||
uint8_t tx_data[12];
|
||||
io32_t *save_data;
|
||||
uint32_t *data_offset;
|
||||
|
||||
if (JOYBUS->SCR & JOYBUS_SCR_RX_READY) {
|
||||
if (JOYBUS->SCR & JOYBUS_SCR_RX_STOP_BIT) {
|
||||
rx(rx_data);
|
||||
|
||||
for (size_t i = 0; i < sizeof(tx_data); i++) {
|
||||
tx_data[i] = 0x00;
|
||||
}
|
||||
|
||||
if (p.eeprom_type != EEPROM_NONE) {
|
||||
save_data = (io32_t *) (SDRAM_BASE + CFG->SAVE_OFFSET + (rx_data[1] * EEPROM_PAGE_SIZE));
|
||||
switch (rx_data[0]) {
|
||||
case CMD_EEPROM_STATUS:
|
||||
tx_data[1] = p.eeprom_type == EEPROM_16K ? EEPROM_ID_16K : EEPROM_ID_4K;
|
||||
tx(tx_data, 3);
|
||||
break;
|
||||
|
||||
case CMD_EEPROM_READ:
|
||||
data_offset = (uint32_t *) (&tx_data[0]);
|
||||
data_offset[0] = swapb(save_data[0]);
|
||||
data_offset[1] = swapb(save_data[1]);
|
||||
tx(tx_data, 8);
|
||||
break;
|
||||
|
||||
case CMD_EEPROM_WRITE:
|
||||
data_offset = (uint32_t *) (&rx_data[2]);
|
||||
save_data[0] = swapb(data_offset[0]);
|
||||
save_data[1] = swapb(data_offset[1]);
|
||||
tx(tx_data, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (rx_data[0]) {
|
||||
case CMD_RTC_STATUS:
|
||||
tx_data[1] = RTC_ID;
|
||||
tx_data[2] = RTC_STATUS(p.rtc_running);
|
||||
tx(tx_data, 3);
|
||||
break;
|
||||
|
||||
case CMD_RTC_READ:
|
||||
if (rx_data[1] == 0) {
|
||||
tx_data[0] = p.rtc_write_protect;
|
||||
if (!p.rtc_running) {
|
||||
tx_data[1] = RTC_ST_MASK;
|
||||
}
|
||||
} else if (rx_data[1] == 2) {
|
||||
rtc_time_t *rtc_time = rtc_get_time();
|
||||
tx_data[0] = rtc_time->seconds;
|
||||
tx_data[1] = rtc_time->minutes;
|
||||
tx_data[2] = rtc_time->hours | 0x80;
|
||||
tx_data[4] = rtc_time->weekday - 1;
|
||||
tx_data[3] = rtc_time->day;
|
||||
tx_data[5] = rtc_time->month;
|
||||
tx_data[6] = rtc_time->year;
|
||||
tx_data[7] = RTC_CENTURY_20XX;
|
||||
}
|
||||
tx_data[8] = RTC_STATUS(p.rtc_running);
|
||||
tx(tx_data, 9);
|
||||
break;
|
||||
|
||||
case CMD_RTC_WRITE:
|
||||
if (rx_data[1] == 0) {
|
||||
p.rtc_write_protect = rx_data[2] & RTC_WP_MASK;
|
||||
p.rtc_running = (!(rx_data[3] & RTC_ST_MASK));
|
||||
} else if (rx_data[1] == 2) {
|
||||
rtc_time_t rtc_time;
|
||||
rtc_time.seconds = rx_data[2];
|
||||
rtc_time.minutes = rx_data[3];
|
||||
rtc_time.hours = rx_data[4] & 0x7F;
|
||||
rtc_time.weekday = rx_data[6] + 1;
|
||||
rtc_time.day = rx_data[5];
|
||||
rtc_time.month = rx_data[7];
|
||||
rtc_time.year = rx_data[8];
|
||||
rtc_set_time(&rtc_time);
|
||||
}
|
||||
tx_data[0] = RTC_STATUS(p.rtc_running);
|
||||
tx(tx_data, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JOYBUS->SCR = JOYBUS_SCR_RX_RESET;
|
||||
}
|
||||
}
|
20
sw/riscv/src/joybus.h
Normal file
20
sw/riscv/src/joybus.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef JOYBUS_H__
|
||||
#define JOYBUS_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
enum eeprom_type {
|
||||
EEPROM_NONE,
|
||||
EEPROM_4K,
|
||||
EEPROM_16K,
|
||||
};
|
||||
|
||||
|
||||
void joybus_init (void);
|
||||
void joybus_set_eeprom (enum eeprom_type eeprom_type);
|
||||
void process_joybus (void);
|
||||
|
||||
|
||||
#endif
|
7
sw/riscv/src/main.c
Normal file
7
sw/riscv/src/main.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include "process.h"
|
||||
|
||||
|
||||
void main (void) {
|
||||
process_init();
|
||||
process_loop();
|
||||
}
|
35
sw/riscv/src/process.c
Normal file
35
sw/riscv/src/process.c
Normal file
@ -0,0 +1,35 @@
|
||||
#include "process.h"
|
||||
#include "usb.h"
|
||||
#include "cfg.h"
|
||||
#include "dma.h"
|
||||
#include "joybus.h"
|
||||
#include "rtc.h"
|
||||
#include "i2c.h"
|
||||
#include "flashram.h"
|
||||
#include "uart.h"
|
||||
|
||||
|
||||
void process_init (void) {
|
||||
usb_init();
|
||||
cfg_init();
|
||||
dma_init();
|
||||
joybus_init();
|
||||
rtc_init();
|
||||
i2c_init();
|
||||
flashram_init();
|
||||
uart_init();
|
||||
}
|
||||
|
||||
|
||||
void process_loop (void) {
|
||||
while (1) {
|
||||
process_usb();
|
||||
process_cfg();
|
||||
process_dma();
|
||||
process_joybus();
|
||||
process_rtc();
|
||||
process_i2c();
|
||||
process_flashram();
|
||||
process_uart();
|
||||
}
|
||||
}
|
9
sw/riscv/src/process.h
Normal file
9
sw/riscv/src/process.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef PROCESS_H__
|
||||
#define PROCESS_H__
|
||||
|
||||
|
||||
void process_init (void);
|
||||
void process_loop (void);
|
||||
|
||||
|
||||
#endif
|
225
sw/riscv/src/rtc.c
Normal file
225
sw/riscv/src/rtc.c
Normal file
@ -0,0 +1,225 @@
|
||||
#include "rtc.h"
|
||||
#include "i2c.h"
|
||||
|
||||
|
||||
enum rtc_regs {
|
||||
RTCSEC,
|
||||
RTCMIN,
|
||||
RTCHOUR,
|
||||
RTCWKDAY,
|
||||
RTCDATE,
|
||||
RTCMTH,
|
||||
RTCYEAR,
|
||||
};
|
||||
|
||||
#define RTC_I2C_ADDR (0xDE)
|
||||
|
||||
#define RTCSEC_ST (1 << 7)
|
||||
#define RTCWKDAY_OSCRUN (1 << 5)
|
||||
#define RTCWKDAY_VBAT (1 << 3)
|
||||
|
||||
|
||||
enum rtc_phase {
|
||||
RTC_PHASE_READ_START,
|
||||
RTC_PHASE_READ_READY,
|
||||
RTC_PHASE_STOP,
|
||||
RTC_PHASE_WAIT_STOP,
|
||||
RTC_PHASE_UPDATE,
|
||||
RTC_PHASE_START,
|
||||
RTC_PHASE_WAIT_START,
|
||||
};
|
||||
|
||||
enum i2c_phase {
|
||||
I2C_PHASE_IDLE,
|
||||
I2C_PHASE_ADDR,
|
||||
I2C_PHASE_DATA,
|
||||
I2C_PHASE_READY,
|
||||
};
|
||||
|
||||
|
||||
struct process {
|
||||
enum rtc_phase rtc_phase;
|
||||
uint8_t data[7];
|
||||
bool running;
|
||||
rtc_time_t time;
|
||||
bool time_valid;
|
||||
bool new_time_valid;
|
||||
|
||||
enum i2c_phase i2c_phase;
|
||||
bool i2c_pending;
|
||||
bool i2c_write;
|
||||
uint8_t i2c_address;
|
||||
uint8_t i2c_length;
|
||||
bool i2c_first_read_done;
|
||||
};
|
||||
|
||||
static struct process p;
|
||||
|
||||
|
||||
static const uint8_t rtc_regs_bit_mask[7] = {
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b00111111,
|
||||
0b00000111,
|
||||
0b00111111,
|
||||
0b00011111,
|
||||
0b11111111
|
||||
};
|
||||
|
||||
static void sanitize_time (uint8_t *data) {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
data[i] &= rtc_regs_bit_mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rtc_time_t *rtc_get_time (void) {
|
||||
return &p.time;
|
||||
}
|
||||
|
||||
bool rtc_is_time_valid (void) {
|
||||
return p.time_valid;
|
||||
}
|
||||
|
||||
bool rtc_is_time_running (void) {
|
||||
return p.running;
|
||||
}
|
||||
|
||||
void rtc_set_time (rtc_time_t *time) {
|
||||
p.time = *time;
|
||||
p.new_time_valid = true;
|
||||
}
|
||||
|
||||
|
||||
void rtc_init (void) {
|
||||
p.rtc_phase = RTC_PHASE_READ_START;
|
||||
p.running = false;
|
||||
p.time_valid = false;
|
||||
p.new_time_valid = false;
|
||||
|
||||
p.i2c_phase = I2C_PHASE_IDLE;
|
||||
p.i2c_pending = false;
|
||||
}
|
||||
|
||||
|
||||
void process_rtc (void) {
|
||||
if (p.i2c_phase == I2C_PHASE_IDLE) {
|
||||
switch (p.rtc_phase) {
|
||||
case RTC_PHASE_READ_START:
|
||||
p.i2c_pending = true;
|
||||
p.i2c_write = false;
|
||||
p.i2c_address = RTCSEC;
|
||||
p.i2c_length = sizeof(p.data);
|
||||
p.rtc_phase = RTC_PHASE_READ_READY;
|
||||
break;
|
||||
|
||||
case RTC_PHASE_READ_READY:
|
||||
p.time_valid = (!i2c_failed());
|
||||
if (p.new_time_valid) {
|
||||
p.rtc_phase = RTC_PHASE_STOP;
|
||||
break;
|
||||
} else if (p.time_valid) {
|
||||
p.running = p.data[RTCSEC] & RTCSEC_ST;
|
||||
sanitize_time(p.data);
|
||||
p.time.seconds = p.data[RTCSEC];
|
||||
p.time.minutes = p.data[RTCMIN];
|
||||
p.time.hours = p.data[RTCHOUR];
|
||||
p.time.weekday = p.data[RTCWKDAY];
|
||||
p.time.day = p.data[RTCDATE];
|
||||
p.time.month = p.data[RTCMTH];
|
||||
p.time.year = p.data[RTCYEAR];
|
||||
}
|
||||
p.rtc_phase = RTC_PHASE_READ_START;
|
||||
break;
|
||||
|
||||
case RTC_PHASE_STOP:
|
||||
p.i2c_pending = true;
|
||||
p.i2c_write = true;
|
||||
p.i2c_length = 2;
|
||||
p.i2c_first_read_done = false;
|
||||
p.data[0] = RTCSEC;
|
||||
p.data[1] = 0x00;
|
||||
p.rtc_phase = RTC_PHASE_WAIT_STOP;
|
||||
break;
|
||||
|
||||
case RTC_PHASE_WAIT_STOP:
|
||||
if (p.i2c_first_read_done) {
|
||||
if (!(p.data[0] & RTCWKDAY_OSCRUN)) {
|
||||
p.rtc_phase = RTC_PHASE_UPDATE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.i2c_pending = true;
|
||||
p.i2c_write = false;
|
||||
p.i2c_address = RTCWKDAY;
|
||||
p.i2c_length = 1;
|
||||
p.i2c_first_read_done = true;
|
||||
break;
|
||||
|
||||
case RTC_PHASE_UPDATE:
|
||||
sanitize_time((uint8_t *)(&p.time));
|
||||
p.i2c_pending = true;
|
||||
p.i2c_write = true;
|
||||
p.i2c_length = 7;
|
||||
p.data[0] = RTCMIN;
|
||||
p.data[1] = p.time.minutes;
|
||||
p.data[2] = p.time.hours;
|
||||
p.data[3] = p.time.weekday | RTCWKDAY_VBAT;
|
||||
p.data[4] = p.time.day;
|
||||
p.data[5] = p.time.month;
|
||||
p.data[6] = p.time.year;
|
||||
p.rtc_phase = RTC_PHASE_START;
|
||||
break;
|
||||
|
||||
case RTC_PHASE_START:
|
||||
p.i2c_pending = true;
|
||||
p.i2c_write = true;
|
||||
p.i2c_length = 2;
|
||||
p.i2c_first_read_done = false;
|
||||
p.data[0] = RTCSEC;
|
||||
p.data[1] = p.time.seconds | RTCSEC_ST;
|
||||
p.rtc_phase = RTC_PHASE_WAIT_START;
|
||||
break;
|
||||
|
||||
case RTC_PHASE_WAIT_START:
|
||||
if (p.i2c_first_read_done) {
|
||||
if (p.data[0] & RTCWKDAY_OSCRUN) {
|
||||
p.new_time_valid = false;
|
||||
p.rtc_phase = RTC_PHASE_READ_START;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.i2c_pending = true;
|
||||
p.i2c_write = false;
|
||||
p.i2c_address = RTCWKDAY;
|
||||
p.i2c_length = 1;
|
||||
p.i2c_first_read_done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!i2c_busy()) {
|
||||
switch (p.i2c_phase) {
|
||||
case I2C_PHASE_IDLE:
|
||||
if (p.i2c_pending) {
|
||||
p.i2c_pending = false;
|
||||
p.i2c_phase = p.i2c_write ? I2C_PHASE_DATA : I2C_PHASE_ADDR;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_PHASE_ADDR:
|
||||
i2c_trx(RTC_I2C_ADDR, &p.i2c_address, 1, true, false);
|
||||
p.i2c_phase = I2C_PHASE_DATA;
|
||||
break;
|
||||
|
||||
case I2C_PHASE_DATA:
|
||||
i2c_trx(RTC_I2C_ADDR, p.data, p.i2c_length, p.i2c_write, true);
|
||||
p.i2c_phase = I2C_PHASE_READY;
|
||||
break;
|
||||
|
||||
case I2C_PHASE_READY:
|
||||
p.i2c_phase = I2C_PHASE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
27
sw/riscv/src/rtc.h
Normal file
27
sw/riscv/src/rtc.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef RTC_H__
|
||||
#define RTC_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t seconds;
|
||||
uint8_t minutes;
|
||||
uint8_t hours;
|
||||
uint8_t weekday;
|
||||
uint8_t day;
|
||||
uint8_t month;
|
||||
uint8_t year;
|
||||
} rtc_time_t;
|
||||
|
||||
|
||||
rtc_time_t *rtc_get_time (void);
|
||||
bool rtc_is_time_valid (void);
|
||||
bool rtc_is_time_running (void);
|
||||
void rtc_set_time (rtc_time_t *time);
|
||||
void rtc_init (void);
|
||||
void process_rtc (void);
|
||||
|
||||
|
||||
#endif
|
@ -4,10 +4,10 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#define DEFAULT_SAVE_OFFSET (0x03FE0000UL)
|
||||
#define DEFAULT_DD_OFFSET (0x03BE0000UL)
|
||||
#define DEBUG_ENABLED
|
||||
|
||||
|
||||
typedef volatile uint8_t io8_t;
|
||||
@ -46,7 +46,6 @@ typedef volatile struct i2c_regs {
|
||||
#define I2C_SCR_MACK (1 << 2)
|
||||
#define I2C_SCR_ACK (1 << 3)
|
||||
#define I2C_SCR_BUSY (1 << 4)
|
||||
#define I2C_ADDR_READ (1 << 0)
|
||||
|
||||
|
||||
typedef volatile struct usb_regs {
|
||||
@ -137,23 +136,23 @@ typedef volatile struct flashram_regs {
|
||||
#define FLASHRAM_PAGE_BIT (8)
|
||||
|
||||
|
||||
typedef volatile struct si_regs {
|
||||
typedef volatile struct joybus_regs {
|
||||
io32_t SCR;
|
||||
io32_t DATA[3];
|
||||
} si_regs_t;
|
||||
} joybus_regs_t;
|
||||
|
||||
#define SI_BASE (0xA0000000UL)
|
||||
#define SI ((si_regs_t *) SI_BASE)
|
||||
#define JOYBUS_BASE (0xA0000000UL)
|
||||
#define JOYBUS ((joybus_regs_t *) JOYBUS_BASE)
|
||||
|
||||
#define SI_SCR_RX_READY (1 << 0)
|
||||
#define SI_SCR_RX_STOP_BIT (1 << 1)
|
||||
#define SI_SCR_TX_START (1 << 2)
|
||||
#define SI_SCR_TX_BUSY (1 << 3)
|
||||
#define SI_SCR_RX_RESET (1 << 6)
|
||||
#define SI_SCR_TX_RESET (1 << 7)
|
||||
#define SI_SCR_RX_LENGTH_BIT (8)
|
||||
#define SI_SCR_RX_LENGTH_MASK (0x7F << SI_SCR_RX_LENGTH_BIT)
|
||||
#define SI_SCR_TX_LENGTH_BIT (16)
|
||||
#define JOYBUS_SCR_RX_READY (1 << 0)
|
||||
#define JOYBUS_SCR_RX_STOP_BIT (1 << 1)
|
||||
#define JOYBUS_SCR_TX_START (1 << 2)
|
||||
#define JOYBUS_SCR_TX_BUSY (1 << 3)
|
||||
#define JOYBUS_SCR_RX_RESET (1 << 6)
|
||||
#define JOYBUS_SCR_TX_RESET (1 << 7)
|
||||
#define JOYBUS_SCR_RX_LENGTH_BIT (8)
|
||||
#define JOYBUS_SCR_RX_LENGTH_MASK (0x7F << JOYBUS_SCR_RX_LENGTH_BIT)
|
||||
#define JOYBUS_SCR_TX_LENGTH_BIT (16)
|
||||
|
||||
|
||||
void reset_handler (void);
|
||||
|
72
sw/riscv/src/uart.c
Normal file
72
sw/riscv/src/uart.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include "uart.h"
|
||||
#include "rtc.h"
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
static const char hex_char_map[16] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
void uart_print (const char *text) {
|
||||
while (*text != '\0') {
|
||||
while (!(UART->SCR & UART_SCR_TXE));
|
||||
UART->DR = *text++;
|
||||
}
|
||||
}
|
||||
|
||||
void uart_print_02hex (uint8_t number) {
|
||||
char buffer[3];
|
||||
buffer[0] = hex_char_map[(number >> 4) & 0x0F];
|
||||
buffer[1] = hex_char_map[number & 0x0F];
|
||||
buffer[2] = '\0';
|
||||
uart_print(buffer);
|
||||
}
|
||||
|
||||
void uart_print_08hex (uint32_t number) {
|
||||
uart_print_02hex((number >> 24) & 0xFF);
|
||||
uart_print_02hex((number >> 16) & 0xFF);
|
||||
uart_print_02hex((number >> 8) & 0xFF);
|
||||
uart_print_02hex((number >> 0) & 0xFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
void uart_init (void) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
uart_print("App ready!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void process_uart (void) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
rtc_time_t *time;
|
||||
|
||||
if (UART->SCR & USB_SCR_RXNE) {
|
||||
switch (UART->DR) {
|
||||
case '/':
|
||||
uart_print("Bootloader reset...\n");
|
||||
reset_handler();
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
uart_print("App reset...\n");
|
||||
app_handler();
|
||||
break;
|
||||
|
||||
case 't':
|
||||
time = rtc_get_time();
|
||||
uart_print("Current time: ");
|
||||
if (rtc_is_time_running()) {
|
||||
uart_print("(running) ");
|
||||
}
|
||||
if (rtc_is_time_valid()) {
|
||||
uart_print("(valid) ");
|
||||
}
|
||||
for (int i = 0; i < 7; i++) {
|
||||
uart_print_02hex(((uint8_t *)(time))[i]);
|
||||
uart_print(" ");
|
||||
}
|
||||
uart_print("\r\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
15
sw/riscv/src/uart.h
Normal file
15
sw/riscv/src/uart.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef UART_H__
|
||||
#define UART_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
void uart_print (const char *text);
|
||||
void uart_print_02hex (uint8_t number);
|
||||
void uart_print_08hex (uint32_t number);
|
||||
void uart_init (void);
|
||||
void process_uart (void);
|
||||
|
||||
|
||||
#endif
|
157
sw/riscv/src/usb.c
Normal file
157
sw/riscv/src/usb.c
Normal file
@ -0,0 +1,157 @@
|
||||
#include "usb.h"
|
||||
#include "dma.h"
|
||||
#include "cfg.h"
|
||||
|
||||
|
||||
static bool rx_byte (uint8_t *data) {
|
||||
if (!(USB->SCR & USB_SCR_RXNE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = USB->DR;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rx_word (uint32_t *data) {
|
||||
static uint8_t current_byte = 0;
|
||||
static uint32_t buffer = 0;
|
||||
uint8_t tmp;
|
||||
|
||||
while (rx_byte(&tmp)) {
|
||||
buffer = (buffer << 8) | tmp;
|
||||
current_byte += 1;
|
||||
if (current_byte == 4) {
|
||||
current_byte = 0;
|
||||
*data = buffer;
|
||||
buffer = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tx_byte (uint8_t data) {
|
||||
if (!(USB->SCR & USB_SCR_TXE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
USB->DR = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tx_word (uint32_t data) {
|
||||
static uint8_t current_byte = 0;
|
||||
while (tx_byte(data >> ((3 - current_byte) * 8))) {
|
||||
current_byte += 1;
|
||||
if (current_byte == 4) {
|
||||
current_byte = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#define USB_CMD_TOKEN (0x434D4400)
|
||||
#define USB_CMP_TOKEN (0x434D5000)
|
||||
#define USB_ERR_TOKEN (0x45525200)
|
||||
|
||||
enum state {
|
||||
STATE_IDLE,
|
||||
STATE_ARGS,
|
||||
STATE_DATA,
|
||||
STATE_RESPONSE,
|
||||
};
|
||||
|
||||
struct process {
|
||||
enum state state;
|
||||
uint8_t counter;
|
||||
uint8_t cmd;
|
||||
uint32_t args[2];
|
||||
bool error;
|
||||
bool dma_in_progress;
|
||||
};
|
||||
|
||||
static struct process p;
|
||||
|
||||
|
||||
void usb_init (void) {
|
||||
USB->SCR = USB_SCR_FLUSH_TX | USB_SCR_FLUSH_RX;
|
||||
p.state = STATE_IDLE;
|
||||
}
|
||||
|
||||
|
||||
void process_usb (void) {
|
||||
switch (p.state) {
|
||||
case STATE_IDLE:
|
||||
if (rx_word(&p.args[0])) {
|
||||
if ((p.args[0] & 0xFFFFFF00) == USB_CMD_TOKEN) {
|
||||
p.cmd = p.args[0] & 0xFF;
|
||||
p.counter = 0;
|
||||
p.error = false;
|
||||
p.dma_in_progress = false;
|
||||
p.state = STATE_ARGS;
|
||||
} else {
|
||||
p.cmd = '!';
|
||||
p.error = true;
|
||||
p.state = STATE_RESPONSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_ARGS:
|
||||
if (rx_word(&p.args[p.counter])) {
|
||||
p.counter += 1;
|
||||
if (p.counter == 2) {
|
||||
p.state = STATE_DATA;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_DATA:
|
||||
switch (p.cmd) {
|
||||
case 'C':
|
||||
cfg_update(p.args);
|
||||
p.state = STATE_RESPONSE;
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
cfg_query(p.args);
|
||||
if (tx_word(p.args[1])) {
|
||||
p.state = STATE_RESPONSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
case 'W':
|
||||
if (!dma_busy()) {
|
||||
if (!p.dma_in_progress) {
|
||||
enum dma_dir dir = p.cmd == 'W' ? DMA_DIR_TO_SDRAM : DMA_DIR_FROM_SDRAM;
|
||||
dma_start(p.args[0], p.args[1], DMA_ID_USB, dir);
|
||||
p.dma_in_progress = true;
|
||||
} else {
|
||||
p.state = STATE_RESPONSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
p.error = false;
|
||||
p.state = STATE_RESPONSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_RESPONSE:
|
||||
if (tx_word(p.error ? USB_ERR_TOKEN : (USB_CMP_TOKEN | p.cmd))) {
|
||||
p.state = STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
12
sw/riscv/src/usb.h
Normal file
12
sw/riscv/src/usb.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef USB_H__
|
||||
#define USB_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
void usb_init (void);
|
||||
void process_usb (void);
|
||||
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user