From 545d906a68bfb96fe9253079a99645933938f666 Mon Sep 17 00:00:00 2001 From: Polprzewodnikowy Date: Mon, 13 Sep 2021 00:22:15 +0200 Subject: [PATCH] huge controller sw cleanup --- fw/rtl/intel/flash/intel_flash.qsys | 4 +- sw/n64/src/main.c | 4 +- sw/n64/src/sc64.c | 12 - sw/n64/src/sc64.h | 22 +- sw/pc/dum.py | 4 +- sw/riscv/Makefile | 2 + sw/riscv/SC64.ld | 1 - sw/riscv/src/cfg.c | 202 ++++++++++ sw/riscv/src/cfg.h | 14 + sw/riscv/src/controller.c | 550 ---------------------------- sw/riscv/src/controller.h | 52 --- sw/riscv/src/dma.c | 26 ++ sw/riscv/src/dma.h | 26 ++ sw/riscv/src/driver.c | 402 -------------------- sw/riscv/src/driver.h | 165 --------- sw/riscv/src/flashram.c | 69 ++++ sw/riscv/src/flashram.h | 12 + sw/riscv/src/i2c.c | 113 ++++++ sw/riscv/src/i2c.h | 16 + sw/riscv/src/joybus.c | 163 +++++++++ sw/riscv/src/joybus.h | 20 + sw/riscv/src/main.c | 7 + sw/riscv/src/process.c | 35 ++ sw/riscv/src/process.h | 9 + sw/riscv/src/rtc.c | 225 ++++++++++++ sw/riscv/src/rtc.h | 27 ++ sw/riscv/src/sys.h | 31 +- sw/riscv/src/uart.c | 72 ++++ sw/riscv/src/uart.h | 15 + sw/riscv/src/usb.c | 157 ++++++++ sw/riscv/src/usb.h | 12 + 31 files changed, 1254 insertions(+), 1215 deletions(-) create mode 100644 sw/riscv/src/cfg.c create mode 100644 sw/riscv/src/cfg.h delete mode 100644 sw/riscv/src/controller.c delete mode 100644 sw/riscv/src/controller.h create mode 100644 sw/riscv/src/dma.c create mode 100644 sw/riscv/src/dma.h delete mode 100644 sw/riscv/src/driver.c delete mode 100644 sw/riscv/src/driver.h create mode 100644 sw/riscv/src/flashram.c create mode 100644 sw/riscv/src/flashram.h create mode 100644 sw/riscv/src/i2c.c create mode 100644 sw/riscv/src/i2c.h create mode 100644 sw/riscv/src/joybus.c create mode 100644 sw/riscv/src/joybus.h create mode 100644 sw/riscv/src/main.c create mode 100644 sw/riscv/src/process.c create mode 100644 sw/riscv/src/process.h create mode 100644 sw/riscv/src/rtc.c create mode 100644 sw/riscv/src/rtc.h create mode 100644 sw/riscv/src/uart.c create mode 100644 sw/riscv/src/uart.h create mode 100644 sw/riscv/src/usb.c create mode 100644 sw/riscv/src/usb.h diff --git a/fw/rtl/intel/flash/intel_flash.qsys b/fw/rtl/intel/flash/intel_flash.qsys index 17afbc8..9aca588 100644 --- a/fw/rtl/intel/flash/intel_flash.qsys +++ b/fw/rtl/intel/flash/intel_flash.qsys @@ -71,8 +71,8 @@ Read only,Read only,Hidden,Read only,Read only $${FILENAME}_onchip_flash_0 - ../sw/n64/bootloader/build/SummerLoader64.hex - ../sw/n64/bootloader/build/SummerLoader64.hex + ../sw/n64/build/SummerLoader64.hex + ../sw/n64/build/SummerLoader64.hex diff --git a/sw/n64/src/main.c b/sw/n64/src/main.c index 49cb5d8..1e0aac6 100644 --- a/sw/n64/src/main.c +++ b/sw/n64/src/main.c @@ -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); } diff --git a/sw/n64/src/sc64.c b/sw/n64/src/sc64.c index 35f7ba2..bc2bc81 100644 --- a/sw/n64/src/sc64.c +++ b/sw/n64/src/sc64.c @@ -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); -} diff --git a/sw/n64/src/sc64.h b/sw/n64/src/sc64.h index f4ea5f9..a478b5f 100644 --- a/sw/n64/src/sc64.h +++ b/sw/n64/src/sc64.h @@ -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 diff --git a/sw/pc/dum.py b/sw/pc/dum.py index 4c75d19..e4374c2 100644 --- a/sw/pc/dum.py +++ b/sw/pc/dum.py @@ -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) diff --git a/sw/riscv/Makefile b/sw/riscv/Makefile index 9919549..c0cbd1e 100644 --- a/sw/riscv/Makefile +++ b/sw/riscv/Makefile @@ -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 diff --git a/sw/riscv/SC64.ld b/sw/riscv/SC64.ld index 22abc7c..2ca7c56 100644 --- a/sw/riscv/SC64.ld +++ b/sw/riscv/SC64.ld @@ -9,7 +9,6 @@ ENTRY(reset_handler) SECTIONS { .text : { - PROVIDE(__app_entry_point = .); *(.text.app_handler) *(.text.unlikely .text.unlikely.*) *(.text.startup .text.startup.*) diff --git a/sw/riscv/src/cfg.c b/sw/riscv/src/cfg.c new file mode 100644 index 0000000..75052a8 --- /dev/null +++ b/sw/riscv/src/cfg.c @@ -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); + } +} diff --git a/sw/riscv/src/cfg.h b/sw/riscv/src/cfg.h new file mode 100644 index 0000000..9377005 --- /dev/null +++ b/sw/riscv/src/cfg.h @@ -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 diff --git a/sw/riscv/src/controller.c b/sw/riscv/src/controller.c deleted file mode 100644 index b9e9656..0000000 --- a/sw/riscv/src/controller.c +++ /dev/null @@ -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; - } -} diff --git a/sw/riscv/src/controller.h b/sw/riscv/src/controller.h deleted file mode 100644 index d5d4228..0000000 --- a/sw/riscv/src/controller.h +++ /dev/null @@ -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 diff --git a/sw/riscv/src/dma.c b/sw/riscv/src/dma.c new file mode 100644 index 0000000..3015753 --- /dev/null +++ b/sw/riscv/src/dma.c @@ -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) { + +} diff --git a/sw/riscv/src/dma.h b/sw/riscv/src/dma.h new file mode 100644 index 0000000..e259cbb --- /dev/null +++ b/sw/riscv/src/dma.h @@ -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 diff --git a/sw/riscv/src/driver.c b/sw/riscv/src/driver.c deleted file mode 100644 index 94a3e65..0000000 --- a/sw/riscv/src/driver.c +++ /dev/null @@ -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) - ); -} diff --git a/sw/riscv/src/driver.h b/sw/riscv/src/driver.h deleted file mode 100644 index 9c411a1..0000000 --- a/sw/riscv/src/driver.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef DRIVER_H__ -#define DRIVER_H__ - - -#include -#include -#include - - -// 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 diff --git a/sw/riscv/src/flashram.c b/sw/riscv/src/flashram.c new file mode 100644 index 0000000..6d1e2c5 --- /dev/null +++ b/sw/riscv/src/flashram.c @@ -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; + } +} diff --git a/sw/riscv/src/flashram.h b/sw/riscv/src/flashram.h new file mode 100644 index 0000000..2d682bc --- /dev/null +++ b/sw/riscv/src/flashram.h @@ -0,0 +1,12 @@ +#ifndef FLASHRAM_H__ +#define FLASHRAM_H__ + + +#include "sys.h" + + +void flashram_init (void); +void process_flashram (void); + + +#endif diff --git a/sw/riscv/src/i2c.c b/sw/riscv/src/i2c.c new file mode 100644 index 0000000..fd34472 --- /dev/null +++ b/sw/riscv/src/i2c.c @@ -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; + } + } +} diff --git a/sw/riscv/src/i2c.h b/sw/riscv/src/i2c.h new file mode 100644 index 0000000..8869685 --- /dev/null +++ b/sw/riscv/src/i2c.h @@ -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 diff --git a/sw/riscv/src/joybus.c b/sw/riscv/src/joybus.c new file mode 100644 index 0000000..486d42e --- /dev/null +++ b/sw/riscv/src/joybus.c @@ -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; + } +} diff --git a/sw/riscv/src/joybus.h b/sw/riscv/src/joybus.h new file mode 100644 index 0000000..ef2d21f --- /dev/null +++ b/sw/riscv/src/joybus.h @@ -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 diff --git a/sw/riscv/src/main.c b/sw/riscv/src/main.c new file mode 100644 index 0000000..d539a5f --- /dev/null +++ b/sw/riscv/src/main.c @@ -0,0 +1,7 @@ +#include "process.h" + + +void main (void) { + process_init(); + process_loop(); +} diff --git a/sw/riscv/src/process.c b/sw/riscv/src/process.c new file mode 100644 index 0000000..093ded3 --- /dev/null +++ b/sw/riscv/src/process.c @@ -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(); + } +} diff --git a/sw/riscv/src/process.h b/sw/riscv/src/process.h new file mode 100644 index 0000000..e0df2a1 --- /dev/null +++ b/sw/riscv/src/process.h @@ -0,0 +1,9 @@ +#ifndef PROCESS_H__ +#define PROCESS_H__ + + +void process_init (void); +void process_loop (void); + + +#endif diff --git a/sw/riscv/src/rtc.c b/sw/riscv/src/rtc.c new file mode 100644 index 0000000..6183707 --- /dev/null +++ b/sw/riscv/src/rtc.c @@ -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; + } + } +} diff --git a/sw/riscv/src/rtc.h b/sw/riscv/src/rtc.h new file mode 100644 index 0000000..7566964 --- /dev/null +++ b/sw/riscv/src/rtc.h @@ -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 diff --git a/sw/riscv/src/sys.h b/sw/riscv/src/sys.h index 21e1367..9f7c14d 100644 --- a/sw/riscv/src/sys.h +++ b/sw/riscv/src/sys.h @@ -4,10 +4,10 @@ #include #include +#include -#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); diff --git a/sw/riscv/src/uart.c b/sw/riscv/src/uart.c new file mode 100644 index 0000000..58ca196 --- /dev/null +++ b/sw/riscv/src/uart.c @@ -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 +} diff --git a/sw/riscv/src/uart.h b/sw/riscv/src/uart.h new file mode 100644 index 0000000..c690dac --- /dev/null +++ b/sw/riscv/src/uart.h @@ -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 diff --git a/sw/riscv/src/usb.c b/sw/riscv/src/usb.c new file mode 100644 index 0000000..64f413d --- /dev/null +++ b/sw/riscv/src/usb.c @@ -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; + } +} diff --git a/sw/riscv/src/usb.h b/sw/riscv/src/usb.h new file mode 100644 index 0000000..3b4f5e4 --- /dev/null +++ b/sw/riscv/src/usb.h @@ -0,0 +1,12 @@ +#ifndef USB_H__ +#define USB_H__ + + +#include "sys.h" + + +void usb_init (void); +void process_usb (void); + + +#endif