From 8696bb9484f8a3c40bf21d41d7502a35b02f405c Mon Sep 17 00:00:00 2001 From: Consani Mattia Date: Fri, 13 Oct 2023 16:02:05 +0200 Subject: [PATCH 01/30] QuadSPI example, not working in Questasim --- sw/applications/example_quadspi_host/main.c | 273 ++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 sw/applications/example_quadspi_host/main.c diff --git a/sw/applications/example_quadspi_host/main.c b/sw/applications/example_quadspi_host/main.c new file mode 100644 index 000000000..9d46dbd49 --- /dev/null +++ b/sw/applications/example_quadspi_host/main.c @@ -0,0 +1,273 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include + +#include "core_v_mini_mcu.h" +#include "csr.h" +#include "hart.h" +#include "handler.h" +#include "soc_ctrl.h" +#include "spi_host.h" +#include "fast_intr_ctrl.h" +#include "fast_intr_ctrl_regs.h" +#include "x-heep.h" + +// W25Q128JW flash commands supported by Questasim flash model +#define W25Q128JW_CMD_RELEASE_POWERDOWN 0xAB +#define W25Q128JW_CMD_POWERDOWN 0xB9 +#define W25Q128JW_CMD_READ 0x03 +#define W25Q128JW_CMD_READ_DUALIO 0xBB +#define W25Q128JW_CMD_READ_QUADIO 0xEB + + +#ifdef TARGET_PYNQ_Z2 + #define USE_SPI_FLASH +#endif + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +// Simple example to check the SPI host peripheral is working. It checks the ram and flash have the same content +#define REVERT_24b_ADDR(addr) ((((uint32_t)(addr) & 0xff0000) >> 16) | ((uint32_t)(addr) & 0xff00) | (((uint32_t)(addr) & 0xff) << 16)) + +#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) + +volatile int8_t spi_intr_flag; +spi_host_t spi_host; +uint32_t flash_data[8]; +uint32_t flash_original[8] = {1}; + +#ifndef USE_SPI_FLASH +void fic_irq_spi(void) +{ + // Disable SPI interrupts + spi_enable_evt_intr(&spi_host, false); + spi_enable_rxwm_intr(&spi_host, false); + spi_intr_flag = 1; +} +#else +void fic_irq_spi_flash(void) +{ + // Disable SPI interrupts + spi_enable_evt_intr(&spi_host, false); + spi_enable_rxwm_intr(&spi_host, false); + spi_intr_flag = 1; +} +#endif + +int main(int argc, char *argv[]) +{ + printf("Let's test the printf"); + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t read_byte_cmd = ((REVERT_24b_ADDR(flash_original) << 8) | W25Q128JW_CMD_READ); // The address bytes sent through the SPI to the Flash are in reverse order + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) // I should never enter here + { +#ifdef USE_SPI_FLASH + PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; +#else + /* + if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different + as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH + */ + uint32_t* ptr_flash = (uint32_t*)FLASH_MEM_START_ADDRESS; + for(int i =0; i < 8 ; i++){ + flash_original[i] = ptr_flash[i]; + } + // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS + read_byte_cmd = ((REVERT_24b_ADDR(0x0) << 8) | W25Q128JW_CMD_READ); // The address bytes sent through the SPI to the Flash are in reverse order + +#endif + + } + + + // spi_host_t spi_host; + #ifndef USE_SPI_FLASH + spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); + #else + spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); + #endif + + uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level fast spi interrupt + #ifndef USE_SPI_FLASH + const uint32_t mask = 1 << 20; + #else + const uint32_t mask = 1 << 21; + #endif + CSR_SET_BITS(CSR_REG_MIE, mask); + spi_intr_flag = 0; + + #ifdef USE_SPI_FLASH + // Select SPI host as SPI output + soc_ctrl_select_spi_host(&soc_ctrl); + #endif + + // Enable SPI host device + spi_set_enable(&spi_host, true); + + // Enable event interrupt + spi_enable_evt_intr(&spi_host, true); + // Enable RX watermark interrupt + spi_enable_rxwm_intr(&spi_host, true); + // Enable SPI output + spi_output_enable(&spi_host, true); + + // Configure SPI clock + // SPI clk freq = 1/2 core clk freq when clk_div = 0 + // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 + uint16_t clk_div = 0; + if(FLASH_CLK_MAX_HZ < core_clk/2){ + clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated + if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 + } + // SPI Configuration + // Configure chip 0 (flash memory) + const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ + .clkdiv = clk_div, + .csnidle = 0xF, + .csntrail = 0xF, + .csnlead = 0xF, + .fullcyc = false, + .cpha = 0, + .cpol = 0 + }); + spi_set_configopts(&spi_host, 0, chip_cfg); + spi_set_csid(&spi_host, 0); + + // Set RX watermark to 8 word + spi_set_rx_watermark(&spi_host, 8); + + uint32_t *flash_data_ptr = flash_data[0]; + + // Power up flash + // ----------------COMMAND---------------- + const uint32_t powerup_byte_cmd = W25Q128JW_CMD_RELEASE_POWERDOWN; + spi_write_word(&spi_host, powerup_byte_cmd); + // Wait for readiness to process commands + spi_wait_for_ready(&spi_host); + + // Load command FIFO with powerup command (1 Byte at single speed) + const uint32_t cmd_powerup = spi_create_command((spi_command_t){ + .len = 3, // Why 4 Bytes? + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_powerup); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + + + volatile uint32_t data_addr = flash_original; + + + // Fast Read Quad I/O + // ----------------COMMAND---------------- + // Fill TX FIFO with TX data (read command + 3B address) + spi_write_word(&spi_host, read_byte_cmd); + // Wait for readiness to process commands + spi_wait_for_ready(&spi_host); + + // Load command FIFO with quadI/O read command + const uint32_t cmd_read = spi_create_command((spi_command_t){ + .len = 3, + .csaat = true, // command not finished + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, cmd_read); + spi_wait_for_ready(&spi_host); + + // //////////////////////////////////////////////////////////////// + + // 8 dummy clocks + const uint32_t cmd_dummy_clocks = spi_create_command((spi_command_t){ + .len = 7, // 8 dummy clocks + .csaat = true, // command not finished + .speed = kSpiSpeedStandard, // Standard speed, I'm not trasmitting + .direction = kSpiDirDummy // Dummy + }); + spi_set_command(&spi_host, cmd_dummy_clocks); + spi_wait_for_ready(&spi_host); + + // //////////////////////////////////////////////////////////////// + + // WHEN I ADD THIS SEGMENT TO THE COMMAND IT FAILS + // Read + const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ + .len = 31, // I read 32 Bytes + .csaat = false, // end of command + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi_host, cmd_read_rx); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + + // Wait transaction is finished (polling register) + // spi_wait_for_rx_watermark(&spi_host); + // or wait for SPI interrupt + PRINTF("Waiting for SPI...\n\r"); + + while( spi_intr_flag == 0 ) { + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + + if( spi_intr_flag == 0 ) + wait_for_interrupt(); + + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + } + + // Enable event interrupt + spi_enable_evt_intr(&spi_host, true); + // Enable RX watermark interrupt + spi_enable_rxwm_intr(&spi_host, true); + + // Read data from SPI RX FIFO + for (int i=0; i<8; i++) { + spi_read_word(&spi_host, &flash_data[i]); + } + + PRINTF("flash vs ram...\n\r"); + + uint32_t errors = 0; + uint32_t* ram_ptr = flash_original; + for (int i=0; i<8; i++) { + if(flash_data[i] != *ram_ptr) { + PRINTF("@%x : %x != %x\n\r", ram_ptr, flash_data[i], *ram_ptr); + errors++; + } + ram_ptr++; + } + + if (errors == 0) { + PRINTF("success!\n\r"); + } else { + PRINTF("failure, %d errors!\n\r", errors); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + +} From c1c4ba3bd6bef77ffc2c7a1c60a537da22dff8c1 Mon Sep 17 00:00:00 2001 From: Consani Mattia Date: Mon, 16 Oct 2023 12:01:01 +0200 Subject: [PATCH 02/30] Add quadIO SPI example --- .../example_spi_host_quadIO/main.c | 304 ++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 sw/applications/example_spi_host_quadIO/main.c diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c new file mode 100644 index 000000000..55972d57d --- /dev/null +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -0,0 +1,304 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * \brief Fast Read Quad I/O SPI Host example + * + * Simple example to check the Fast Read Quad I/O SPI_host functionality. + * It checks that the ram and flash have the same content. + * + * \author Mattia Consani, EPFL +*/ + + +#include +#include +#include + +#include "core_v_mini_mcu.h" +#include "csr.h" +#include "hart.h" +#include "handler.h" +#include "soc_ctrl.h" +#include "spi_host.h" +#include "fast_intr_ctrl.h" +#include "fast_intr_ctrl_regs.h" +#include "x-heep.h" + + +// W25Q128JW flash commands supported by Questasim flash model +// Also FFh and EDh are supported by the simulation model, but not by the phisical flash +#define W25Q128JW_CMD_RELEASE_POWERDOWN 0xab +#define W25Q128JW_CMD_POWERDOWN 0xb9 +#define W25Q128JW_CMD_READ 0x03 +#define W25Q128JW_CMD_READ_DUALIO 0xbb +#define W25Q128JW_CMD_READ_QUADIO 0xeb + + +#ifdef TARGET_PYNQ_Z2 + #define USE_SPI_FLASH +#endif + + +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 1 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + + +#define REVERT_24b_ADDR(addr) ((((uint32_t)(addr) & 0xff0000) >> 16) | ((uint32_t)(addr) & 0xff00) | (((uint32_t)(addr) & 0xff) << 16)) + +#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) + +volatile int8_t spi_intr_flag; +spi_host_t spi_host; +uint32_t flash_data[8]; +uint32_t flash_original[8] = {1}; + +#ifndef USE_SPI_FLASH +void fic_irq_spi(void) +{ + // Disable SPI interrupts + spi_enable_evt_intr(&spi_host, false); + spi_enable_rxwm_intr(&spi_host, false); + spi_intr_flag = 1; +} +#else +void fic_irq_spi_flash(void) +{ + // Disable SPI interrupts + spi_enable_evt_intr(&spi_host, false); + spi_enable_rxwm_intr(&spi_host, false); + spi_intr_flag = 1; +} +#endif + + +int main(int argc, char *argv[]) +{ + PRINTF("Quad I/O SPI Host example\n\r"); + + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + // 24-bit address + Fxh (here FFh) as required by W25Q128JW flash datasheet + uint32_t read_byte_cmd = (REVERT_24b_ADDR(flash_original) | 0xFF << 24); + PRINTF("read_byte_cmd = %x\n\r", read_byte_cmd); + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) + { + #ifdef USE_SPI_FLASH + PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + #else + /* + if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different + as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH + */ + uint32_t* ptr_flash = (uint32_t*)FLASH_MEM_START_ADDRESS; + for(int i =0; i < 8 ; i++){ + flash_original[i] = ptr_flash[i]; + } + // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS + read_byte_cmd = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order + #endif + } + + + // spi_host_t spi_host; + #ifndef USE_SPI_FLASH + spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); + #else + spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); + #endif + + uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level fast spi interrupt + #ifndef USE_SPI_FLASH + const uint32_t mask = 1 << 20; + #else + const uint32_t mask = 1 << 21; + #endif + CSR_SET_BITS(CSR_REG_MIE, mask); + spi_intr_flag = 0; + + #ifdef USE_SPI_FLASH + // Select SPI host as SPI output + soc_ctrl_select_spi_host(&soc_ctrl); + #endif + + + // Enable SPI host device + spi_set_enable(&spi_host, true); + + // Enable event interrupt + spi_enable_evt_intr(&spi_host, true); + // Enable RX watermark interrupt + spi_enable_rxwm_intr(&spi_host, true); + // Enable SPI output + spi_output_enable(&spi_host, true); + + // Configure SPI clock + // SPI clk freq = 1/2 core clk freq when clk_div = 0 + // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 + uint16_t clk_div = 0; + if(FLASH_CLK_MAX_HZ < core_clk/2){ + clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated + if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 + } + // SPI Configuration + // Configure chip 0 (flash memory) + const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ + .clkdiv = clk_div, + .csnidle = 0xF, + .csntrail = 0xF, + .csnlead = 0xF, + .fullcyc = false, + .cpha = 0, + .cpol = 0 + }); + spi_set_configopts(&spi_host, 0, chip_cfg); + spi_set_csid(&spi_host, 0); + + // Set RX watermark to 8 word + spi_set_rx_watermark(&spi_host, 8); + + uint32_t *flash_data_ptr = flash_data[0]; + + + // ----------------COMMAND---------------- + // Power up flash + // ----------------COMMAND---------------- + + // Create segment 1 + const uint32_t powerup_byte_cmd = W25Q128JW_CMD_RELEASE_POWERDOWN; + spi_write_word(&spi_host, powerup_byte_cmd); + + const uint32_t cmd_powerup = spi_create_command((spi_command_t){ + .len = 3, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, cmd_powerup); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + + + volatile uint32_t data_addr = flash_original; + + + // ----------------COMMAND---------------- + // Fast Read Quad I/O + // ----------------COMMAND---------------- + + // Create segment 1 + uint32_t cmd_read_quadIO = W25Q128JW_CMD_READ_QUADIO; + spi_write_word(&spi_host, cmd_read_quadIO); + spi_wait_for_ready(&spi_host); + + const uint32_t cmd_read = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, cmd_read); + spi_wait_for_ready(&spi_host); + + + // Create segment 2 + spi_write_word(&spi_host, read_byte_cmd); + spi_wait_for_ready(&spi_host); + + const uint32_t cmd_address = spi_create_command((spi_command_t){ + .len = 3, // 3 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, cmd_address); + spi_wait_for_ready(&spi_host); + + + // Create segment 3 + const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ + .len = 7, // 8 Byte [WARNING]: W25Q128JW flash needs 4 + .csaat = true, // Command not finished + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirDummy // Dummy + }); + spi_set_command(&spi_host, dummy_clocks_cmd); + spi_wait_for_ready(&spi_host); + + + // Create segment 4 + const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ + .len = 31, // 32 Byte + .csaat = false, // End command + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi_host, cmd_read_rx); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + + + + // Wait transaction is finished (polling register) + // spi_wait_for_rx_watermark(&spi_host); + // or wait for SPI interrupt + PRINTF("Waiting for SPI...\n\r"); + + while( spi_intr_flag == 0 ) { + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + + if( spi_intr_flag == 0 ) + wait_for_interrupt(); + + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + } + + // Enable event interrupt + spi_enable_evt_intr(&spi_host, true); + // Enable RX watermark interrupt + spi_enable_rxwm_intr(&spi_host, true); + + // Read data from SPI RX FIFO + for (int i=0; i<8; i++) { + spi_read_word(&spi_host, &flash_data[i]); + } + + PRINTF("flash vs ram...\n\r"); + + uint32_t errors = 0; + uint32_t* ram_ptr = flash_original; + for (int i=0; i<8; i++) { + if(flash_data[i] != *ram_ptr) { + PRINTF("@%x : %x != %x\n\r", ram_ptr, flash_data[i], *ram_ptr); + errors++; + } + ram_ptr++; + } + + if (errors == 0) { + PRINTF("success!\n\r"); + } else { + PRINTF("failure, %d errors!\n\r", errors); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + +} From 0dad5dad2d0626bf2e0895eb64205a95aa0a4889 Mon Sep 17 00:00:00 2001 From: Consani Mattia Date: Mon, 16 Oct 2023 14:35:54 +0200 Subject: [PATCH 03/30] Remove old quadspi example --- sw/applications/example_quadspi_host/main.c | 273 -------------------- 1 file changed, 273 deletions(-) delete mode 100644 sw/applications/example_quadspi_host/main.c diff --git a/sw/applications/example_quadspi_host/main.c b/sw/applications/example_quadspi_host/main.c deleted file mode 100644 index 9d46dbd49..000000000 --- a/sw/applications/example_quadspi_host/main.c +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include - -#include "core_v_mini_mcu.h" -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "soc_ctrl.h" -#include "spi_host.h" -#include "fast_intr_ctrl.h" -#include "fast_intr_ctrl_regs.h" -#include "x-heep.h" - -// W25Q128JW flash commands supported by Questasim flash model -#define W25Q128JW_CMD_RELEASE_POWERDOWN 0xAB -#define W25Q128JW_CMD_POWERDOWN 0xB9 -#define W25Q128JW_CMD_READ 0x03 -#define W25Q128JW_CMD_READ_DUALIO 0xBB -#define W25Q128JW_CMD_READ_QUADIO 0xEB - - -#ifdef TARGET_PYNQ_Z2 - #define USE_SPI_FLASH -#endif - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -// Simple example to check the SPI host peripheral is working. It checks the ram and flash have the same content -#define REVERT_24b_ADDR(addr) ((((uint32_t)(addr) & 0xff0000) >> 16) | ((uint32_t)(addr) & 0xff00) | (((uint32_t)(addr) & 0xff) << 16)) - -#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) - -volatile int8_t spi_intr_flag; -spi_host_t spi_host; -uint32_t flash_data[8]; -uint32_t flash_original[8] = {1}; - -#ifndef USE_SPI_FLASH -void fic_irq_spi(void) -{ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#else -void fic_irq_spi_flash(void) -{ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#endif - -int main(int argc, char *argv[]) -{ - printf("Let's test the printf"); - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - uint32_t read_byte_cmd = ((REVERT_24b_ADDR(flash_original) << 8) | W25Q128JW_CMD_READ); // The address bytes sent through the SPI to the Flash are in reverse order - - if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) // I should never enter here - { -#ifdef USE_SPI_FLASH - PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); - return EXIT_SUCCESS; -#else - /* - if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different - as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH - */ - uint32_t* ptr_flash = (uint32_t*)FLASH_MEM_START_ADDRESS; - for(int i =0; i < 8 ; i++){ - flash_original[i] = ptr_flash[i]; - } - // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS - read_byte_cmd = ((REVERT_24b_ADDR(0x0) << 8) | W25Q128JW_CMD_READ); // The address bytes sent through the SPI to the Flash are in reverse order - -#endif - - } - - - // spi_host_t spi_host; - #ifndef USE_SPI_FLASH - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); - #else - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); - #endif - - uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - // Set mie.MEIE bit to one to enable machine-level fast spi interrupt - #ifndef USE_SPI_FLASH - const uint32_t mask = 1 << 20; - #else - const uint32_t mask = 1 << 21; - #endif - CSR_SET_BITS(CSR_REG_MIE, mask); - spi_intr_flag = 0; - - #ifdef USE_SPI_FLASH - // Select SPI host as SPI output - soc_ctrl_select_spi_host(&soc_ctrl); - #endif - - // Enable SPI host device - spi_set_enable(&spi_host, true); - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); - // Enable SPI output - spi_output_enable(&spi_host, true); - - // Configure SPI clock - // SPI clk freq = 1/2 core clk freq when clk_div = 0 - // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 - uint16_t clk_div = 0; - if(FLASH_CLK_MAX_HZ < core_clk/2){ - clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated - if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 - } - // SPI Configuration - // Configure chip 0 (flash memory) - const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ - .clkdiv = clk_div, - .csnidle = 0xF, - .csntrail = 0xF, - .csnlead = 0xF, - .fullcyc = false, - .cpha = 0, - .cpol = 0 - }); - spi_set_configopts(&spi_host, 0, chip_cfg); - spi_set_csid(&spi_host, 0); - - // Set RX watermark to 8 word - spi_set_rx_watermark(&spi_host, 8); - - uint32_t *flash_data_ptr = flash_data[0]; - - // Power up flash - // ----------------COMMAND---------------- - const uint32_t powerup_byte_cmd = W25Q128JW_CMD_RELEASE_POWERDOWN; - spi_write_word(&spi_host, powerup_byte_cmd); - // Wait for readiness to process commands - spi_wait_for_ready(&spi_host); - - // Load command FIFO with powerup command (1 Byte at single speed) - const uint32_t cmd_powerup = spi_create_command((spi_command_t){ - .len = 3, // Why 4 Bytes? - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_powerup); - spi_wait_for_ready(&spi_host); - // ----------------END COMMAND---------------- - - - volatile uint32_t data_addr = flash_original; - - - // Fast Read Quad I/O - // ----------------COMMAND---------------- - // Fill TX FIFO with TX data (read command + 3B address) - spi_write_word(&spi_host, read_byte_cmd); - // Wait for readiness to process commands - spi_wait_for_ready(&spi_host); - - // Load command FIFO with quadI/O read command - const uint32_t cmd_read = spi_create_command((spi_command_t){ - .len = 3, - .csaat = true, // command not finished - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirTxOnly // Write only - }); - spi_set_command(&spi_host, cmd_read); - spi_wait_for_ready(&spi_host); - - // //////////////////////////////////////////////////////////////// - - // 8 dummy clocks - const uint32_t cmd_dummy_clocks = spi_create_command((spi_command_t){ - .len = 7, // 8 dummy clocks - .csaat = true, // command not finished - .speed = kSpiSpeedStandard, // Standard speed, I'm not trasmitting - .direction = kSpiDirDummy // Dummy - }); - spi_set_command(&spi_host, cmd_dummy_clocks); - spi_wait_for_ready(&spi_host); - - // //////////////////////////////////////////////////////////////// - - // WHEN I ADD THIS SEGMENT TO THE COMMAND IT FAILS - // Read - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ - .len = 31, // I read 32 Bytes - .csaat = false, // end of command - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirRxOnly // Read only - }); - spi_set_command(&spi_host, cmd_read_rx); - spi_wait_for_ready(&spi_host); - // ----------------END COMMAND---------------- - - // Wait transaction is finished (polling register) - // spi_wait_for_rx_watermark(&spi_host); - // or wait for SPI interrupt - PRINTF("Waiting for SPI...\n\r"); - - while( spi_intr_flag == 0 ) { - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - - if( spi_intr_flag == 0 ) - wait_for_interrupt(); - - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - } - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); - - // Read data from SPI RX FIFO - for (int i=0; i<8; i++) { - spi_read_word(&spi_host, &flash_data[i]); - } - - PRINTF("flash vs ram...\n\r"); - - uint32_t errors = 0; - uint32_t* ram_ptr = flash_original; - for (int i=0; i<8; i++) { - if(flash_data[i] != *ram_ptr) { - PRINTF("@%x : %x != %x\n\r", ram_ptr, flash_data[i], *ram_ptr); - errors++; - } - ram_ptr++; - } - - if (errors == 0) { - PRINTF("success!\n\r"); - } else { - PRINTF("failure, %d errors!\n\r", errors); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; - -} From 6f5235ac49409670f7ff3cef9c41b326504d3a0f Mon Sep 17 00:00:00 2001 From: Consani Mattia Date: Mon, 16 Oct 2023 15:07:38 +0200 Subject: [PATCH 04/30] Code cleanup, fix to also support fisical flash --- .../example_spi_host_quadIO/main.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index 55972d57d..98f865bbe 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -42,7 +42,7 @@ #define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 1 +#define PRINTF_IN_SIM 0 #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) @@ -88,16 +88,15 @@ int main(int argc, char *argv[]) soc_ctrl_t soc_ctrl; soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - // 24-bit address + Fxh (here FFh) as required by W25Q128JW flash datasheet - uint32_t read_byte_cmd = (REVERT_24b_ADDR(flash_original) | 0xFF << 24); - PRINTF("read_byte_cmd = %x\n\r", read_byte_cmd); - + // [WARNING]: this part was not updated to support quad SPI if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { #ifdef USE_SPI_FLASH PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); return EXIT_SUCCESS; #else + PRINTF("This application is not supporting quad SPI in memory mapped mode (yet)\n"); + return EXIT_FAILURE; /* if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH @@ -107,7 +106,7 @@ int main(int argc, char *argv[]) flash_original[i] = ptr_flash[i]; } // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS - read_byte_cmd = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order + uint32_t read_byte_cmd_spimemio = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order #endif } @@ -186,7 +185,7 @@ int main(int argc, char *argv[]) spi_write_word(&spi_host, powerup_byte_cmd); const uint32_t cmd_powerup = spi_create_command((spi_command_t){ - .len = 3, // 1 Byte + .len = 0, // 1 Byte .csaat = false, // End command .speed = kSpiSpeedStandard, // Single speed .direction = kSpiDirTxOnly // Write only @@ -219,6 +218,8 @@ int main(int argc, char *argv[]) // Create segment 2 + uint32_t read_byte_cmd = (REVERT_24b_ADDR(flash_original) | 0xFF << 24); // Fxh (here FFh) required by W25Q128JW + PRINTF("read_byte_cmd = %x\n\r", read_byte_cmd); spi_write_word(&spi_host, read_byte_cmd); spi_wait_for_ready(&spi_host); @@ -234,7 +235,11 @@ int main(int argc, char *argv[]) // Create segment 3 const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ - .len = 7, // 8 Byte [WARNING]: W25Q128JW flash needs 4 + #ifdef TARGET_PYNQ_Z2 + .len = 3, // W25Q128JW flash needs 4 dummy cycles + #else + .len = 7, // SPI flash simulation model needs 8 dummy cycles + #endif .csaat = true, // Command not finished .speed = kSpiSpeedQuad, // Quad speed .direction = kSpiDirDummy // Dummy From 800e97c9312b55cde4aeb39df317e4d86a06734a Mon Sep 17 00:00:00 2001 From: Consani Mattia Date: Wed, 18 Oct 2023 18:29:09 +0200 Subject: [PATCH 05/30] QE bit set, small changes --- .../example_spi_host_quadIO/main.c | 95 ++++++++++++++++++- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index 98f865bbe..c2aaf6524 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -34,6 +34,9 @@ #define W25Q128JW_CMD_READ 0x03 #define W25Q128JW_CMD_READ_DUALIO 0xbb #define W25Q128JW_CMD_READ_QUADIO 0xeb +// Not supported in Verilog flash model +#define W25Q128JW_CMD_READ_REG2 0x35 +#define W25Q128JW_CMD_WRITE_REG2 0x31 #ifdef TARGET_PYNQ_Z2 @@ -60,7 +63,9 @@ volatile int8_t spi_intr_flag; spi_host_t spi_host; uint32_t flash_data[8]; -uint32_t flash_original[8] = {1}; + +// This is the vector that the spi_host is reading from the flash +uint32_t flash_original[8] = {0x76543210,0xfedcba98,0x579a6f90,0x657d5bee,0x758ee41f,0x01234567,0xfedbca98,0x89abcdef}; #ifndef USE_SPI_FLASH void fic_irq_spi(void) @@ -88,6 +93,7 @@ int main(int argc, char *argv[]) soc_ctrl_t soc_ctrl; soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + // [WARNING]: this part was not updated to support quad SPI if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { @@ -109,6 +115,7 @@ int main(int argc, char *argv[]) uint32_t read_byte_cmd_spimemio = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order #endif } + // [WARNING STOP] ----------------------------- // spi_host_t spi_host; @@ -183,6 +190,7 @@ int main(int argc, char *argv[]) // Create segment 1 const uint32_t powerup_byte_cmd = W25Q128JW_CMD_RELEASE_POWERDOWN; spi_write_word(&spi_host, powerup_byte_cmd); + spi_wait_for_ready(&spi_host); const uint32_t cmd_powerup = spi_create_command((spi_command_t){ .len = 0, // 1 Byte @@ -195,6 +203,83 @@ int main(int argc, char *argv[]) // ----------------END COMMAND---------------- + // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed + // The Verilog flash do not model this behavior and no actions are required + // #ifdef TARGET_PYNQ_Z2 + + // ----------------COMMAND---------------- + // Read Status Register 2 + // ----------------COMMAND---------------- + + // Create segment 1 + const uint32_t reg2_read_cmd = W25Q128JW_CMD_READ_REG2; + spi_write_word(&spi_host, reg2_read_cmd); + spi_wait_for_ready(&spi_host); + + const uint32_t reg2_read_1 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, reg2_read_1); + spi_wait_for_ready(&spi_host); + + + // Create segment 2 + const uint32_t reg2_read_2 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Standard speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi_host, reg2_read_2); + spi_wait_for_ready(&spi_host); + + uint32_t reg2_data; // The actual register is 8 bit, but the SPI host reads 32 bit + spi_read_word(&spi_host, ®2_data); + // ----------------END COMMAND---------------- + + + // Set bit in position 1 (QE bit) + reg2_data |= 0x2; + + + // ----------------COMMAND---------------- + // Write Status Register 2 + // ----------------COMMAND---------------- + + // Create segment 1 + const uint32_t reg2_read_cmd = W25Q128JW_CMD_WRITE_REG2; + spi_write_word(&spi_host, reg2_read_cmd); + spi_wait_for_ready(&spi_host); + + const uint32_t reg2_write_1 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, reg2_write_1); + spi_wait_for_ready(&spi_host); + + + // Create segment 2 + spi_write_word(&spi_host, reg2_data); + spi_wait_for_ready(&spi_host); + + const uint32_t reg2_write_2 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Standard speed + .direction = kSpiDirRxOnly // Write only + }); + spi_set_command(&spi_host, reg2_write_2); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + // #endif + + volatile uint32_t data_addr = flash_original; @@ -215,11 +300,12 @@ int main(int argc, char *argv[]) }); spi_set_command(&spi_host, cmd_read); spi_wait_for_ready(&spi_host); + PRINTF("cmd_read = 0x%x\n\r", cmd_read); // Create segment 2 - uint32_t read_byte_cmd = (REVERT_24b_ADDR(flash_original) | 0xFF << 24); // Fxh (here FFh) required by W25Q128JW - PRINTF("read_byte_cmd = %x\n\r", read_byte_cmd); + uint32_t read_byte_cmd = (REVERT_24b_ADDR(flash_original) | (0xFF << 24)); // Fxh (here FFh) required by W25Q128JW + PRINTF("read_byte_cmd = %u\n\r", read_byte_cmd); spi_write_word(&spi_host, read_byte_cmd); spi_wait_for_ready(&spi_host); @@ -231,6 +317,7 @@ int main(int argc, char *argv[]) }); spi_set_command(&spi_host, cmd_address); spi_wait_for_ready(&spi_host); + PRINTF("cmd_address = 0x%x\n\r", cmd_address); // Create segment 3 @@ -246,6 +333,7 @@ int main(int argc, char *argv[]) }); spi_set_command(&spi_host, dummy_clocks_cmd); spi_wait_for_ready(&spi_host); + PRINTF("dummy_clocks_cmd = 0x%x\n\r", dummy_clocks_cmd); // Create segment 4 @@ -257,6 +345,7 @@ int main(int argc, char *argv[]) }); spi_set_command(&spi_host, cmd_read_rx); spi_wait_for_ready(&spi_host); + PRINTF("cmd_read_rx = 0x%x\n\r", cmd_read_rx); // ----------------END COMMAND---------------- From de7901011af480c0dce4362147e66d0ad3c13571 Mon Sep 17 00:00:00 2001 From: Consani Mattia Date: Wed, 18 Oct 2023 18:30:50 +0200 Subject: [PATCH 06/30] small fix --- sw/applications/example_spi_host_quadIO/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index c2aaf6524..0cf9f9fff 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -250,8 +250,8 @@ int main(int argc, char *argv[]) // ----------------COMMAND---------------- // Create segment 1 - const uint32_t reg2_read_cmd = W25Q128JW_CMD_WRITE_REG2; - spi_write_word(&spi_host, reg2_read_cmd); + const uint32_t reg2_write_cmd = W25Q128JW_CMD_WRITE_REG2; + spi_write_word(&spi_host, reg2_write_cmd); spi_wait_for_ready(&spi_host); const uint32_t reg2_write_1 = spi_create_command((spi_command_t){ From b2e1a5b8ffe78b87647e50047a28f69121652233 Mon Sep 17 00:00:00 2001 From: Consani Mattia Date: Wed, 18 Oct 2023 18:33:06 +0200 Subject: [PATCH 07/30] small fix --- sw/applications/example_spi_host_quadIO/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index 0cf9f9fff..9ce086702 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -205,7 +205,7 @@ int main(int argc, char *argv[]) // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed // The Verilog flash do not model this behavior and no actions are required - // #ifdef TARGET_PYNQ_Z2 + #ifdef TARGET_PYNQ_Z2 // ----------------COMMAND---------------- // Read Status Register 2 @@ -277,7 +277,7 @@ int main(int argc, char *argv[]) spi_set_command(&spi_host, reg2_write_2); spi_wait_for_ready(&spi_host); // ----------------END COMMAND---------------- - // #endif + #endif volatile uint32_t data_addr = flash_original; From 2d021b0fdc15b3c521743137ee88ac368ae76e85 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Sun, 22 Oct 2023 11:54:51 +0200 Subject: [PATCH 08/30] Write Enable, status reg2 check --- .../example_spi_host_quadIO/main.c | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index 9ce086702..1b3fcd605 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -37,6 +37,7 @@ // Not supported in Verilog flash model #define W25Q128JW_CMD_READ_REG2 0x35 #define W25Q128JW_CMD_WRITE_REG2 0x31 +#define W25Q128JW_CMD_WRITE_ENABLE 0x06 #ifdef TARGET_PYNQ_Z2 @@ -207,10 +208,13 @@ int main(int argc, char *argv[]) // The Verilog flash do not model this behavior and no actions are required #ifdef TARGET_PYNQ_Z2 + PRINTF("FPGA target: setting QE bit...\n\r"); + spi_set_rx_watermark(&spi_host,1); + // ----------------COMMAND---------------- // Read Status Register 2 // ----------------COMMAND---------------- - + // Create segment 1 const uint32_t reg2_read_cmd = W25Q128JW_CMD_READ_REG2; spi_write_word(&spi_host, reg2_read_cmd); @@ -235,20 +239,42 @@ int main(int argc, char *argv[]) }); spi_set_command(&spi_host, reg2_read_2); spi_wait_for_ready(&spi_host); - - uint32_t reg2_data; // The actual register is 8 bit, but the SPI host reads 32 bit + spi_wait_for_rx_watermark(&spi_host); + + // the partial word will be zero-padded and inserted into the RX FIFO once the segment is completed + uint32_t reg2_data; // The actual register is 8 bit, but the SPI host gives a full word spi_read_word(&spi_host, ®2_data); // ----------------END COMMAND---------------- // Set bit in position 1 (QE bit) + PRINTF("before reg2_data = 0x%x\n\r", reg2_data); reg2_data |= 0x2; + PRINTF("after reg2_data = 0x%x\n\r", reg2_data); + uint8_t reg2_data_8bit = reg2_data & 0xFF; // Explicit cast to 8 bit + PRINTF("after reg2_data_8bit = 0x%x\n\r", reg2_data_8bit); // ----------------COMMAND---------------- - // Write Status Register 2 + // Write Enable - WEL (Write Enable Latch) set // ----------------COMMAND---------------- + // Create segment 1 + const uint32_t write_enable_cmd = W25Q128JW_CMD_WRITE_ENABLE; + spi_write_word(&spi_host, write_enable_cmd); + const uint32_t cmd_write_en = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_write_en); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + + // ----------------COMMAND---------------- + // Write Status Register 2 + // ----------------COMMAND---------------- // Create segment 1 const uint32_t reg2_write_cmd = W25Q128JW_CMD_WRITE_REG2; spi_write_word(&spi_host, reg2_write_cmd); @@ -265,7 +291,7 @@ int main(int argc, char *argv[]) // Create segment 2 - spi_write_word(&spi_host, reg2_data); + spi_write_word(&spi_host, 0x02); spi_wait_for_ready(&spi_host); const uint32_t reg2_write_2 = spi_create_command((spi_command_t){ @@ -277,8 +303,22 @@ int main(int argc, char *argv[]) spi_set_command(&spi_host, reg2_write_2); spi_wait_for_ready(&spi_host); // ----------------END COMMAND---------------- - #endif + // Check back the register + spi_write_word(&spi_host, reg2_read_cmd); + spi_wait_for_ready(&spi_host); + spi_set_command(&spi_host, reg2_read_1); + spi_wait_for_ready(&spi_host); + spi_set_command(&spi_host, reg2_read_2); + spi_wait_for_ready(&spi_host); + spi_wait_for_rx_watermark(&spi_host); + uint32_t reg2_data_check = 0x00; + spi_read_word(&spi_host, ®2_data_check); + PRINTF("reg2_data_check = 0x%x\n\r", reg2_data_check); + + spi_set_rx_watermark(&spi_host,8); + #endif + volatile uint32_t data_addr = flash_original; From bc2227a06296835bf8400878564c06cc8eca759d Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Fri, 3 Nov 2023 16:48:07 +0100 Subject: [PATCH 09/30] add standard write functionality --- hw/vendor/yosyshq_picorv32/picosoc/spiflash.v | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v index e0eef9f71..ed2c9b3ff 100644 --- a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v +++ b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v @@ -26,7 +26,7 @@ // updates output signals 1ns after the SPI clock edge. // // Supported commands: -// AB, B9, FF, 03, BB, EB, ED +// AB, B9, FF, 03, BB, EB, ED, 06, 02 // // Well written SPI flash data sheets: // Cypress S25FL064L http://www.cypress.com/file/316661/download @@ -61,6 +61,8 @@ module spiflash ( reg spi_io_vld; reg powered_up = 0; + reg write_enable = 0; + reg write_enable_reset = 0; localparam [3:0] mode_spi = 1; localparam [3:0] mode_dspi_rd = 2; @@ -129,6 +131,9 @@ module spiflash ( if (spi_cmd == 8'h ff) xip_cmd = 0; + + if (spi_cmd == 8'h 06) + write_enable = 1; end if (powered_up && spi_cmd == 'h 03) begin @@ -147,6 +152,25 @@ module spiflash ( end end + if (powered_up && write_enable && spi_cmd == 'h 02) begin + if (bytecount == 1) + write_enable_reset = 1; + + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) + spi_addr[7:0] = buffer; + + if (bytecount >= 5 && bytecount <= 260) begin + memory[spi_addr] = buffer; + spi_addr = spi_addr + 1; + end + end + if (powered_up && spi_cmd == 'h bb) begin if (bytecount == 1) mode = mode_dspi_rd; @@ -274,6 +298,10 @@ module spiflash ( $display(""); $fflush; end + if (write_enable_reset) begin + write_enable = 0; + write_enable_reset = 0; + end buffer = 0; bitcount = 0; bytecount = 0; From 8b1ab85b297798e63c4ed489b361b4bfbc281d25 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Fri, 3 Nov 2023 16:49:27 +0100 Subject: [PATCH 10/30] add basic write example --- sw/applications/example_spi_host_write/main.c | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 sw/applications/example_spi_host_write/main.c diff --git a/sw/applications/example_spi_host_write/main.c b/sw/applications/example_spi_host_write/main.c new file mode 100644 index 000000000..455bfb97c --- /dev/null +++ b/sw/applications/example_spi_host_write/main.c @@ -0,0 +1,280 @@ +/** + * @file main.c + * @brief Example application for the SPI host module - write to the SPI Flash +*/ + +#include +#include +#include + +#include "core_v_mini_mcu.h" +#include "csr.h" +#include "hart.h" +#include "handler.h" +#include "rv_plic.h" +#include "rv_plic_regs.h" +#include "soc_ctrl.h" +#include "spi_host.h" +#include "dma.h" +#include "fast_intr_ctrl.h" +#include "fast_intr_ctrl_regs.h" +#include "x-heep.h" + +#ifdef TARGET_PYNQ_Z2 + #define USE_SPI_FLASH +#endif + +#define REVERT_24b_ADDR(addr) ((((uint32_t)addr & 0xff0000) >> 16) | ((uint32_t)addr & 0xff00) | (((uint32_t)addr & 0xff) << 16)) +#define FLASH_ADDR 0x00008500 // 256B data alignment +#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 1 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +int8_t spi_intr_flag; +spi_host_t spi_host; + +// Test buffers +uint32_t flash_data_towrite[16] = { + 0x76543210,0xfedcba98,0x579a6f90,0x657d5bee,0x758ee41f,0x01234567,0xfedbca98, + 0x89abcdef,0x679852fe,0xff8252bb,0x763b4521,0x6875adaa,0x09ac65bb,0x666ba334, + 0x44556677,0x0000ba98 +}; +uint32_t flash_data_toread[16] = {}; + +#ifndef USE_SPI_FLASH +void fic_irq_spi(void) +{ + // Disable SPI interrupts + spi_enable_evt_intr(&spi_host, false); + spi_enable_rxwm_intr(&spi_host, false); + spi_intr_flag = 1; +} +#else +void fic_irq_spi_flash(void) +{ + // Disable SPI interrupts + // PRINTF("&"); + spi_enable_evt_intr(&spi_host, false); + spi_enable_rxwm_intr(&spi_host, false); + spi_intr_flag = 1; +} +#endif //USE_SPI_FLASH + + + +static inline __attribute__((always_inline)) void spi_config() { +/* +* SPI CONFIGURATIONS +*/ +#ifndef USE_SPI_FLASH + spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); +#else + spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); +#endif //USE_SPI_FLASH + + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level fast spi interrupt + + +#ifndef USE_SPI_FLASH + const uint32_t mask = 1 << 20; +#else + const uint32_t mask = 1 << 21; +#endif + CSR_SET_BITS(CSR_REG_MIE, mask); + spi_intr_flag = 0; + +#ifdef USE_SPI_FLASH + // Select SPI host as SPI output + soc_ctrl_select_spi_host(&soc_ctrl); +#endif // USE_SPI_FLASH + + + CSR_SET_BITS(CSR_REG_MIE, mask); + + // Enable SPI host device + spi_set_enable(&spi_host, true); + // Enable SPI output + spi_output_enable(&spi_host, true); + + // Configure SPI clock + // SPI clk freq = 1/2 core clk freq when clk_div = 0 + // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 + uint16_t clk_div = 0; + if(FLASH_CLK_MAX_HZ < core_clk/2){ + clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated + if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 + } + // SPI Configuration + // Configure chip 0 (flash memory) + const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ + .clkdiv = clk_div, + .csnidle = 0xF, + .csntrail = 0xF, + .csnlead = 0xF, + .fullcyc = false, + .cpha = 0, + .cpol = 0 + }); + spi_set_configopts(&spi_host, 0, chip_cfg); + spi_set_csid(&spi_host, 0); + + // Reset + const uint32_t reset_cmd = 0xFFFFFFFF; // ??? + spi_write_word(&spi_host, reset_cmd); + const uint32_t cmd_reset = spi_create_command((spi_command_t){ + .len = 3, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_reset); + spi_wait_for_ready(&spi_host); + spi_set_rx_watermark(&spi_host,1); + + // Power up flash + const uint32_t powerup_byte_cmd = 0xab; + spi_write_word(&spi_host, powerup_byte_cmd); + const uint32_t cmd_powerup = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_powerup); + spi_wait_for_ready(&spi_host); + + // Write enable + const uint32_t write_enable_cmd = 0x06; + spi_write_word(&spi_host, write_enable_cmd); + const uint32_t cmd_write_en = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_write_en); + spi_wait_for_ready(&spi_host); +} + + +int main(int argc, char *argv[]) { + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + #ifdef USE_SPI_FLASH + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) + { + PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + } + #endif + + /** + * Configure the SPI<->flash connection parameters and the SPI host. + * Set the write enale bit. + */ + spi_config(); + + // Write command - Program Page + address + const uint32_t write_byte_cmd = ((REVERT_24b_ADDR(FLASH_ADDR) << 8) | 0x02); + spi_write_word(&spi_host, write_byte_cmd); + const uint32_t cmd_write = spi_create_command((spi_command_t){ + .len = 3, + .csaat = true, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_write); + spi_wait_for_ready(&spi_host); + + // Write test buffer to SPI TX FIFO + for (int i = 0; i < 16; i++) { + spi_write_word(&spi_host, flash_data_towrite[i]); + } + const uint32_t cmd_write1 = spi_create_command((spi_command_t){ + .len = 16*4 - 1, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_write1); + spi_wait_for_ready(&spi_host); + + // Wait for all the fifo to be drained + spi_wait_for_tx_empty(&spi_host); + #ifndef TARGET_SIM + // wait_also_flash + #endif // TARGET_SIM + + // Read back the data + // Fill TX FIFO with TX data (read command + 3B address) + const uint32_t read_byte_cmd = ((REVERT_24b_ADDR(FLASH_ADDR) << 8) | 0x03); + spi_write_word(&spi_host, read_byte_cmd); + // Wait for readiness to process commands + spi_wait_for_ready(&spi_host); + // Load command FIFO with read command (1 Byte at single speed) + const uint32_t cmd_read = spi_create_command((spi_command_t){ + .len = 3, + .csaat = true, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_read); + spi_wait_for_ready(&spi_host); + + spi_set_rx_watermark(&spi_host, 16); + const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ + .len = 16*4 - 1, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirRxOnly + }); + spi_set_command(&spi_host, cmd_read_rx); + spi_wait_for_ready(&spi_host); + + // Wait till all the data is received + spi_wait_for_rx_watermark(&spi_host); + + // Read data from SPI RX FIFO + for (int i=0; i<16; i++) { + spi_read_word(&spi_host, &flash_data_toread[i]); + } + + PRINTF("flash vs ram...\n\r"); + + uint32_t errors = 0; + uint32_t* ram_ptr = flash_data_towrite; + for (int i=0; i<16; i++) { + if(flash_data_toread[i] != *ram_ptr) { + PRINTF("@%x : %x != %x\n\r", ram_ptr, flash_data_toread[i], *ram_ptr); + errors++; + } + ram_ptr++; + } + + if (errors == 0) { + PRINTF("success!\n\r"); + } else { + PRINTF("failure, %d errors!\n\r", errors); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} \ No newline at end of file From 2a73f8f392d1e5d7462209effde1a846ecd2e847 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Sat, 4 Nov 2023 11:28:32 +0100 Subject: [PATCH 11/30] add wait for flash function --- sw/applications/example_spi_host_write/main.c | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/sw/applications/example_spi_host_write/main.c b/sw/applications/example_spi_host_write/main.c index 455bfb97c..e0c0bd8eb 100644 --- a/sw/applications/example_spi_host_write/main.c +++ b/sw/applications/example_spi_host_write/main.c @@ -173,6 +173,36 @@ static inline __attribute__((always_inline)) void spi_config() { spi_wait_for_ready(&spi_host); } +static inline __attribute__((always_inline)) void spi_wait_4_resp() +{ + // Check status register status waiting for ready + bool flash_busy = true; + uint8_t flash_resp[4] = {0xff,0xff,0xff,0xff}; + while(flash_busy){ + uint32_t flash_cmd = 0x00000005; // [CMD] Read status register + spi_write_word(&spi_host, flash_cmd); // Push TX buffer + uint32_t spi_status_cmd = spi_create_command((spi_command_t){ + .len = 0, + .csaat = true, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + uint32_t spi_status_read_cmd = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirRxOnly + }); + spi_set_command(&spi_host, spi_status_cmd); + spi_wait_for_ready(&spi_host); + spi_set_command(&spi_host, spi_status_read_cmd); + spi_wait_for_ready(&spi_host); + spi_wait_for_rx_watermark(&spi_host); + spi_read_word(&spi_host, &flash_resp[0]); + if ((flash_resp[0] & 0x01) == 0) flash_busy = false; + } +} + int main(int argc, char *argv[]) { soc_ctrl_t soc_ctrl; @@ -220,7 +250,7 @@ int main(int argc, char *argv[]) { // Wait for all the fifo to be drained spi_wait_for_tx_empty(&spi_host); #ifndef TARGET_SIM - // wait_also_flash + spi_wait_4_resp() #endif // TARGET_SIM // Read back the data From 44eb1f6fee5504bd001ea7659001646d50c2437b Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Sat, 4 Nov 2023 11:47:18 +0100 Subject: [PATCH 12/30] add quad page program, not tested --- hw/vendor/yosyshq_picorv32/picosoc/spiflash.v | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v index ed2c9b3ff..4a0338a4b 100644 --- a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v +++ b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v @@ -221,6 +221,27 @@ module spiflash ( end end + if (powered_up && write_enable && spi_cmd == 'h 32) begin + if (bytecount == 1) + write_enable_reset = 1; + + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) begin + spi_addr[7:0] = buffer; + mode = mode_qspi_rd; + end + + if (bytecount >= 5 && bytecount <= 260) begin + memory[spi_addr] = buffer; + spi_addr = spi_addr + 1; + end + end + if (powered_up && spi_cmd == 'h ed) begin if (bytecount == 1) next_mode = mode_qspi_ddr_rd; From 3e5bd52a47eb5fdff0deaa1bf99539e2a65edfb6 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Tue, 7 Nov 2023 17:45:08 +0100 Subject: [PATCH 13/30] Delate non relevant example --- .../example_spi_host_quadIO/main.c | 438 ------------------ 1 file changed, 438 deletions(-) delete mode 100644 sw/applications/example_spi_host_quadIO/main.c diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c deleted file mode 100644 index 1b3fcd605..000000000 --- a/sw/applications/example_spi_host_quadIO/main.c +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -/** - * \brief Fast Read Quad I/O SPI Host example - * - * Simple example to check the Fast Read Quad I/O SPI_host functionality. - * It checks that the ram and flash have the same content. - * - * \author Mattia Consani, EPFL -*/ - - -#include -#include -#include - -#include "core_v_mini_mcu.h" -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "soc_ctrl.h" -#include "spi_host.h" -#include "fast_intr_ctrl.h" -#include "fast_intr_ctrl_regs.h" -#include "x-heep.h" - - -// W25Q128JW flash commands supported by Questasim flash model -// Also FFh and EDh are supported by the simulation model, but not by the phisical flash -#define W25Q128JW_CMD_RELEASE_POWERDOWN 0xab -#define W25Q128JW_CMD_POWERDOWN 0xb9 -#define W25Q128JW_CMD_READ 0x03 -#define W25Q128JW_CMD_READ_DUALIO 0xbb -#define W25Q128JW_CMD_READ_QUADIO 0xeb -// Not supported in Verilog flash model -#define W25Q128JW_CMD_READ_REG2 0x35 -#define W25Q128JW_CMD_WRITE_REG2 0x31 -#define W25Q128JW_CMD_WRITE_ENABLE 0x06 - - -#ifdef TARGET_PYNQ_Z2 - #define USE_SPI_FLASH -#endif - - -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - - -#define REVERT_24b_ADDR(addr) ((((uint32_t)(addr) & 0xff0000) >> 16) | ((uint32_t)(addr) & 0xff00) | (((uint32_t)(addr) & 0xff) << 16)) - -#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) - -volatile int8_t spi_intr_flag; -spi_host_t spi_host; -uint32_t flash_data[8]; - -// This is the vector that the spi_host is reading from the flash -uint32_t flash_original[8] = {0x76543210,0xfedcba98,0x579a6f90,0x657d5bee,0x758ee41f,0x01234567,0xfedbca98,0x89abcdef}; - -#ifndef USE_SPI_FLASH -void fic_irq_spi(void) -{ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#else -void fic_irq_spi_flash(void) -{ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#endif - - -int main(int argc, char *argv[]) -{ - PRINTF("Quad I/O SPI Host example\n\r"); - - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - - - // [WARNING]: this part was not updated to support quad SPI - if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) - { - #ifdef USE_SPI_FLASH - PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); - return EXIT_SUCCESS; - #else - PRINTF("This application is not supporting quad SPI in memory mapped mode (yet)\n"); - return EXIT_FAILURE; - /* - if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different - as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH - */ - uint32_t* ptr_flash = (uint32_t*)FLASH_MEM_START_ADDRESS; - for(int i =0; i < 8 ; i++){ - flash_original[i] = ptr_flash[i]; - } - // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS - uint32_t read_byte_cmd_spimemio = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order - #endif - } - // [WARNING STOP] ----------------------------- - - - // spi_host_t spi_host; - #ifndef USE_SPI_FLASH - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); - #else - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); - #endif - - uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - // Set mie.MEIE bit to one to enable machine-level fast spi interrupt - #ifndef USE_SPI_FLASH - const uint32_t mask = 1 << 20; - #else - const uint32_t mask = 1 << 21; - #endif - CSR_SET_BITS(CSR_REG_MIE, mask); - spi_intr_flag = 0; - - #ifdef USE_SPI_FLASH - // Select SPI host as SPI output - soc_ctrl_select_spi_host(&soc_ctrl); - #endif - - - // Enable SPI host device - spi_set_enable(&spi_host, true); - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); - // Enable SPI output - spi_output_enable(&spi_host, true); - - // Configure SPI clock - // SPI clk freq = 1/2 core clk freq when clk_div = 0 - // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 - uint16_t clk_div = 0; - if(FLASH_CLK_MAX_HZ < core_clk/2){ - clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated - if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 - } - // SPI Configuration - // Configure chip 0 (flash memory) - const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ - .clkdiv = clk_div, - .csnidle = 0xF, - .csntrail = 0xF, - .csnlead = 0xF, - .fullcyc = false, - .cpha = 0, - .cpol = 0 - }); - spi_set_configopts(&spi_host, 0, chip_cfg); - spi_set_csid(&spi_host, 0); - - // Set RX watermark to 8 word - spi_set_rx_watermark(&spi_host, 8); - - uint32_t *flash_data_ptr = flash_data[0]; - - - // ----------------COMMAND---------------- - // Power up flash - // ----------------COMMAND---------------- - - // Create segment 1 - const uint32_t powerup_byte_cmd = W25Q128JW_CMD_RELEASE_POWERDOWN; - spi_write_word(&spi_host, powerup_byte_cmd); - spi_wait_for_ready(&spi_host); - - const uint32_t cmd_powerup = spi_create_command((spi_command_t){ - .len = 0, // 1 Byte - .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only - }); - spi_set_command(&spi_host, cmd_powerup); - spi_wait_for_ready(&spi_host); - // ----------------END COMMAND---------------- - - - // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed - // The Verilog flash do not model this behavior and no actions are required - #ifdef TARGET_PYNQ_Z2 - - PRINTF("FPGA target: setting QE bit...\n\r"); - spi_set_rx_watermark(&spi_host,1); - - // ----------------COMMAND---------------- - // Read Status Register 2 - // ----------------COMMAND---------------- - - // Create segment 1 - const uint32_t reg2_read_cmd = W25Q128JW_CMD_READ_REG2; - spi_write_word(&spi_host, reg2_read_cmd); - spi_wait_for_ready(&spi_host); - - const uint32_t reg2_read_1 = spi_create_command((spi_command_t){ - .len = 0, // 1 Byte - .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only - }); - spi_set_command(&spi_host, reg2_read_1); - spi_wait_for_ready(&spi_host); - - - // Create segment 2 - const uint32_t reg2_read_2 = spi_create_command((spi_command_t){ - .len = 0, // 1 Byte - .csaat = false, // End command - .speed = kSpiSpeedStandard, // Standard speed - .direction = kSpiDirRxOnly // Read only - }); - spi_set_command(&spi_host, reg2_read_2); - spi_wait_for_ready(&spi_host); - spi_wait_for_rx_watermark(&spi_host); - - // the partial word will be zero-padded and inserted into the RX FIFO once the segment is completed - uint32_t reg2_data; // The actual register is 8 bit, but the SPI host gives a full word - spi_read_word(&spi_host, ®2_data); - // ----------------END COMMAND---------------- - - - // Set bit in position 1 (QE bit) - PRINTF("before reg2_data = 0x%x\n\r", reg2_data); - reg2_data |= 0x2; - PRINTF("after reg2_data = 0x%x\n\r", reg2_data); - uint8_t reg2_data_8bit = reg2_data & 0xFF; // Explicit cast to 8 bit - PRINTF("after reg2_data_8bit = 0x%x\n\r", reg2_data_8bit); - - - // ----------------COMMAND---------------- - // Write Enable - WEL (Write Enable Latch) set - // ----------------COMMAND---------------- - // Create segment 1 - const uint32_t write_enable_cmd = W25Q128JW_CMD_WRITE_ENABLE; - spi_write_word(&spi_host, write_enable_cmd); - const uint32_t cmd_write_en = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_write_en); - spi_wait_for_ready(&spi_host); - // ----------------END COMMAND---------------- - - - // ----------------COMMAND---------------- - // Write Status Register 2 - // ----------------COMMAND---------------- - // Create segment 1 - const uint32_t reg2_write_cmd = W25Q128JW_CMD_WRITE_REG2; - spi_write_word(&spi_host, reg2_write_cmd); - spi_wait_for_ready(&spi_host); - - const uint32_t reg2_write_1 = spi_create_command((spi_command_t){ - .len = 0, // 1 Byte - .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only - }); - spi_set_command(&spi_host, reg2_write_1); - spi_wait_for_ready(&spi_host); - - - // Create segment 2 - spi_write_word(&spi_host, 0x02); - spi_wait_for_ready(&spi_host); - - const uint32_t reg2_write_2 = spi_create_command((spi_command_t){ - .len = 0, // 1 Byte - .csaat = false, // End command - .speed = kSpiSpeedStandard, // Standard speed - .direction = kSpiDirRxOnly // Write only - }); - spi_set_command(&spi_host, reg2_write_2); - spi_wait_for_ready(&spi_host); - // ----------------END COMMAND---------------- - - // Check back the register - spi_write_word(&spi_host, reg2_read_cmd); - spi_wait_for_ready(&spi_host); - spi_set_command(&spi_host, reg2_read_1); - spi_wait_for_ready(&spi_host); - spi_set_command(&spi_host, reg2_read_2); - spi_wait_for_ready(&spi_host); - spi_wait_for_rx_watermark(&spi_host); - uint32_t reg2_data_check = 0x00; - spi_read_word(&spi_host, ®2_data_check); - PRINTF("reg2_data_check = 0x%x\n\r", reg2_data_check); - - spi_set_rx_watermark(&spi_host,8); - #endif - - - volatile uint32_t data_addr = flash_original; - - - // ----------------COMMAND---------------- - // Fast Read Quad I/O - // ----------------COMMAND---------------- - - // Create segment 1 - uint32_t cmd_read_quadIO = W25Q128JW_CMD_READ_QUADIO; - spi_write_word(&spi_host, cmd_read_quadIO); - spi_wait_for_ready(&spi_host); - - const uint32_t cmd_read = spi_create_command((spi_command_t){ - .len = 0, // 1 Byte - .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only - }); - spi_set_command(&spi_host, cmd_read); - spi_wait_for_ready(&spi_host); - PRINTF("cmd_read = 0x%x\n\r", cmd_read); - - - // Create segment 2 - uint32_t read_byte_cmd = (REVERT_24b_ADDR(flash_original) | (0xFF << 24)); // Fxh (here FFh) required by W25Q128JW - PRINTF("read_byte_cmd = %u\n\r", read_byte_cmd); - spi_write_word(&spi_host, read_byte_cmd); - spi_wait_for_ready(&spi_host); - - const uint32_t cmd_address = spi_create_command((spi_command_t){ - .len = 3, // 3 Byte - .csaat = true, // Command not finished - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirTxOnly // Write only - }); - spi_set_command(&spi_host, cmd_address); - spi_wait_for_ready(&spi_host); - PRINTF("cmd_address = 0x%x\n\r", cmd_address); - - - // Create segment 3 - const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ - #ifdef TARGET_PYNQ_Z2 - .len = 3, // W25Q128JW flash needs 4 dummy cycles - #else - .len = 7, // SPI flash simulation model needs 8 dummy cycles - #endif - .csaat = true, // Command not finished - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirDummy // Dummy - }); - spi_set_command(&spi_host, dummy_clocks_cmd); - spi_wait_for_ready(&spi_host); - PRINTF("dummy_clocks_cmd = 0x%x\n\r", dummy_clocks_cmd); - - - // Create segment 4 - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ - .len = 31, // 32 Byte - .csaat = false, // End command - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirRxOnly // Read only - }); - spi_set_command(&spi_host, cmd_read_rx); - spi_wait_for_ready(&spi_host); - PRINTF("cmd_read_rx = 0x%x\n\r", cmd_read_rx); - // ----------------END COMMAND---------------- - - - - // Wait transaction is finished (polling register) - // spi_wait_for_rx_watermark(&spi_host); - // or wait for SPI interrupt - PRINTF("Waiting for SPI...\n\r"); - - while( spi_intr_flag == 0 ) { - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - - if( spi_intr_flag == 0 ) - wait_for_interrupt(); - - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - } - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); - - // Read data from SPI RX FIFO - for (int i=0; i<8; i++) { - spi_read_word(&spi_host, &flash_data[i]); - } - - PRINTF("flash vs ram...\n\r"); - - uint32_t errors = 0; - uint32_t* ram_ptr = flash_original; - for (int i=0; i<8; i++) { - if(flash_data[i] != *ram_ptr) { - PRINTF("@%x : %x != %x\n\r", ram_ptr, flash_data[i], *ram_ptr); - errors++; - } - ram_ptr++; - } - - if (errors == 0) { - PRINTF("success!\n\r"); - } else { - PRINTF("failure, %d errors!\n\r", errors); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; - -} From 643dc267dd96d3f51aac899f26672f74413b439a Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Thu, 9 Nov 2023 11:41:31 +0100 Subject: [PATCH 14/30] Tested on FPGA --- .../example_spi_host_quadIO/main.c | 62 ++++++------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index 1b3fcd605..75e8332e5 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -67,6 +67,7 @@ uint32_t flash_data[8]; // This is the vector that the spi_host is reading from the flash uint32_t flash_original[8] = {0x76543210,0xfedcba98,0x579a6f90,0x657d5bee,0x758ee41f,0x01234567,0xfedbca98,0x89abcdef}; +// uint32_t flash_original[8] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; #ifndef USE_SPI_FLASH void fic_irq_spi(void) @@ -128,31 +129,25 @@ int main(int argc, char *argv[]) uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - // Set mie.MEIE bit to one to enable machine-level fast spi interrupt - #ifndef USE_SPI_FLASH - const uint32_t mask = 1 << 20; - #else - const uint32_t mask = 1 << 21; - #endif - CSR_SET_BITS(CSR_REG_MIE, mask); - spi_intr_flag = 0; - #ifdef USE_SPI_FLASH - // Select SPI host as SPI output - soc_ctrl_select_spi_host(&soc_ctrl); + // Select SPI host as SPI output + soc_ctrl_select_spi_host(&soc_ctrl); #endif + // Reset + const uint32_t reset_cmd = 0xFFFFFFFF; + spi_write_word(&spi_host, reset_cmd); + const uint32_t cmd_reset = spi_create_command((spi_command_t){ + .len = 3, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_reset); + spi_wait_for_ready(&spi_host); // Enable SPI host device spi_set_enable(&spi_host, true); - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); // Enable SPI output spi_output_enable(&spi_host, true); @@ -181,9 +176,6 @@ int main(int argc, char *argv[]) // Set RX watermark to 8 word spi_set_rx_watermark(&spi_host, 8); - uint32_t *flash_data_ptr = flash_data[0]; - - // ----------------COMMAND---------------- // Power up flash // ----------------COMMAND---------------- @@ -203,6 +195,7 @@ int main(int argc, char *argv[]) spi_wait_for_ready(&spi_host); // ----------------END COMMAND---------------- + /* // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed // The Verilog flash do not model this behavior and no actions are required @@ -316,11 +309,12 @@ int main(int argc, char *argv[]) spi_read_word(&spi_host, ®2_data_check); PRINTF("reg2_data_check = 0x%x\n\r", reg2_data_check); - spi_set_rx_watermark(&spi_host,8); #endif + */ - volatile uint32_t data_addr = flash_original; + // Set RX watermark to 8 word (32 bytes) + spi_set_rx_watermark(&spi_host,8); // ----------------COMMAND---------------- @@ -391,23 +385,8 @@ int main(int argc, char *argv[]) // Wait transaction is finished (polling register) - // spi_wait_for_rx_watermark(&spi_host); - // or wait for SPI interrupt PRINTF("Waiting for SPI...\n\r"); - - while( spi_intr_flag == 0 ) { - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - - if( spi_intr_flag == 0 ) - wait_for_interrupt(); - - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - } - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); + spi_wait_for_rx_watermark(&spi_host); // Read data from SPI RX FIFO for (int i=0; i<8; i++) { @@ -419,8 +398,8 @@ int main(int argc, char *argv[]) uint32_t errors = 0; uint32_t* ram_ptr = flash_original; for (int i=0; i<8; i++) { + PRINTF("@%x : %x == %x(ref)\n\r", ram_ptr, flash_data[i], *ram_ptr); if(flash_data[i] != *ram_ptr) { - PRINTF("@%x : %x != %x\n\r", ram_ptr, flash_data[i], *ram_ptr); errors++; } ram_ptr++; @@ -434,5 +413,4 @@ int main(int argc, char *argv[]) } return EXIT_SUCCESS; - } From e585f5ffae74d3f64134545b0f9eb18c8cce032f Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Thu, 9 Nov 2023 11:42:11 +0100 Subject: [PATCH 15/30] small fix --- sw/applications/example_spi_host_quadIO/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index 75e8332e5..e89e5060d 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -398,9 +398,11 @@ int main(int argc, char *argv[]) uint32_t errors = 0; uint32_t* ram_ptr = flash_original; for (int i=0; i<8; i++) { - PRINTF("@%x : %x == %x(ref)\n\r", ram_ptr, flash_data[i], *ram_ptr); if(flash_data[i] != *ram_ptr) { + PRINTF("@%x : %x != %x(ref)\n\r", ram_ptr, flash_data[i], *ram_ptr); errors++; + } else { + PRINTF("@%x : %x == %x(ref)\n\r", ram_ptr, flash_data[i], *ram_ptr); } ram_ptr++; } From 2fdd12bdad208d1f405c363a4d35c7f0089f5643 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Thu, 23 Nov 2023 14:47:38 +0100 Subject: [PATCH 16/30] Disable QE bit before programming --- sw/vendor/yosyshq_icestorm/iceprog/iceprog.c | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c index 38e308f82..8c4c7177d 100644 --- a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c +++ b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c @@ -480,6 +480,34 @@ static void flash_enable_quad() fprintf(stderr, "SR2: %08x\n", data[1]); } +static void flash_disable_quad() +{ + fprintf(stderr, "Disabling Quad operation...\n"); + + // Allow write + flash_write_enable(); + + // Write Status Register 2 <- 0x00 + uint8_t data[2] = { FC_WSR2, 0x00 }; + flash_chip_select(); + mpsse_xfer_spi(data, 2); + flash_chip_deselect(); + + flash_wait(); + + // Read Status Register 1 + data[0] = FC_RSR2; + + flash_chip_select(); + mpsse_xfer_spi(data, 2); + flash_chip_deselect(); + + if ((data[1] & 0x02) != 0x00) + fprintf(stderr, "failed to set QE=0, SR2 now equal to 0x%02x (expected 0x%02x)\n", data[1], data[1] | 0x00); + + fprintf(stderr, "SR2: %08x\n", data[1]); +} + // --------------------------------------------------------- // iceprog implementation // --------------------------------------------------------- @@ -949,6 +977,8 @@ int main(int argc, char **argv) flash_reset(); flash_power_up(); + flash_disable_quad(); + flash_read_id(); From 0af5c4354134e66399fecc21ee3abdfadc04057e Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Thu, 23 Nov 2023 16:49:25 +0100 Subject: [PATCH 17/30] Debug QE bit set --- sw/applications/example_spi_host_quadIO/main.c | 7 ++----- sw/vendor/yosyshq_icestorm/iceprog/iceprog.c | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index e89e5060d..c0c3901ae 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -195,7 +195,7 @@ int main(int argc, char *argv[]) spi_wait_for_ready(&spi_host); // ----------------END COMMAND---------------- - /* + // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed // The Verilog flash do not model this behavior and no actions are required @@ -244,8 +244,6 @@ int main(int argc, char *argv[]) PRINTF("before reg2_data = 0x%x\n\r", reg2_data); reg2_data |= 0x2; PRINTF("after reg2_data = 0x%x\n\r", reg2_data); - uint8_t reg2_data_8bit = reg2_data & 0xFF; // Explicit cast to 8 bit - PRINTF("after reg2_data_8bit = 0x%x\n\r", reg2_data_8bit); // ----------------COMMAND---------------- @@ -284,7 +282,7 @@ int main(int argc, char *argv[]) // Create segment 2 - spi_write_word(&spi_host, 0x02); + spi_write_word(&spi_host, reg2_data); spi_wait_for_ready(&spi_host); const uint32_t reg2_write_2 = spi_create_command((spi_command_t){ @@ -311,7 +309,6 @@ int main(int argc, char *argv[]) #endif - */ // Set RX watermark to 8 word (32 bytes) spi_set_rx_watermark(&spi_host,8); diff --git a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c index 8c4c7177d..30e53e167 100644 --- a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c +++ b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c @@ -978,6 +978,7 @@ int main(int argc, char **argv) flash_power_up(); flash_disable_quad(); + flash_enable_quad(); flash_read_id(); From 08e35168a836f36be4b7c0957714833faaa1545a Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Fri, 24 Nov 2023 15:57:20 +0100 Subject: [PATCH 18/30] Fix QE bit set bug --- sw/applications/example_spi_host_quadIO/main.c | 2 +- sw/vendor/yosyshq_icestorm/iceprog/iceprog.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sw/applications/example_spi_host_quadIO/main.c b/sw/applications/example_spi_host_quadIO/main.c index c0c3901ae..c45fd0206 100644 --- a/sw/applications/example_spi_host_quadIO/main.c +++ b/sw/applications/example_spi_host_quadIO/main.c @@ -289,7 +289,7 @@ int main(int argc, char *argv[]) .len = 0, // 1 Byte .csaat = false, // End command .speed = kSpiSpeedStandard, // Standard speed - .direction = kSpiDirRxOnly // Write only + .direction = kSpiDirTxOnly // Write only }); spi_set_command(&spi_host, reg2_write_2); spi_wait_for_ready(&spi_host); diff --git a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c index 30e53e167..8c4c7177d 100644 --- a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c +++ b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c @@ -978,7 +978,6 @@ int main(int argc, char **argv) flash_power_up(); flash_disable_quad(); - flash_enable_quad(); flash_read_id(); From d47946a4bbe8860e24ca0163d967f691c7eeebf3 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Fri, 24 Nov 2023 16:56:33 +0100 Subject: [PATCH 19/30] boh --- ...er-iceprog-custom-for-heep-with-gpio.patch | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch index b325b7bc3..692ff570b 100644 --- a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch +++ b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch @@ -1,8 +1,43 @@ diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c -index 8ee6443..38e308f 100644 +index 8ee6443..8c4c717 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c -@@ -506,6 +506,7 @@ static void help(const char *progname) +@@ -480,6 +480,34 @@ static void flash_enable_quad() + fprintf(stderr, "SR2: %08x\n", data[1]); + } + ++static void flash_disable_quad() ++{ ++ fprintf(stderr, "Disabling Quad operation...\n"); ++ ++ // Allow write ++ flash_write_enable(); ++ ++ // Write Status Register 2 <- 0x00 ++ uint8_t data[2] = { FC_WSR2, 0x00 }; ++ flash_chip_select(); ++ mpsse_xfer_spi(data, 2); ++ flash_chip_deselect(); ++ ++ flash_wait(); ++ ++ // Read Status Register 1 ++ data[0] = FC_RSR2; ++ ++ flash_chip_select(); ++ mpsse_xfer_spi(data, 2); ++ flash_chip_deselect(); ++ ++ if ((data[1] & 0x02) != 0x00) ++ fprintf(stderr, "failed to set QE=0, SR2 now equal to 0x%02x (expected 0x%02x)\n", data[1], data[1] | 0x00); ++ ++ fprintf(stderr, "SR2: %08x\n", data[1]); ++} ++ + // --------------------------------------------------------- + // iceprog implementation + // --------------------------------------------------------- +@@ -506,6 +534,7 @@ static void help(const char *progname) fprintf(stderr, " -s slow SPI (50 kHz instead of 6 MHz)\n"); fprintf(stderr, " -k keep flash in powered up state (i.e. skip power down command)\n"); fprintf(stderr, " -v verbose output\n"); @@ -10,7 +45,7 @@ index 8ee6443..38e308f 100644 fprintf(stderr, " -i [4,32,64] select erase block size [default: 64k]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Mode of operation:\n"); -@@ -587,6 +588,8 @@ int main(int argc, char **argv) +@@ -587,6 +616,8 @@ int main(int argc, char **argv) const char *devstr = NULL; int ifnum = 0; @@ -19,7 +54,7 @@ index 8ee6443..38e308f 100644 #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); -@@ -600,7 +603,7 @@ int main(int argc, char **argv) +@@ -600,7 +631,7 @@ int main(int argc, char **argv) /* Decode command line parameters */ int opt; char *endptr; @@ -28,7 +63,7 @@ index 8ee6443..38e308f 100644 switch (opt) { case 'd': /* device string */ devstr = optarg; -@@ -696,6 +699,9 @@ int main(int argc, char **argv) +@@ -696,6 +727,9 @@ int main(int argc, char **argv) case 'v': /* provide verbose output */ verbose = true; break; @@ -38,7 +73,16 @@ index 8ee6443..38e308f 100644 case 's': /* use slow SPI clock */ slow_clock = true; break; -@@ -997,22 +1003,59 @@ int main(int argc, char **argv) +@@ -943,6 +977,8 @@ int main(int argc, char **argv) + flash_reset(); + flash_power_up(); + ++ flash_disable_quad(); ++ + flash_read_id(); + + +@@ -997,22 +1033,59 @@ int main(int argc, char **argv) } } @@ -107,7 +151,7 @@ index 8ee6443..38e308f 100644 fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); -@@ -1026,6 +1069,12 @@ int main(int argc, char **argv) +@@ -1026,6 +1099,12 @@ int main(int argc, char **argv) // --------------------------------------------------------- if (read_mode) { @@ -120,7 +164,7 @@ index 8ee6443..38e308f 100644 fprintf(stderr, "reading..\n"); for (int addr = 0; addr < read_size; addr += 256) { uint8_t buffer[256]; -@@ -1037,23 +1086,40 @@ int main(int argc, char **argv) +@@ -1037,23 +1116,40 @@ int main(int argc, char **argv) fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); } else if (!erase_mode && !disable_verify) { @@ -171,31 +215,3 @@ index 8ee6443..38e308f 100644 } -diff --git a/iceprog/mpsse.c b/iceprog/mpsse.c -index 80d462f..71c9ee6 100644 ---- a/iceprog/mpsse.c -+++ b/iceprog/mpsse.c -@@ -309,6 +309,12 @@ void mpsse_init(int ifnum, const char *devstr, bool slow_clock) - - mpsse_ftdic_open = true; - -+ /* Reset the BITMODE. Set all pins to output. */ -+ if (ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_RESET) < 0) { -+ fprintf(stderr, "Failed to set BITMODE_RESET on iCE FTDI USB device.\n"); -+ mpsse_error(2); -+ } -+ - if (ftdi_usb_reset(&mpsse_ftdic)) { - fprintf(stderr, "Failed to reset iCE FTDI USB device.\n"); - mpsse_error(2); -@@ -358,6 +364,9 @@ void mpsse_close(void) - { - ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency); - ftdi_disable_bitbang(&mpsse_ftdic); -+ -+ ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_BITBANG); -+ - ftdi_usb_close(&mpsse_ftdic); - ftdi_deinit(&mpsse_ftdic); - } -\ No newline at end of file From e15865c2abcb97ce195dff9140708b79465c4f24 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Fri, 24 Nov 2023 16:58:17 +0100 Subject: [PATCH 20/30] Revert "boh" This reverts commit d47946a4bbe8860e24ca0163d967f691c7eeebf3. --- ...er-iceprog-custom-for-heep-with-gpio.patch | 88 ++++++++----------- 1 file changed, 36 insertions(+), 52 deletions(-) diff --git a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch index 692ff570b..b325b7bc3 100644 --- a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch +++ b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch @@ -1,43 +1,8 @@ diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c -index 8ee6443..8c4c717 100644 +index 8ee6443..38e308f 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c -@@ -480,6 +480,34 @@ static void flash_enable_quad() - fprintf(stderr, "SR2: %08x\n", data[1]); - } - -+static void flash_disable_quad() -+{ -+ fprintf(stderr, "Disabling Quad operation...\n"); -+ -+ // Allow write -+ flash_write_enable(); -+ -+ // Write Status Register 2 <- 0x00 -+ uint8_t data[2] = { FC_WSR2, 0x00 }; -+ flash_chip_select(); -+ mpsse_xfer_spi(data, 2); -+ flash_chip_deselect(); -+ -+ flash_wait(); -+ -+ // Read Status Register 1 -+ data[0] = FC_RSR2; -+ -+ flash_chip_select(); -+ mpsse_xfer_spi(data, 2); -+ flash_chip_deselect(); -+ -+ if ((data[1] & 0x02) != 0x00) -+ fprintf(stderr, "failed to set QE=0, SR2 now equal to 0x%02x (expected 0x%02x)\n", data[1], data[1] | 0x00); -+ -+ fprintf(stderr, "SR2: %08x\n", data[1]); -+} -+ - // --------------------------------------------------------- - // iceprog implementation - // --------------------------------------------------------- -@@ -506,6 +534,7 @@ static void help(const char *progname) +@@ -506,6 +506,7 @@ static void help(const char *progname) fprintf(stderr, " -s slow SPI (50 kHz instead of 6 MHz)\n"); fprintf(stderr, " -k keep flash in powered up state (i.e. skip power down command)\n"); fprintf(stderr, " -v verbose output\n"); @@ -45,7 +10,7 @@ index 8ee6443..8c4c717 100644 fprintf(stderr, " -i [4,32,64] select erase block size [default: 64k]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Mode of operation:\n"); -@@ -587,6 +616,8 @@ int main(int argc, char **argv) +@@ -587,6 +588,8 @@ int main(int argc, char **argv) const char *devstr = NULL; int ifnum = 0; @@ -54,7 +19,7 @@ index 8ee6443..8c4c717 100644 #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); -@@ -600,7 +631,7 @@ int main(int argc, char **argv) +@@ -600,7 +603,7 @@ int main(int argc, char **argv) /* Decode command line parameters */ int opt; char *endptr; @@ -63,7 +28,7 @@ index 8ee6443..8c4c717 100644 switch (opt) { case 'd': /* device string */ devstr = optarg; -@@ -696,6 +727,9 @@ int main(int argc, char **argv) +@@ -696,6 +699,9 @@ int main(int argc, char **argv) case 'v': /* provide verbose output */ verbose = true; break; @@ -73,16 +38,7 @@ index 8ee6443..8c4c717 100644 case 's': /* use slow SPI clock */ slow_clock = true; break; -@@ -943,6 +977,8 @@ int main(int argc, char **argv) - flash_reset(); - flash_power_up(); - -+ flash_disable_quad(); -+ - flash_read_id(); - - -@@ -997,22 +1033,59 @@ int main(int argc, char **argv) +@@ -997,22 +1003,59 @@ int main(int argc, char **argv) } } @@ -151,7 +107,7 @@ index 8ee6443..8c4c717 100644 fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); -@@ -1026,6 +1099,12 @@ int main(int argc, char **argv) +@@ -1026,6 +1069,12 @@ int main(int argc, char **argv) // --------------------------------------------------------- if (read_mode) { @@ -164,7 +120,7 @@ index 8ee6443..8c4c717 100644 fprintf(stderr, "reading..\n"); for (int addr = 0; addr < read_size; addr += 256) { uint8_t buffer[256]; -@@ -1037,23 +1116,40 @@ int main(int argc, char **argv) +@@ -1037,23 +1086,40 @@ int main(int argc, char **argv) fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); } else if (!erase_mode && !disable_verify) { @@ -215,3 +171,31 @@ index 8ee6443..8c4c717 100644 } +diff --git a/iceprog/mpsse.c b/iceprog/mpsse.c +index 80d462f..71c9ee6 100644 +--- a/iceprog/mpsse.c ++++ b/iceprog/mpsse.c +@@ -309,6 +309,12 @@ void mpsse_init(int ifnum, const char *devstr, bool slow_clock) + + mpsse_ftdic_open = true; + ++ /* Reset the BITMODE. Set all pins to output. */ ++ if (ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_RESET) < 0) { ++ fprintf(stderr, "Failed to set BITMODE_RESET on iCE FTDI USB device.\n"); ++ mpsse_error(2); ++ } ++ + if (ftdi_usb_reset(&mpsse_ftdic)) { + fprintf(stderr, "Failed to reset iCE FTDI USB device.\n"); + mpsse_error(2); +@@ -358,6 +364,9 @@ void mpsse_close(void) + { + ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency); + ftdi_disable_bitbang(&mpsse_ftdic); ++ ++ ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_BITBANG); ++ + ftdi_usb_close(&mpsse_ftdic); + ftdi_deinit(&mpsse_ftdic); + } +\ No newline at end of file From a3e7cfdae9e2b5630fe00d5903e3d4181eb5b12d Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Fri, 24 Nov 2023 17:04:17 +0100 Subject: [PATCH 21/30] boh2 --- ...er-iceprog-custom-for-heep-with-gpio.patch | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch index b325b7bc3..692ff570b 100644 --- a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch +++ b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch @@ -1,8 +1,43 @@ diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c -index 8ee6443..38e308f 100644 +index 8ee6443..8c4c717 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c -@@ -506,6 +506,7 @@ static void help(const char *progname) +@@ -480,6 +480,34 @@ static void flash_enable_quad() + fprintf(stderr, "SR2: %08x\n", data[1]); + } + ++static void flash_disable_quad() ++{ ++ fprintf(stderr, "Disabling Quad operation...\n"); ++ ++ // Allow write ++ flash_write_enable(); ++ ++ // Write Status Register 2 <- 0x00 ++ uint8_t data[2] = { FC_WSR2, 0x00 }; ++ flash_chip_select(); ++ mpsse_xfer_spi(data, 2); ++ flash_chip_deselect(); ++ ++ flash_wait(); ++ ++ // Read Status Register 1 ++ data[0] = FC_RSR2; ++ ++ flash_chip_select(); ++ mpsse_xfer_spi(data, 2); ++ flash_chip_deselect(); ++ ++ if ((data[1] & 0x02) != 0x00) ++ fprintf(stderr, "failed to set QE=0, SR2 now equal to 0x%02x (expected 0x%02x)\n", data[1], data[1] | 0x00); ++ ++ fprintf(stderr, "SR2: %08x\n", data[1]); ++} ++ + // --------------------------------------------------------- + // iceprog implementation + // --------------------------------------------------------- +@@ -506,6 +534,7 @@ static void help(const char *progname) fprintf(stderr, " -s slow SPI (50 kHz instead of 6 MHz)\n"); fprintf(stderr, " -k keep flash in powered up state (i.e. skip power down command)\n"); fprintf(stderr, " -v verbose output\n"); @@ -10,7 +45,7 @@ index 8ee6443..38e308f 100644 fprintf(stderr, " -i [4,32,64] select erase block size [default: 64k]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Mode of operation:\n"); -@@ -587,6 +588,8 @@ int main(int argc, char **argv) +@@ -587,6 +616,8 @@ int main(int argc, char **argv) const char *devstr = NULL; int ifnum = 0; @@ -19,7 +54,7 @@ index 8ee6443..38e308f 100644 #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); -@@ -600,7 +603,7 @@ int main(int argc, char **argv) +@@ -600,7 +631,7 @@ int main(int argc, char **argv) /* Decode command line parameters */ int opt; char *endptr; @@ -28,7 +63,7 @@ index 8ee6443..38e308f 100644 switch (opt) { case 'd': /* device string */ devstr = optarg; -@@ -696,6 +699,9 @@ int main(int argc, char **argv) +@@ -696,6 +727,9 @@ int main(int argc, char **argv) case 'v': /* provide verbose output */ verbose = true; break; @@ -38,7 +73,16 @@ index 8ee6443..38e308f 100644 case 's': /* use slow SPI clock */ slow_clock = true; break; -@@ -997,22 +1003,59 @@ int main(int argc, char **argv) +@@ -943,6 +977,8 @@ int main(int argc, char **argv) + flash_reset(); + flash_power_up(); + ++ flash_disable_quad(); ++ + flash_read_id(); + + +@@ -997,22 +1033,59 @@ int main(int argc, char **argv) } } @@ -107,7 +151,7 @@ index 8ee6443..38e308f 100644 fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); -@@ -1026,6 +1069,12 @@ int main(int argc, char **argv) +@@ -1026,6 +1099,12 @@ int main(int argc, char **argv) // --------------------------------------------------------- if (read_mode) { @@ -120,7 +164,7 @@ index 8ee6443..38e308f 100644 fprintf(stderr, "reading..\n"); for (int addr = 0; addr < read_size; addr += 256) { uint8_t buffer[256]; -@@ -1037,23 +1086,40 @@ int main(int argc, char **argv) +@@ -1037,23 +1116,40 @@ int main(int argc, char **argv) fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); } else if (!erase_mode && !disable_verify) { @@ -171,31 +215,3 @@ index 8ee6443..38e308f 100644 } -diff --git a/iceprog/mpsse.c b/iceprog/mpsse.c -index 80d462f..71c9ee6 100644 ---- a/iceprog/mpsse.c -+++ b/iceprog/mpsse.c -@@ -309,6 +309,12 @@ void mpsse_init(int ifnum, const char *devstr, bool slow_clock) - - mpsse_ftdic_open = true; - -+ /* Reset the BITMODE. Set all pins to output. */ -+ if (ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_RESET) < 0) { -+ fprintf(stderr, "Failed to set BITMODE_RESET on iCE FTDI USB device.\n"); -+ mpsse_error(2); -+ } -+ - if (ftdi_usb_reset(&mpsse_ftdic)) { - fprintf(stderr, "Failed to reset iCE FTDI USB device.\n"); - mpsse_error(2); -@@ -358,6 +364,9 @@ void mpsse_close(void) - { - ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency); - ftdi_disable_bitbang(&mpsse_ftdic); -+ -+ ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_BITBANG); -+ - ftdi_usb_close(&mpsse_ftdic); - ftdi_deinit(&mpsse_ftdic); - } -\ No newline at end of file From 8fb317c9a205d9634b50b3ba5e70364b7737e944 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Fri, 24 Nov 2023 17:31:02 +0100 Subject: [PATCH 22/30] boh3 --- ...lash-prgraner-iceprog-custom-for-heep-with-gpio.patch | 6 +++--- sw/vendor/yosyshq_icestorm/iceprog/iceprog.c | 4 ++-- sw/vendor/yosyshq_icestorm/iceprog/mpsse.c | 9 --------- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch index 692ff570b..06c990c2a 100644 --- a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch +++ b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch @@ -1,5 +1,5 @@ diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c -index 8ee6443..8c4c717 100644 +index 8ee6443..25c7b0e 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c @@ -480,6 +480,34 @@ static void flash_enable_quad() @@ -106,7 +106,7 @@ index 8ee6443..8c4c717 100644 + size_t len = 0; + uint8_t buffer[256]; + int count = 0; -+ while (true) { ++ while (true) { + rc = getline(&line_buffer, &len, f); + if (rc <= 0){ + if(count > 0){ @@ -178,7 +178,7 @@ index 8ee6443..8c4c717 100644 + int rc, addr = 0; + size_t len = 0; + uint8_t buffer_flash[256], buffer_file[256]; -+ while (true) { ++ while (true) { + rc = getline(&line_buffer, &len, f); if (rc <= 0) break; diff --git a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c index 8c4c7177d..25c7b0e56 100644 --- a/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c +++ b/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c @@ -1048,7 +1048,7 @@ int main(int argc, char **argv) size_t len = 0; uint8_t buffer[256]; int count = 0; - while (true) { + while (true) { rc = getline(&line_buffer, &len, f); if (rc <= 0){ if(count > 0){ @@ -1123,7 +1123,7 @@ int main(int argc, char **argv) int rc, addr = 0; size_t len = 0; uint8_t buffer_flash[256], buffer_file[256]; - while (true) { + while (true) { rc = getline(&line_buffer, &len, f); if (rc <= 0) break; diff --git a/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c b/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c index 71c9ee6e1..80d462f18 100644 --- a/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c +++ b/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c @@ -309,12 +309,6 @@ void mpsse_init(int ifnum, const char *devstr, bool slow_clock) mpsse_ftdic_open = true; - /* Reset the BITMODE. Set all pins to output. */ - if (ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_RESET) < 0) { - fprintf(stderr, "Failed to set BITMODE_RESET on iCE FTDI USB device.\n"); - mpsse_error(2); - } - if (ftdi_usb_reset(&mpsse_ftdic)) { fprintf(stderr, "Failed to reset iCE FTDI USB device.\n"); mpsse_error(2); @@ -364,9 +358,6 @@ void mpsse_close(void) { ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency); ftdi_disable_bitbang(&mpsse_ftdic); - - ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_BITBANG); - ftdi_usb_close(&mpsse_ftdic); ftdi_deinit(&mpsse_ftdic); } \ No newline at end of file From 80843bab975c2f1e3025fd8aabb2dc2989a5afbe Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Wed, 29 Nov 2023 13:28:45 +0100 Subject: [PATCH 23/30] fix merge --- ...er-iceprog-custom-for-heep-with-gpio.patch | 28 +++++++++++++++++++ sw/vendor/yosyshq_icestorm/iceprog/mpsse.c | 9 ++++++ 2 files changed, 37 insertions(+) diff --git a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch index 06c990c2a..19c71e6e9 100644 --- a/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch +++ b/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch @@ -215,3 +215,31 @@ index 8ee6443..25c7b0e 100644 } +diff --git a/iceprog/mpsse.c b/iceprog/mpsse.c +index 80d462f..71c9ee6 100644 +--- a/iceprog/mpsse.c ++++ b/iceprog/mpsse.c +@@ -309,6 +309,12 @@ void mpsse_init(int ifnum, const char *devstr, bool slow_clock) + + mpsse_ftdic_open = true; + ++ /* Reset the BITMODE. Set all pins to output. */ ++ if (ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_RESET) < 0) { ++ fprintf(stderr, "Failed to set BITMODE_RESET on iCE FTDI USB device.\n"); ++ mpsse_error(2); ++ } ++ + if (ftdi_usb_reset(&mpsse_ftdic)) { + fprintf(stderr, "Failed to reset iCE FTDI USB device.\n"); + mpsse_error(2); +@@ -358,6 +364,9 @@ void mpsse_close(void) + { + ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency); + ftdi_disable_bitbang(&mpsse_ftdic); ++ ++ ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_BITBANG); ++ + ftdi_usb_close(&mpsse_ftdic); + ftdi_deinit(&mpsse_ftdic); + } +\ No newline at end of file diff --git a/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c b/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c index 80d462f18..71c9ee6e1 100644 --- a/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c +++ b/sw/vendor/yosyshq_icestorm/iceprog/mpsse.c @@ -309,6 +309,12 @@ void mpsse_init(int ifnum, const char *devstr, bool slow_clock) mpsse_ftdic_open = true; + /* Reset the BITMODE. Set all pins to output. */ + if (ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_RESET) < 0) { + fprintf(stderr, "Failed to set BITMODE_RESET on iCE FTDI USB device.\n"); + mpsse_error(2); + } + if (ftdi_usb_reset(&mpsse_ftdic)) { fprintf(stderr, "Failed to reset iCE FTDI USB device.\n"); mpsse_error(2); @@ -358,6 +364,9 @@ void mpsse_close(void) { ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency); ftdi_disable_bitbang(&mpsse_ftdic); + + ftdi_set_bitmode(&mpsse_ftdic, 0x00, BITMODE_BITBANG); + ftdi_usb_close(&mpsse_ftdic); ftdi_deinit(&mpsse_ftdic); } \ No newline at end of file From 57d9dcc25b7eeca85ec466574a305e9ee1a8bf73 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Wed, 29 Nov 2023 16:02:28 +0100 Subject: [PATCH 24/30] Modify to support run in simulation --- sw/applications/example_spi_flash_write/main.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sw/applications/example_spi_flash_write/main.c b/sw/applications/example_spi_flash_write/main.c index a3d273e71..fa1d09580 100644 --- a/sw/applications/example_spi_flash_write/main.c +++ b/sw/applications/example_spi_flash_write/main.c @@ -60,7 +60,7 @@ /* By default, printfs are activated for FPGA and disabled for simulation. */ #define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 +#define PRINTF_IN_SIM 1 #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) @@ -267,13 +267,6 @@ static inline __attribute__((always_inline)) void spi_wait_4_resp() int main(int argc, char *argv[]) { - -#ifdef TARGET_SIM - #pragma message("This app does not allow Flash write operations in simulation!") - PRINTF("Flash writes are not permitted during Simulation, only on FPGA\n"); - return EXIT_SUCCESS; -#endif - soc_ctrl_t soc_ctrl; soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); @@ -367,12 +360,15 @@ int main(int argc, char *argv[]) } PRINTF("triggered\n\r"); + // In simulation there is no need to wait + #ifdef USE_SPI_FLASH spi_wait_4_resp(); + #endif //USE_SPI_FLASH PRINTF("%d Bytes written in Flash at @ 0x%08x \n\r", COPY_DATA_UNITS*DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE), FLASH_ADDR); -#endif //TEST_SPI_2_MEM +#endif // TEST_MEM_2_SPI #ifdef TEST_SPI_2_MEM From 303a22c018fe65917b20b560778a5973e7f1f42e Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Thu, 30 Nov 2023 13:08:23 +0100 Subject: [PATCH 25/30] Update supported command list --- hw/vendor/yosyshq_picorv32/picosoc/spiflash.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v index 4a0338a4b..0358b6a55 100644 --- a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v +++ b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v @@ -26,7 +26,7 @@ // updates output signals 1ns after the SPI clock edge. // // Supported commands: -// AB, B9, FF, 03, BB, EB, ED, 06, 02 +// AB, B9, FF, 03, BB, EB, ED, 06, 02, 32 // // Well written SPI flash data sheets: // Cypress S25FL064L http://www.cypress.com/file/316661/download From 79028c6383ea44ef264a7535fe25d4f48a2d31fc Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Thu, 30 Nov 2023 14:47:51 +0100 Subject: [PATCH 26/30] Add quad write example --- .../main.c | 129 +++++++++++++++++- 1 file changed, 126 insertions(+), 3 deletions(-) rename sw/applications/{example_spi_host_write => example_spi_flash_write_quad}/main.c (68%) diff --git a/sw/applications/example_spi_host_write/main.c b/sw/applications/example_spi_flash_write_quad/main.c similarity index 68% rename from sw/applications/example_spi_host_write/main.c rename to sw/applications/example_spi_flash_write_quad/main.c index e0c0bd8eb..7de547cbd 100644 --- a/sw/applications/example_spi_host_write/main.c +++ b/sw/applications/example_spi_flash_write_quad/main.c @@ -51,6 +51,9 @@ uint32_t flash_data_towrite[16] = { }; uint32_t flash_data_toread[16] = {}; +// Function to set the QE bit in the W25Q128JW flash memory +void set_QE_bit(void); + #ifndef USE_SPI_FLASH void fic_irq_spi(void) { @@ -216,14 +219,20 @@ int main(int argc, char *argv[]) { } #endif - /** + /* * Configure the SPI<->flash connection parameters and the SPI host. * Set the write enale bit. */ spi_config(); + /* + * Set the QE bit in the W25Q128JW flash memory. + * The function execute the command only if the target is the PYNQ-Z2 FPGA. + */ + set_QE_bit(); + // Write command - Program Page + address - const uint32_t write_byte_cmd = ((REVERT_24b_ADDR(FLASH_ADDR) << 8) | 0x02); + const uint32_t write_byte_cmd = ((REVERT_24b_ADDR(FLASH_ADDR) << 8) | 0x32); // QUAD SPEED COMMAND spi_write_word(&spi_host, write_byte_cmd); const uint32_t cmd_write = spi_create_command((spi_command_t){ .len = 3, @@ -241,7 +250,7 @@ int main(int argc, char *argv[]) { const uint32_t cmd_write1 = spi_create_command((spi_command_t){ .len = 16*4 - 1, .csaat = false, - .speed = kSpiSpeedStandard, + .speed = kSpiSpeedQuad, // QUAD SPEED .direction = kSpiDirTxOnly }); spi_set_command(&spi_host, cmd_write1); @@ -307,4 +316,118 @@ int main(int argc, char *argv[]) { } return EXIT_SUCCESS; +} + +void set_QE_bit() { + // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed + // The Verilog flash do not model this behavior and no actions are required + #ifdef TARGET_PYNQ_Z2 + + PRINTF("FPGA target: setting QE bit...\n\r"); + spi_set_rx_watermark(&spi_host,1); + + // ----------------COMMAND---------------- + // Read Status Register 2 + // ----------------COMMAND---------------- + + // Create segment 1 + const uint32_t reg2_read_cmd = W25Q128JW_CMD_READ_REG2; + spi_write_word(&spi_host, reg2_read_cmd); + spi_wait_for_ready(&spi_host); + + const uint32_t reg2_read_1 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, reg2_read_1); + spi_wait_for_ready(&spi_host); + + + // Create segment 2 + const uint32_t reg2_read_2 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Standard speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi_host, reg2_read_2); + spi_wait_for_ready(&spi_host); + spi_wait_for_rx_watermark(&spi_host); + + // the partial word will be zero-padded and inserted into the RX FIFO once the segment is completed + uint32_t reg2_data; // The actual register is 8 bit, but the SPI host gives a full word + spi_read_word(&spi_host, ®2_data); + // ----------------END COMMAND---------------- + + + // Set bit in position 1 (QE bit) + PRINTF("before reg2_data = 0x%x\n\r", reg2_data); + reg2_data |= 0x2; + PRINTF("after reg2_data = 0x%x\n\r", reg2_data); + + + // ----------------COMMAND---------------- + // Write Enable - WEL (Write Enable Latch) set + // ----------------COMMAND---------------- + // Create segment 1 + const uint32_t write_enable_cmd = W25Q128JW_CMD_WRITE_ENABLE; + spi_write_word(&spi_host, write_enable_cmd); + const uint32_t cmd_write_en = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_write_en); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + + + // ----------------COMMAND---------------- + // Write Status Register 2 + // ----------------COMMAND---------------- + // Create segment 1 + const uint32_t reg2_write_cmd = W25Q128JW_CMD_WRITE_REG2; + spi_write_word(&spi_host, reg2_write_cmd); + spi_wait_for_ready(&spi_host); + + const uint32_t reg2_write_1 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, reg2_write_1); + spi_wait_for_ready(&spi_host); + + + // Create segment 2 + spi_write_word(&spi_host, reg2_data); + spi_wait_for_ready(&spi_host); + + const uint32_t reg2_write_2 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Standard speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi_host, reg2_write_2); + spi_wait_for_ready(&spi_host); + // ----------------END COMMAND---------------- + + // Check back the register + spi_write_word(&spi_host, reg2_read_cmd); + spi_wait_for_ready(&spi_host); + spi_set_command(&spi_host, reg2_read_1); + spi_wait_for_ready(&spi_host); + spi_set_command(&spi_host, reg2_read_2); + spi_wait_for_ready(&spi_host); + spi_wait_for_rx_watermark(&spi_host); + uint32_t reg2_data_check = 0x00; + spi_read_word(&spi_host, ®2_data_check); + PRINTF("reg2_data_check = 0x%x\n\r", reg2_data_check); + + #endif } \ No newline at end of file From 4645e1b71e6f2e47f38ef18c0a5fa34e7fec860f Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Thu, 30 Nov 2023 16:07:16 +0100 Subject: [PATCH 27/30] Bug fix --- .../example_spi_flash_write_quad/main.c | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/sw/applications/example_spi_flash_write_quad/main.c b/sw/applications/example_spi_flash_write_quad/main.c index 7de547cbd..6673f1955 100644 --- a/sw/applications/example_spi_flash_write_quad/main.c +++ b/sw/applications/example_spi_flash_write_quad/main.c @@ -24,6 +24,18 @@ #define USE_SPI_FLASH #endif +// W25Q128JW flash commands supported by Questasim flash model +// Also FFh and EDh are supported by the simulation model, but not by the phisical flash +#define W25Q128JW_CMD_RELEASE_POWERDOWN 0xab +#define W25Q128JW_CMD_POWERDOWN 0xb9 +#define W25Q128JW_CMD_READ 0x03 +#define W25Q128JW_CMD_READ_DUALIO 0xbb +#define W25Q128JW_CMD_READ_QUADIO 0xeb +// Not supported in Verilog flash model +#define W25Q128JW_CMD_READ_REG2 0x35 +#define W25Q128JW_CMD_WRITE_REG2 0x31 +#define W25Q128JW_CMD_WRITE_ENABLE 0x06 + #define REVERT_24b_ADDR(addr) ((((uint32_t)addr & 0xff0000) >> 16) | ((uint32_t)addr & 0xff00) | (((uint32_t)addr & 0xff) << 16)) #define FLASH_ADDR 0x00008500 // 256B data alignment #define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) @@ -163,17 +175,6 @@ static inline __attribute__((always_inline)) void spi_config() { spi_set_command(&spi_host, cmd_powerup); spi_wait_for_ready(&spi_host); - // Write enable - const uint32_t write_enable_cmd = 0x06; - spi_write_word(&spi_host, write_enable_cmd); - const uint32_t cmd_write_en = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_write_en); - spi_wait_for_ready(&spi_host); } static inline __attribute__((always_inline)) void spi_wait_4_resp() @@ -231,6 +232,18 @@ int main(int argc, char *argv[]) { */ set_QE_bit(); + // Write enable + const uint32_t write_enable_cmd = 0x06; + spi_write_word(&spi_host, write_enable_cmd); + const uint32_t cmd_write_en = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi_host, cmd_write_en); + spi_wait_for_ready(&spi_host); + // Write command - Program Page + address const uint32_t write_byte_cmd = ((REVERT_24b_ADDR(FLASH_ADDR) << 8) | 0x32); // QUAD SPEED COMMAND spi_write_word(&spi_host, write_byte_cmd); @@ -259,7 +272,7 @@ int main(int argc, char *argv[]) { // Wait for all the fifo to be drained spi_wait_for_tx_empty(&spi_host); #ifndef TARGET_SIM - spi_wait_4_resp() + spi_wait_4_resp(); #endif // TARGET_SIM // Read back the data From e61012b0f27f5aba7afc4313609442f9b51fa427 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Mon, 4 Dec 2023 11:06:25 +0100 Subject: [PATCH 28/30] Code clean-up --- .../example_spi_flash_write/main.c | 14 ++--------- .../example_spi_flash_write_quad/main.c | 23 ++++++------------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/sw/applications/example_spi_flash_write/main.c b/sw/applications/example_spi_flash_write/main.c index fa1d09580..da44a51cf 100644 --- a/sw/applications/example_spi_flash_write/main.c +++ b/sw/applications/example_spi_flash_write/main.c @@ -60,7 +60,7 @@ /* By default, printfs are activated for FPGA and disabled for simulation. */ #define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 1 +#define PRINTF_IN_SIM 0 #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) @@ -183,17 +183,7 @@ static inline __attribute__((always_inline)) void spi_config() spi_set_configopts(&spi_host, 0, chip_cfg); spi_set_csid(&spi_host, 0); - // Reset - const uint32_t reset_cmd = 0xFFFFFFFF; - spi_write_word(&spi_host, reset_cmd); - const uint32_t cmd_reset = spi_create_command((spi_command_t){ - .len = 3, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_reset); - spi_wait_for_ready(&spi_host); + // Set read watermark to 1 word spi_set_rx_watermark(&spi_host,1); // Power up flash diff --git a/sw/applications/example_spi_flash_write_quad/main.c b/sw/applications/example_spi_flash_write_quad/main.c index 6673f1955..020d013a6 100644 --- a/sw/applications/example_spi_flash_write_quad/main.c +++ b/sw/applications/example_spi_flash_write_quad/main.c @@ -150,18 +150,7 @@ static inline __attribute__((always_inline)) void spi_config() { spi_set_configopts(&spi_host, 0, chip_cfg); spi_set_csid(&spi_host, 0); - // Reset - const uint32_t reset_cmd = 0xFFFFFFFF; // ??? - spi_write_word(&spi_host, reset_cmd); - const uint32_t cmd_reset = spi_create_command((spi_command_t){ - .len = 3, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_reset); - spi_wait_for_ready(&spi_host); - spi_set_rx_watermark(&spi_host,1); + // Reset is not needed. The flash is in reset state at startup. // Power up flash const uint32_t powerup_byte_cmd = 0xab; @@ -271,9 +260,11 @@ int main(int argc, char *argv[]) { // Wait for all the fifo to be drained spi_wait_for_tx_empty(&spi_host); - #ifndef TARGET_SIM + + // Wait for the flash to be ready (FPGA only) + #ifdef TARGET_PYNQ_Z2 spi_wait_4_resp(); - #endif // TARGET_SIM + #endif // Read back the data // Fill TX FIFO with TX data (read command + 3B address) @@ -332,8 +323,8 @@ int main(int argc, char *argv[]) { } void set_QE_bit() { - // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed - // The Verilog flash do not model this behavior and no actions are required + // W25Q128JW requires the QE (Quad Enable) bit to be set in order to operate at quad speed. + // The Verilog flash do not model this behavior and no actions are required. #ifdef TARGET_PYNQ_Z2 PRINTF("FPGA target: setting QE bit...\n\r"); From 2a1e370a73ae884a552f22c7a71e6919c07a2895 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Tue, 5 Dec 2023 15:42:42 +0100 Subject: [PATCH 29/30] code cleanup --- sw/applications/example_spi_flash_write_quad/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sw/applications/example_spi_flash_write_quad/main.c b/sw/applications/example_spi_flash_write_quad/main.c index 020d013a6..d3531169c 100644 --- a/sw/applications/example_spi_flash_write_quad/main.c +++ b/sw/applications/example_spi_flash_write_quad/main.c @@ -42,7 +42,7 @@ /* By default, printfs are activated for FPGA and disabled for simulation. */ #define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 1 +#define PRINTF_IN_SIM 0 #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) From 627e809a3cffd0e24013c033b81acba72d01ed59 Mon Sep 17 00:00:00 2001 From: Mattia Consani Date: Tue, 5 Dec 2023 15:45:30 +0100 Subject: [PATCH 30/30] vendor patch --- .../0002-spiflash_valueargs.patch | 97 ++++++++++++++++++- hw/vendor/yosyshq_picorv32/picosoc/spiflash.v | 2 +- 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch b/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch index 5b525705f..9baadd8cc 100644 --- a/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch +++ b/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch @@ -1,8 +1,26 @@ diff --git a/picosoc/spiflash.v b/picosoc/spiflash.v -index 22b337b..e0eef9f 100644 +index 22b337b..88582b3 100644 --- a/picosoc/spiflash.v +++ b/picosoc/spiflash.v -@@ -102,8 +102,14 @@ module spiflash ( +@@ -26,7 +26,7 @@ + // updates output signals 1ns after the SPI clock edge. + // + // Supported commands: +-// AB, B9, FF, 03, BB, EB, ED ++// AB, B9, FF, 03, BB, EB, ED, 06, 02, 32 + // + // Well written SPI flash data sheets: + // Cypress S25FL064L http://www.cypress.com/file/316661/download +@@ -61,6 +61,8 @@ module spiflash ( + reg spi_io_vld; + + reg powered_up = 0; ++ reg write_enable = 0; ++ reg write_enable_reset = 0; + + localparam [3:0] mode_spi = 1; + localparam [3:0] mode_dspi_rd = 2; +@@ -102,8 +104,14 @@ module spiflash ( reg [7:0] memory [0:16*1024*1024-1]; reg [1023:0] firmware_file; @@ -18,3 +36,78 @@ index 22b337b..e0eef9f 100644 firmware_file = "firmware.hex"; $readmemh(firmware_file, memory); end +@@ -123,6 +131,9 @@ module spiflash ( + + if (spi_cmd == 8'h ff) + xip_cmd = 0; ++ ++ if (spi_cmd == 8'h 06) ++ write_enable = 1; + end + + if (powered_up && spi_cmd == 'h 03) begin +@@ -141,6 +152,25 @@ module spiflash ( + end + end + ++ if (powered_up && write_enable && spi_cmd == 'h 02) begin ++ if (bytecount == 1) ++ write_enable_reset = 1; ++ ++ if (bytecount == 2) ++ spi_addr[23:16] = buffer; ++ ++ if (bytecount == 3) ++ spi_addr[15:8] = buffer; ++ ++ if (bytecount == 4) ++ spi_addr[7:0] = buffer; ++ ++ if (bytecount >= 5 && bytecount <= 260) begin ++ memory[spi_addr] = buffer; ++ spi_addr = spi_addr + 1; ++ end ++ end ++ + if (powered_up && spi_cmd == 'h bb) begin + if (bytecount == 1) + mode = mode_dspi_rd; +@@ -191,6 +221,27 @@ module spiflash ( + end + end + ++ if (powered_up && write_enable && spi_cmd == 'h 32) begin ++ if (bytecount == 1) ++ write_enable_reset = 1; ++ ++ if (bytecount == 2) ++ spi_addr[23:16] = buffer; ++ ++ if (bytecount == 3) ++ spi_addr[15:8] = buffer; ++ ++ if (bytecount == 4) begin ++ spi_addr[7:0] = buffer; ++ mode = mode_qspi_rd; ++ end ++ ++ if (bytecount >= 5 && bytecount <= 260) begin ++ memory[spi_addr] = buffer; ++ spi_addr = spi_addr + 1; ++ end ++ end ++ + if (powered_up && spi_cmd == 'h ed) begin + if (bytecount == 1) + next_mode = mode_qspi_ddr_rd; +@@ -268,6 +319,10 @@ module spiflash ( + $display(""); + $fflush; + end ++ if (write_enable_reset) begin ++ write_enable = 0; ++ write_enable_reset = 0; ++ end + buffer = 0; + bitcount = 0; + bytecount = 0; diff --git a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v index 0358b6a55..88582b30d 100644 --- a/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v +++ b/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v @@ -131,7 +131,7 @@ module spiflash ( if (spi_cmd == 8'h ff) xip_cmd = 0; - + if (spi_cmd == 8'h 06) write_enable = 1; end