[SC64][FW][SW] SD card byte swap on reads support (#39)

And other bug fixes related to DMA write mask
This commit is contained in:
Mateusz Faderewski 2023-06-30 01:09:02 +02:00 committed by GitHub
parent 8c7f97b433
commit c4f6a0d555
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 170 additions and 41 deletions

View File

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

View File

@ -5,7 +5,7 @@
## 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 |
@ -23,6 +23,7 @@
| `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 |

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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