huge controller sw cleanup

This commit is contained in:
Polprzewodnikowy 2021-09-13 00:22:15 +02:00
parent ef205d218a
commit 545d906a68
31 changed files with 1254 additions and 1215 deletions

View File

@ -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" />

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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;
}
}

View File

@ -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
View 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
View 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

View File

@ -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)
);
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,7 @@
#include "process.h"
void main (void) {
process_init();
process_loop();
}

35
sw/riscv/src/process.c Normal file
View 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
View 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
View 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
View 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

View File

@ -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
View 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
View 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
View 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
View File

@ -0,0 +1,12 @@
#ifndef USB_H__
#define USB_H__
#include "sys.h"
void usb_init (void);
void process_usb (void);
#endif