diff --git a/build.sh b/build.sh index 9f5b78a..1fde564 100755 --- a/build.sh +++ b/build.sh @@ -8,6 +8,7 @@ PACKAGE_FILE_NAME="sc64-extra" TOP_FILES=( "./fw/ftdi/ft232h_config.xml" + "./fw/project/lcmxo2/impl1/fpga_max_frequency.txt" "./sw/tools/primer.py" "./sw/tools/requirements.txt" "./sc64-firmware-${SC64_VERSION}.bin" @@ -90,6 +91,7 @@ build_update () { rm -f ../../sc64-firmware-*.bin fi GIT_INFO="" + GIT_INFO+=$'\n'"freq: $(cat ../../fw/project/lcmxo2/impl1/fpga_max_frequency.txt)" if [ ! -z "${SC64_VERSION}" ]; then GIT_INFO+=$'\n'"ver: $SC64_VERSION"; fi if [ ! -z "${GIT_BRANCH}" ]; then GIT_INFO+=$'\n'"branch: $GIT_BRANCH"; fi if [ ! -z "${GIT_TAG}" ]; then GIT_INFO+=$'\n'"tag: $GIT_TAG"; fi diff --git a/docs/03_n64_commands.md b/docs/03_n64_commands.md index c12d6bc..7655977 100644 --- a/docs/03_n64_commands.md +++ b/docs/03_n64_commands.md @@ -4,26 +4,27 @@ ## N64 commands -| id | name | arg0 | arg1 | rsp0 | rsp1 | description | -| --- | --------------------- | ---------- | ------------ | ---------------- | -------------- | -------------------------------------------------- | -| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` | -| `V` | **VERSION_GET** | --- | --- | version | --- | Get flashcart firmware version | -| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | -| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value | -| `c` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option | -| `C` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option | -| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value | -| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value | -| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart | -| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB | -| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length | -| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status | -| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on SD card | -| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation | -| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart | -| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card | -| `D` | **DD_SD_INFO** | pi_address | table_size | --- | --- | Set 64DD disk SD sector info | -| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it | -| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer | -| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size | -| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase | +| id | name | arg0 | arg1 | rsp0 | rsp1 | description | +| --- | --------------------- | -------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- | +| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` | +| `V` | **VERSION_GET** | --- | --- | version | --- | Get flashcart firmware version | +| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | +| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value | +| `c` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option | +| `C` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option | +| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value | +| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value | +| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart | +| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB | +| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length | +| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status | +| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on SD card | +| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation | +| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart | +| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card | +| `D` | **DD_SD_INFO** | pi_address | table_size | --- | --- | Set 64DD disk SD sector info | +| `w` | **WRITEBACK_PENDING** | pending_status | --- | --- | --- | Get save writeback status (is write queued to the SD card) | +| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it | +| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer | +| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size | +| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase | diff --git a/fw/project/lcmxo2/build.sh b/fw/project/lcmxo2/build.sh index 35a8b44..ebe6849 100755 --- a/fw/project/lcmxo2/build.sh +++ b/fw/project/lcmxo2/build.sh @@ -1,5 +1,31 @@ #!/bin/bash +set -e + source $bindir/diamond_env diamondc build.tcl + +MINIMUM_FREQ=$(cat impl1/sc64_impl1.twr \ + | grep 'Preference: FREQUENCY NET "clk"' \ + | head -1 \ + | awk -F ' ' '{print $5}' \ +) + +DESIGN_FREQ=$(cat impl1/sc64_impl1.twr \ + | sed -n '/Preference: FREQUENCY NET "clk"/,$p' \ + | grep 'is the maximum frequency for this preference' \ + | head -1 \ + | awk -F ' ' '{print $2}' \ + | sed 's/MHz//' \ +) + +echo "Minimum required frequency: $MINIMUM_FREQ MHz" +echo "Maximum design frequency: $DESIGN_FREQ MHz" + +if (( $(echo "$DESIGN_FREQ < $MINIMUM_FREQ" | bc -l) )); then + echo "Timing error detected, build failed" + exit 1 +fi + +echo -n "$DESIGN_FREQ MHz" > impl1/fpga_max_frequency.txt diff --git a/fw/project/lcmxo2/sc64.lpf b/fw/project/lcmxo2/sc64.lpf index ac7502d..49d8d38 100644 --- a/fw/project/lcmxo2/sc64.lpf +++ b/fw/project/lcmxo2/sc64.lpf @@ -21,8 +21,10 @@ IOBUF PORT "inclk" PULLMODE=NONE IO_TYPE=LVCMOS33 ; IOBUF PORT "mcu_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 ; IOBUF PORT "mcu_cs" PULLMODE=UP IO_TYPE=LVCMOS33 ; IOBUF PORT "mcu_int" PULLMODE=UP IO_TYPE=LVCMOS33 ; -IOBUF PORT "mcu_miso" IO_TYPE=LVCMOS33 PULLMODE=NONE ; -IOBUF PORT "mcu_mosi" IO_TYPE=LVCMOS33 PULLMODE=NONE ; +IOBUF PORT "mcu_miso" PULLMODE=NONE IO_TYPE=LVCMOS33 ; +IOBUF PORT "mcu_mosi" PULLMODE=NONE IO_TYPE=LVCMOS33 ; +IOBUF PORT "n64_cic_clk" PULLMODE=UP IO_TYPE=LVCMOS33 ; +IOBUF PORT "n64_cic_dq" PULLMODE=UP IO_TYPE=LVCMOS33 ; IOBUF PORT "n64_irq" PULLMODE=UP IO_TYPE=LVCMOS33 ; IOBUF PORT "n64_nmi" PULLMODE=DOWN IO_TYPE=LVCMOS33 ; IOBUF PORT "n64_pi_ad[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ; @@ -48,6 +50,7 @@ IOBUF PORT "n64_pi_write" PULLMODE=UP IO_TYPE=LVCMOS33 ; IOBUF PORT "n64_reset" PULLMODE=DOWN IO_TYPE=LVCMOS33 ; IOBUF PORT "n64_si_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 ; IOBUF PORT "n64_si_dq" PULLMODE=UP IO_TYPE=LVCMOS33 ; +IOBUF PORT "n64_video_sync" PULLMODE=NONE IO_TYPE=LVCMOS33 ; IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 ; IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 ; IOBUF PORT "sd_dat[0]" PULLMODE=UP IO_TYPE=LVCMOS33 ; @@ -120,6 +123,8 @@ LOCATE COMP "mcu_miso" SITE "119" ; LOCATE COMP "mcu_mosi" SITE "120" ; LOCATE COMP "n64_irq" SITE "32" ; LOCATE COMP "n64_nmi" SITE "28" ; +LOCATE COMP "n64_cic_clk" SITE "34" ; +LOCATE COMP "n64_cic_dq" SITE "35" ; LOCATE COMP "n64_pi_ad[0]" SITE "60" ; LOCATE COMP "n64_pi_ad[1]" SITE "58" ; LOCATE COMP "n64_pi_ad[10]" SITE "42" ; @@ -143,6 +148,7 @@ LOCATE COMP "n64_pi_write" SITE "49" ; LOCATE COMP "n64_reset" SITE "31" ; LOCATE COMP "n64_si_clk" SITE "33" ; LOCATE COMP "n64_si_dq" SITE "27" ; +LOCATE COMP "n64_video_sync" SITE "26" ; LOCATE COMP "sd_clk" SITE "111" ; LOCATE COMP "sd_cmd" SITE "112" ; LOCATE COMP "sd_dat[0]" SITE "110" ; diff --git a/fw/rtl/mcu/mcu_top.sv b/fw/rtl/mcu/mcu_top.sv index 3b80958..e55c36c 100644 --- a/fw/rtl/mcu/mcu_top.sv +++ b/fw/rtl/mcu/mcu_top.sv @@ -364,6 +364,7 @@ module mcu_top ( logic bootloader_skip; assign n64_scb.cfg_identifier = 32'h53437632; + assign usb_dma_scb.byte_swap = 1'b0; logic dd_bm_ack; @@ -577,7 +578,8 @@ module mcu_top ( REG_SD_DMA_SCR: begin reg_rdata <= { - 28'd0, + 27'd0, + sd_dma_scb.byte_swap, sd_dma_scb.busy, sd_dma_scb.direction, 2'b00 @@ -855,11 +857,10 @@ module mcu_top ( end REG_SD_DMA_SCR: begin - { - sd_dma_scb.direction, - sd_dma_scb.stop, - sd_dma_scb.start - } <= reg_wdata[2:0]; + sd_dma_scb.byte_swap <= reg_wdata[4]; + sd_dma_scb.direction <= reg_wdata[2]; + sd_dma_scb.stop <= reg_wdata[1]; + sd_dma_scb.start <= reg_wdata[0]; end REG_DD_SCR: begin diff --git a/fw/rtl/memory/memory_dma.sv b/fw/rtl/memory/memory_dma.sv index fcba0bd..b401ddf 100644 --- a/fw/rtl/memory/memory_dma.sv +++ b/fw/rtl/memory/memory_dma.sv @@ -4,6 +4,7 @@ interface dma_scb (); logic stop; logic busy; logic direction; + logic byte_swap; logic [26:0] starting_address; logic [26:0] transfer_length; @@ -12,6 +13,7 @@ interface dma_scb (); output stop, input busy, output direction, + output byte_swap, output starting_address, output transfer_length ); @@ -21,6 +23,7 @@ interface dma_scb (); input stop, output busy, input direction, + input byte_swap, input starting_address, input transfer_length ); @@ -61,6 +64,7 @@ module memory_dma ( // RX FIFO controller + logic [1:0] rx_wmask; logic rx_rdata_pop; logic rx_rdata_shift; logic rx_rdata_valid; @@ -88,11 +92,11 @@ module memory_dma ( if (dma_start) begin if (dma_scb.starting_address[0]) begin - mem_bus.wmask <= 2'b01; + rx_wmask <= 2'b01; rx_buffer_counter <= 2'd1; rx_buffer_valid_counter <= 2'd1; end else begin - mem_bus.wmask <= 2'b11; + rx_wmask <= 2'b11; rx_buffer_counter <= 2'd0; rx_buffer_valid_counter <= 2'd0; end @@ -103,16 +107,21 @@ module memory_dma ( end if (rx_rdata_shift || rx_rdata_valid) begin - rx_buffer <= {rx_buffer[7:0], fifo_bus.rx_rdata}; + if (dma_scb.byte_swap) begin + rx_buffer <= {fifo_bus.rx_rdata, rx_buffer[15:8]}; + end else begin + rx_buffer <= {rx_buffer[7:0], fifo_bus.rx_rdata}; + end rx_buffer_valid_counter <= rx_buffer_valid_counter + 1'd1; if (remaining == 27'd0 && rx_buffer_counter == 2'd1) begin - mem_bus.wmask <= 2'b10; + rx_wmask <= 2'b10; rx_rdata_shift <= 1'b1; rx_buffer_counter <= rx_buffer_counter + 1'd1; end end if (rx_buffer_valid && !mem_bus.request) begin + rx_wmask <= 2'b11; rx_buffer_counter <= 2'd0; rx_buffer_valid_counter <= 2'd0; end @@ -209,6 +218,7 @@ module memory_dma ( if (mem_bus.write) begin if (rx_buffer_valid) begin mem_bus.request <= 1'b1; + mem_bus.wmask <= rx_wmask; mem_bus.wdata <= rx_buffer; end end else begin diff --git a/fw/rtl/top.sv b/fw/rtl/top.sv index 293dd9b..7cad9ad 100644 --- a/fw/rtl/top.sv +++ b/fw/rtl/top.sv @@ -45,7 +45,12 @@ module top ( input mcu_clk, input mcu_cs, input mcu_mosi, - output mcu_miso + output mcu_miso, + + // Unused I/O + output n64_cic_clk, + output n64_cic_dq, + output n64_video_sync ); logic clk; @@ -264,4 +269,11 @@ module top ( .vendor_scb(vendor_scb) ); + + // Unused I/O + + assign n64_cic_clk = 1'bZ; + assign n64_cic_dq = 1'bZ; + assign n64_video_sync = 1'bZ; + endmodule diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index c36fab3..e8387bf 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -52,6 +52,8 @@ typedef enum { SD_CARD_OP_INIT = 1, SD_CARD_OP_GET_STATUS = 2, SD_CARD_OP_GET_INFO = 3, + SD_CARD_OP_BYTE_SWAP_ON = 4, + SD_CARD_OP_BYTE_SWAP_OFF = 5, } sd_card_op_t; @@ -235,6 +237,14 @@ bool sc64_sd_card_get_info (void *address) { return false; } +bool sc64_sd_set_byte_swap (bool enabled) { + uint32_t args[2] = { (uint32_t) (NULL), enabled ? SD_CARD_OP_BYTE_SWAP_ON : SD_CARD_OP_BYTE_SWAP_OFF }; + if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) { + return true; + } + return false; +} + bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count) { uint32_t sector_set_args[2] = { sector, 0 }; uint32_t read_args[2] = { (uint32_t) (address), count }; diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index 030f43d..e77cff6 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -86,6 +86,7 @@ typedef enum { SD_CARD_STATUS_INITIALIZED = (1 << 1), SD_CARD_STATUS_TYPE_BLOCK = (1 << 2), SD_CARD_STATUS_50MHZ_MODE = (1 << 3), + SD_CARD_STATUS_BYTE_SWAP = (1 << 4), } sc64_sd_card_status_t; typedef struct { @@ -143,6 +144,7 @@ bool sc64_sd_card_init (void); bool sc64_sd_card_deinit (void); sc64_sd_card_status_t sc64_sd_card_get_status (void); bool sc64_sd_card_get_info (void *address); +bool sc64_sd_set_byte_swap (bool enabled); bool sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count); bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count); bool sc64_dd_set_sd_disk_info (void *address, uint32_t length); diff --git a/sw/bootloader/src/test.c b/sw/bootloader/src/test.c index 392c860..8aa194d 100644 --- a/sw/bootloader/src/test.c +++ b/sw/bootloader/src/test.c @@ -57,6 +57,9 @@ static void test_sd_card (void) { if (card_status & SD_CARD_STATUS_50MHZ_MODE) { display_printf("SD card runs at 50 MHz clock speed\n"); } + if (card_status & SD_CARD_STATUS_BYTE_SWAP) { + display_printf("SD card read byte swap is enabled\n"); + } if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) { display_printf("SD card get info error!\n"); diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index 1ff6a66..2a0757c 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -79,6 +79,8 @@ typedef enum { SD_CARD_OP_INIT = 1, SD_CARD_OP_GET_STATUS = 2, SD_CARD_OP_GET_INFO = 3, + SD_CARD_OP_BYTE_SWAP_ON = 4, + SD_CARD_OP_BYTE_SWAP_OFF = 5, } sd_card_op_t; typedef enum { @@ -176,7 +178,7 @@ static void cfg_change_scr_bits (uint32_t mask, bool value) { } static bool cfg_set_save_type (save_type_t save_type) { - if (save_type > SAVE_TYPE_SRAM_BANKED) { + if (save_type > SAVE_TYPE_SRAM_1M) { return true; } @@ -575,6 +577,18 @@ void cfg_process (void) { return; } break; + case SD_CARD_OP_BYTE_SWAP_ON: + if (sd_set_byte_swap(true)) { + cfg_set_error(CFG_ERROR_SD_CARD); + return; + } + break; + case SD_CARD_OP_BYTE_SWAP_OFF: + if (sd_set_byte_swap(false)) { + cfg_set_error(CFG_ERROR_SD_CARD); + return; + } + break; default: cfg_set_error(CFG_ERROR_BAD_ARGUMENT); return; @@ -625,6 +639,10 @@ void cfg_process (void) { dd_set_sd_info(args[0], args[1]); break; + case 'w': + args[0] = writeback_pending(); + break; + case 'W': if (cfg_translate_address(&args[0], WRITEBACK_SECTOR_TABLE_SIZE, (SDRAM | BRAM))) { cfg_set_error(CFG_ERROR_BAD_ADDRESS); diff --git a/sw/controller/src/fpga.h b/sw/controller/src/fpga.h index 84521a5..69e9b5e 100644 --- a/sw/controller/src/fpga.h +++ b/sw/controller/src/fpga.h @@ -92,6 +92,7 @@ typedef enum { #define DMA_SCR_STOP (1 << 1) #define DMA_SCR_DIRECTION (1 << 2) #define DMA_SCR_BUSY (1 << 3) +#define DMA_SCR_BYTE_SWAP (1 << 4) #define CFG_SCR_BOOTLOADER_ENABLED (1 << 0) #define CFG_SCR_BOOTLOADER_SKIP (1 << 1) diff --git a/sw/controller/src/hw.c b/sw/controller/src/hw.c index fb6b189..25bdf37 100644 --- a/sw/controller/src/hw.c +++ b/sw/controller/src/hw.c @@ -508,7 +508,7 @@ static void hw_init_crc (void) { static void hw_init_misc (void) { hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0); - hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0); + hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0); hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_OUTPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1); hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0); hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0); diff --git a/sw/controller/src/sd.c b/sw/controller/src/sd.c index f25df99..a07917c 100644 --- a/sw/controller/src/sd.c +++ b/sw/controller/src/sd.c @@ -7,6 +7,7 @@ #define SD_INIT_BUFFER_ADDRESS (0x05002800UL) +#define BYTE_SWAP_ADDRESS_END (0x05000000UL) #define CMD6_ARG_CHECK_HS (0x00FFFFF1UL) #define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL) @@ -67,6 +68,7 @@ struct process { uint8_t csd[16]; uint8_t cid[16]; volatile bool timeout; + bool byte_swap; }; @@ -178,6 +180,9 @@ static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) { if (mode == DAT_READ) { sd_dat |= SD_DAT_START_READ; sd_dma_scr |= DMA_SCR_DIRECTION; + if (p.byte_swap && (address < BYTE_SWAP_ADDRESS_END)) { + sd_dma_scr |= DMA_SCR_BYTE_SWAP; + } } else { sd_dat |= SD_DAT_START_WRITE; } @@ -217,6 +222,8 @@ bool sd_card_init (void) { uint32_t rsp; uint16_t tmp; + p.byte_swap = false; + if (p.card_initialized) { return false; } @@ -336,6 +343,7 @@ bool sd_card_init (void) { void sd_card_deinit (void) { if (p.card_initialized) { p.card_initialized = false; + p.byte_swap = false; sd_set_clock(CLOCK_400KHZ); sd_cmd(0, 0, RSP_NONE, NULL); sd_set_clock(CLOCK_STOP); @@ -348,11 +356,13 @@ bool sd_card_is_inserted (void) { uint32_t sd_card_get_status (void) { uint32_t scr = fpga_reg_get(REG_SD_SCR); + uint32_t byte_swap = p.byte_swap ? 1 : 0; uint32_t clock_mode_50mhz = ((scr & SD_SCR_CLOCK_MODE_MASK) == SD_SCR_CLOCK_MODE_50MHZ) ? 1 : 0; uint32_t card_type_block = p.card_type_block ? 1 : 0; uint32_t card_initialized = p.card_initialized ? 1 : 0; uint32_t card_inserted = (scr & SD_SCR_CARD_INSERTED) ? 1 : 0; return ( + (byte_swap << 4) | (clock_mode_50mhz << 3) | (card_type_block << 2) | (card_initialized << 1) | @@ -371,6 +381,14 @@ bool sd_card_get_info (uint32_t address) { return false; } +bool sd_set_byte_swap (bool enabled) { + if (!p.card_initialized) { + return true; + } + p.byte_swap = enabled; + return false; +} + bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { if (!p.card_initialized || (count == 0)) { return true; @@ -406,6 +424,10 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { return true; } + if (p.byte_swap && ((address % 2) != 0)) { + return true; + } + if (!p.card_type_block) { sector *= SD_SECTOR_SIZE; } @@ -463,11 +485,12 @@ bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t cou void sd_init (void) { p.card_initialized = false; + p.byte_swap = false; sd_set_clock(CLOCK_STOP); } void sd_process (void) { - if (!sd_card_is_inserted()) { + if (p.card_initialized && !sd_card_is_inserted()) { sd_card_deinit(); } } diff --git a/sw/controller/src/sd.h b/sw/controller/src/sd.h index 690905b..9094df4 100644 --- a/sw/controller/src/sd.h +++ b/sw/controller/src/sd.h @@ -17,6 +17,7 @@ void sd_card_deinit (void); bool sd_card_is_inserted (void); uint32_t sd_card_get_status (void); bool sd_card_get_info (uint32_t address); +bool sd_set_byte_swap (bool enabled); bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count); bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count); bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors); diff --git a/sw/controller/src/writeback.c b/sw/controller/src/writeback.c index 39ded8e..8e65f05 100644 --- a/sw/controller/src/writeback.c +++ b/sw/controller/src/writeback.c @@ -124,6 +124,10 @@ void writeback_disable (void) { timer_set(TIMER_ID_WRITEBACK, 0); } +bool writeback_pending (void) { + return p.enabled && p.pending; +} + void writeback_init (void) { p.enabled = false; p.pending = false; diff --git a/sw/controller/src/writeback.h b/sw/controller/src/writeback.h index f1bff21..8e10b45 100644 --- a/sw/controller/src/writeback.h +++ b/sw/controller/src/writeback.h @@ -18,6 +18,7 @@ typedef enum { void writeback_load_sector_table (uint32_t address); void writeback_enable (writeback_mode_t mode); void writeback_disable (void); +bool writeback_pending (void); void writeback_init (void); void writeback_process (void); diff --git a/sw/deployer/src/main.rs b/sw/deployer/src/main.rs index 138b7ef..07af7a6 100644 --- a/sw/deployer/src/main.rs +++ b/sw/deployer/src/main.rs @@ -157,6 +157,10 @@ struct DebugArgs { /// Use EUC-JP encoding for text printing #[arg(long)] euc_jp: bool, + + /// Do not enable save writeback via USB + #[arg(long)] + no_writeback: bool } #[derive(Args)] @@ -612,7 +616,9 @@ fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), .bright_blue() ); } - sc64.set_save_writeback(true)?; + if !args.no_writeback { + sc64.set_save_writeback(true)?; + } println!("{}: Started", "[Debug]".bold()); @@ -639,7 +645,9 @@ fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(), } } - sc64.set_save_writeback(false)?; + if !args.no_writeback { + sc64.set_save_writeback(false)?; + } if args.isv.is_some() { sc64.configure_is_viewer_64(None)?; println!("{}: Stopped listening", "[IS-Viewer 64]".bold());