Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
5c42d5cafThis file is pinned to the selected release. Download the original to open it in your design tool.
#
# This file is part of LiteX.
#
# Copyright (c) 2026 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import os
import subprocess
import textwrap
def _write(path, contents=""):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(textwrap.dedent(contents))
def test_is25lp128_quad_enable_preserves_status(tmp_path):
repo = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
include_dir = tmp_path / "include"
source = tmp_path / "spiflash_harness.c"
binary = tmp_path / "spiflash_harness"
_write(include_dir / "generated" / "csr.h", """
#ifndef __GENERATED_CSR_H
#define __GENERATED_CSR_H
#define CSR_SPIFLASH_BASE 1
#define CSR_SPIFLASH_MASTER_CS_ADDR 1
#define CSR_SPIFLASH_MASTER_PHYCONFIG_LEN_SIZE 8
#define CSR_SPIFLASH_MASTER_PHYCONFIG_LEN_OFFSET 0
#define CSR_SPIFLASH_MASTER_PHYCONFIG_WIDTH_SIZE 4
#define CSR_SPIFLASH_MASTER_PHYCONFIG_WIDTH_OFFSET 8
#define CSR_SPIFLASH_MASTER_PHYCONFIG_MASK_SIZE 8
#define CSR_SPIFLASH_MASTER_PHYCONFIG_MASK_OFFSET 16
#define CSR_SPIFLASH_MASTER_STATUS_TX_READY_OFFSET 0
#define CSR_SPIFLASH_MASTER_STATUS_RX_READY_OFFSET 1
uint32_t test_spiflash_master_status_read(void);
uint32_t test_spiflash_master_rxtx_read(void);
void test_spiflash_master_rxtx_write(uint32_t value);
void test_spiflash_master_phyconfig_write(uint32_t value);
void test_spiflash_master_cs_write(uint32_t value);
#define spiflash_master_status_read test_spiflash_master_status_read
#define spiflash_master_rxtx_read test_spiflash_master_rxtx_read
#define spiflash_master_rxtx_write test_spiflash_master_rxtx_write
#define spiflash_master_phyconfig_write test_spiflash_master_phyconfig_write
#define spiflash_master_cs_write test_spiflash_master_cs_write
#endif
""")
_write(include_dir / "generated" / "mem.h")
_write(include_dir / "libbase" / "crc.h")
_write(include_dir / "libbase" / "memtest.h")
_write(include_dir / "system.h", """
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include <stdbool.h>
#define CONFIG_CLOCK_FREQUENCY 1000000
#define SPIFLASH_PHY_FREQUENCY 1000000
#define SPIFLASH_MODULE_NAME "is25lp128"
#define SPIFLASH_MODULE_QUAD_CAPABLE
#define SPIFLASH_MODULE_QUAD_ENABLE_WRSR_SR1_BIT6
static inline void cdelay(int cycles) { (void)cycles; }
#endif
""")
_write(source, f"""
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
static uint8_t flash_status;
static uint8_t transaction_command;
static unsigned int transaction_index;
static uint32_t phyconfig;
static uint32_t rx_value;
static uint32_t wrsr_value;
static unsigned int wrsr_bits;
static unsigned int write_enable_count;
static bool rx_ready;
static bool ignore_wrsr;
uint32_t test_spiflash_master_status_read(void)
{{
return 1 | (rx_ready << 1);
}}
uint32_t test_spiflash_master_rxtx_read(void)
{{
rx_ready = false;
return rx_value;
}}
void test_spiflash_master_phyconfig_write(uint32_t value)
{{
phyconfig = value;
}}
void test_spiflash_master_cs_write(uint32_t value)
{{
if (value) {{
transaction_command = 0;
transaction_index = 0;
}} else if (transaction_command == 0x06) {{
flash_status |= 0x02;
write_enable_count++;
}}
}}
void test_spiflash_master_rxtx_write(uint32_t value)
{{
unsigned int bits = phyconfig & 0xff;
rx_value = 0;
if (bits > 8) {{
transaction_command = (value >> (bits - 8)) & 0xff;
if (transaction_command == 0x01) {{
wrsr_value = value;
wrsr_bits = bits;
if ((flash_status & 0x02) && !ignore_wrsr)
flash_status = value & 0xfc;
else
flash_status &= ~0x02;
}}
}} else {{
uint8_t byte = value;
if (transaction_index++ == 0)
transaction_command = byte;
else if (transaction_command == 0x05)
rx_value = flash_status;
}}
rx_ready = true;
}}
#include "{repo}/litex/soc/software/liblitespi/spiflash.c"
#define REQUIRE(cond) do {{ \\
if (!(cond)) {{ \\
fprintf(stderr, "requirement failed at %s:%d: %s\\n", __FILE__, __LINE__, #cond); \\
return 1; \\
}} \\
}} while (0)
int main(void)
{{
flash_status = 0x9c;
REQUIRE(spiflash_enable_quad_mode());
REQUIRE(write_enable_count == 1);
REQUIRE(wrsr_bits == 16);
REQUIRE(wrsr_value == 0x01dc);
REQUIRE(flash_status == 0xdc);
REQUIRE(spiflash_enable_quad_mode());
REQUIRE(write_enable_count == 1);
flash_status = 0x04;
wrsr_value = 0;
wrsr_bits = 0;
write_enable_count = 0;
ignore_wrsr = true;
REQUIRE(!spiflash_enable_quad_mode());
REQUIRE(write_enable_count == 1);
REQUIRE(wrsr_bits == 16);
REQUIRE(wrsr_value == 0x0144);
REQUIRE(flash_status == 0x04);
return 0;
}}
""")
subprocess.check_call([
"gcc",
"-std=c11",
"-Wall",
"-Wextra",
"-Werror",
"-Wno-format",
"-I", str(include_dir),
str(source),
"-o", str(binary),
])
subprocess.check_call([str(binary)])
def test_erase_uses_module_geometry(tmp_path):
repo = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
include_dir = tmp_path / "include"
source = tmp_path / "spiflash_erase_harness.c"
binary = tmp_path / "spiflash_erase_harness"
_write(include_dir / "generated" / "csr.h", """
#ifndef __GENERATED_CSR_H
#define __GENERATED_CSR_H
#define CSR_SPIFLASH_BASE 1
#define CSR_SPIFLASH_MASTER_CS_ADDR 1
#define CSR_SPIFLASH_MASTER_PHYCONFIG_LEN_SIZE 8
#define CSR_SPIFLASH_MASTER_PHYCONFIG_LEN_OFFSET 0
#define CSR_SPIFLASH_MASTER_PHYCONFIG_WIDTH_SIZE 4
#define CSR_SPIFLASH_MASTER_PHYCONFIG_WIDTH_OFFSET 8
#define CSR_SPIFLASH_MASTER_PHYCONFIG_MASK_SIZE 8
#define CSR_SPIFLASH_MASTER_PHYCONFIG_MASK_OFFSET 16
#define CSR_SPIFLASH_MASTER_STATUS_TX_READY_OFFSET 0
#define CSR_SPIFLASH_MASTER_STATUS_RX_READY_OFFSET 1
uint32_t test_spiflash_master_status_read(void);
uint32_t test_spiflash_master_rxtx_read(void);
void test_spiflash_master_rxtx_write(uint32_t value);
void test_spiflash_master_phyconfig_write(uint32_t value);
void test_spiflash_master_cs_write(uint32_t value);
#define spiflash_master_status_read test_spiflash_master_status_read
#define spiflash_master_rxtx_read test_spiflash_master_rxtx_read
#define spiflash_master_rxtx_write test_spiflash_master_rxtx_write
#define spiflash_master_phyconfig_write test_spiflash_master_phyconfig_write
#define spiflash_master_cs_write test_spiflash_master_cs_write
#endif
""")
_write(include_dir / "generated" / "mem.h")
_write(include_dir / "libbase" / "crc.h")
_write(include_dir / "libbase" / "memtest.h")
_write(include_dir / "system.h", """
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include <stdbool.h>
#define CONFIG_CLOCK_FREQUENCY 1000000
#define SPIFLASH_PHY_FREQUENCY 1000000
#define SPIFLASH_MODULE_NAME "model"
#define SPIFLASH_MODULE_ERASE_OPCODE 0x21
#define SPIFLASH_MODULE_ERASE_SIZE 4096
#define SPIFLASH_MODULE_ERASE_ADDR_BITS 32
static inline void cdelay(int cycles) { (void)cycles; }
#endif
""")
_write(source, f"""
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define MAX_TRANSACTIONS 16
#define MAX_TRANSACTION_BYTES 8
static uint8_t transactions[MAX_TRANSACTIONS][MAX_TRANSACTION_BYTES];
static unsigned int transaction_lengths[MAX_TRANSACTIONS];
static unsigned int transaction_count;
static bool transaction_active;
static bool rx_ready;
static uint32_t rx_value;
uint32_t test_spiflash_master_status_read(void)
{{
return 1 | (rx_ready << 1);
}}
uint32_t test_spiflash_master_rxtx_read(void)
{{
rx_ready = false;
return rx_value;
}}
void test_spiflash_master_phyconfig_write(uint32_t value)
{{
(void)value;
}}
void test_spiflash_master_cs_write(uint32_t value)
{{
if (value) {{
transaction_active = true;
transaction_lengths[transaction_count] = 0;
}} else if (transaction_active) {{
transaction_active = false;
transaction_count++;
}}
}}
void test_spiflash_master_rxtx_write(uint32_t value)
{{
unsigned int length = transaction_lengths[transaction_count];
if (transaction_count < MAX_TRANSACTIONS && length < MAX_TRANSACTION_BYTES)
transactions[transaction_count][length] = value;
transaction_lengths[transaction_count] = length + 1;
rx_value = 0;
rx_ready = true;
}}
#include "{repo}/litex/soc/software/liblitespi/spiflash.c"
#define REQUIRE(cond) do {{ \
if (!(cond)) {{ \
fprintf(stderr, "requirement failed at %s:%d: %s\\n", __FILE__, __LINE__, #cond); \
return 1; \
}} \
}} while (0)
static void clear_transactions(void)
{{
memset(transactions, 0, sizeof(transactions));
memset(transaction_lengths, 0, sizeof(transaction_lengths));
transaction_count = 0;
transaction_active = false;
rx_ready = false;
rx_value = 0;
}}
static int check_erase(unsigned int index, uint32_t address)
{{
REQUIRE(transaction_lengths[index] == 5);
REQUIRE(transactions[index][0] == 0x21);
REQUIRE(transactions[index][1] == ((address >> 24) & 0xff));
REQUIRE(transactions[index][2] == ((address >> 16) & 0xff));
REQUIRE(transactions[index][3] == ((address >> 8) & 0xff));
REQUIRE(transactions[index][4] == ((address >> 0) & 0xff));
return 0;
}}
int main(void)
{{
spiflash_erase_range(0x1234, 1);
REQUIRE(transaction_count == 3);
REQUIRE(transaction_lengths[0] == 1);
REQUIRE(transactions[0][0] == 0x06);
REQUIRE(check_erase(1, 0x1000) == 0);
REQUIRE(transactions[2][0] == 0x05);
clear_transactions();
spiflash_erase_range(0x1fff, 2);
REQUIRE(transaction_count == 6);
REQUIRE(check_erase(1, 0x1000) == 0);
REQUIRE(check_erase(4, 0x2000) == 0);
clear_transactions();
spiflash_erase_range(0xffffffff, 2);
REQUIRE(transaction_count == 0);
clear_transactions();
spiflash_erase_4k_sector(0x3456);
REQUIRE(transaction_count == 3);
REQUIRE(transactions[0][0] == 0x06);
REQUIRE(transaction_lengths[1] == 4);
REQUIRE(transactions[1][0] == 0x20);
REQUIRE(transactions[1][1] == 0x00);
REQUIRE(transactions[1][2] == 0x34);
REQUIRE(transactions[1][3] == 0x56);
REQUIRE(transactions[2][0] == 0x05);
return 0;
}}
""")
subprocess.check_call([
"gcc",
"-std=c11",
"-Wall",
"-Wextra",
"-Werror",
"-Wno-format",
"-Wno-unused-function",
"-I", str(include_dir),
str(source),
"-o", str(binary),
])
subprocess.check_call([str(binary)])